diff --git a/.travis.yml b/.travis.yml index ee408409..f0e0593c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ go: - tip go_import_path: github.com/kataras/iris install: - - go get ./... # for iris-contrib/httpexpect and sirupsen/logrus + - go get ./... # for iris-contrib/httpexpect and kataras/golog script: - go test -v -cover ./... after_script: diff --git a/HISTORY.md b/HISTORY.md index f9cca571..9781e9d4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,10 +13,46 @@ ### Should I upgrade my Iris? Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready. + > Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes. **How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`. + +# We, 26 July 2017 | v8.1.0 + +The `app.Logger() *logrus.Logger` was replaced with a custom implementation [[golog](https://github.com/kataras/golog)], it's compatible with the [logrus](https://github.com/sirupsen/logrus) package and other open-source golang loggers as well, because of that: https://github.com/kataras/iris/issues/680#issuecomment-316184570. + +The API didn't change much except these: + +- the new implementation does not recognise `Fatal` and `Panic` because, actually, iris never panics +- the old `app.Logger().Out = io.Writer` should be written as `app.Logger().SetOutput(io.Writer)` + +The new implementation, [golog](https://github.com/kataras/golog) is more featured +and it completes more use cases than the before external implementation. + +At general you have to know that the low-level relative fields and functions are actually inside `app.Logger().Printer` object, i.e: `app.Logger().Printer.Output` to get the `io.Writer` or `app.Logger().Printer.AddOuput/SetOutput` to set or add more output(`io.Writer`) targets. + +### Integration + +I understand that many of you may use logrus outside of Iris too. To integrate an external `logrus` logger just +`Install` it-- all print operations will be handled by the provided `logrus instance`. + +```go +import ( + "github.com/kataras/iris" + "github.com/sirupsen/logrus" +) + +package main(){ + app := iris.New() + app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance + // [...] +} +``` + +For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well! + # Sa, 23 July 2017 | v8.0.7 Fix [It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed](https://github.com/kataras/iris/issues/683#issuecomment-317229068) diff --git a/README.md b/README.md index 92f2b47e..bc9d5510 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Iris is a fast, simple and efficient micro web framework for Go. It provides a b ### 📑 Table of contents * [Installation](#-installation) -* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-23-july-2017--v807) +* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#we-26-july-2017--v810) * [Learn](#-learn) * [HTTP Listening](_examples/#http-listening) * [Configuration](_examples/#configuration) @@ -339,7 +339,7 @@ Thank You for your trust! ### 📌 Version -Current: **8.0.7** +Current: **8.1.0** Each new release is pushed to the master. It stays there until the next version. When a next version is released then the previous version goes to its own branch with `gopkg.in` as its import path (and its own vendor folder), in order to keep it working "for-ever". diff --git a/_examples/http-listening/listen-addr/omit-server-errors/main_test.go b/_examples/http-listening/listen-addr/omit-server-errors/main_test.go index 0a6b541f..a1915419 100644 --- a/_examples/http-listening/listen-addr/omit-server-errors/main_test.go +++ b/_examples/http-listening/listen-addr/omit-server-errors/main_test.go @@ -3,7 +3,6 @@ package main import ( "bytes" stdContext "context" - "fmt" "strings" "testing" "time" @@ -14,7 +13,7 @@ import ( func logger(app *iris.Application) *bytes.Buffer { buf := &bytes.Buffer{} - app.Logger().Out = buf + app.Logger().SetOutput(buf) // disable the "Now running at...." in order to have a clean log of the error. // we could attach that on `Run` but better to keep things simple here. @@ -41,20 +40,12 @@ func TestListenAddr(t *testing.T) { t.Fatalf("expecting err to be `iris.ErrServerClosed` but got: %v", err) } - // println(log.Bytes()) - // println(len(log.Bytes())) + expectedMessage := iris.ErrServerClosed.Error() - expected := fmt.Sprintln("\"" + iris.ErrServerClosed.Error() + "\" ") - expected = strings.TrimSpace(expected) - // println([]byte(expected)) - // println(len([]byte(expected))) - - got := log.String() - got = strings.Split(got, "msg=")[1] - got = strings.TrimSpace(got) - if expected != got { - t.Fatalf("expecting to log the:\n'%s'\ninstead of:\n'%s'", expected, got) + if got := log.String(); !strings.Contains(got, expectedMessage) { + t.Fatalf("expecting to log to contains the:\n'%s'\ninstead of:\n'%s'", expectedMessage, got) } + } func TestListenAddrWithoutServerErr(t *testing.T) { diff --git a/_examples/http_request/request-logger/main.go b/_examples/http_request/request-logger/main.go index 5b3486bc..1239dc54 100644 --- a/_examples/http_request/request-logger/main.go +++ b/_examples/http_request/request-logger/main.go @@ -18,7 +18,8 @@ func main() { Method: true, // Path displays the request path Path: true, - // Columns: true, + + //Columns: true, // if !empty then its contents derives from `ctx.Values().Get("logger_message") // will be added to the logs. @@ -57,6 +58,6 @@ func main() { // http://localhost:8080/2 // http://lcoalhost:8080/notfoundhere // see the output on the console. - app.Run(iris.Addr(":8080")) + app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed)) } diff --git a/_examples/http_request/request-logger/request-logger-file/main.go b/_examples/http_request/request-logger/request-logger-file/main.go index 6f50644d..21fcf3d1 100644 --- a/_examples/http_request/request-logger/request-logger-file/main.go +++ b/_examples/http_request/request-logger/request-logger-file/main.go @@ -36,7 +36,7 @@ func main() { // http://localhost:8080/1 // http://localhost:8080/2 // http://lcoalhost:8080/notfoundhere - app.Run(iris.Addr(":8080")) + app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed)) } // get a filename based on the date, file logs works that way the most times diff --git a/_examples/miscellaneous/file-logger/main.go b/_examples/miscellaneous/file-logger/main.go index ac6f6a16..bd82c982 100644 --- a/_examples/miscellaneous/file-logger/main.go +++ b/_examples/miscellaneous/file-logger/main.go @@ -32,11 +32,11 @@ func main() { app := iris.New() // attach the file as logger, remember, iris' app logger is just an io.Writer. - app.Logger().Out = newLogFile() + app.Logger().SetOutput(newLogFile()) app.Get("/", func(ctx context.Context) { // for the sake of simplicity, in order see the logs at the ./_today_.txt - ctx.Application().Logger().Infoln("Request path: " + ctx.Path()) + ctx.Application().Logger().Info("Request path: " + ctx.Path()) ctx.Writef("hello") }) @@ -44,7 +44,7 @@ func main() { // and open the ./logs.txt file if err := app.Run(iris.Addr(":8080"), iris.WithoutBanner); err != nil { if err != iris.ErrServerClosed { - app.Logger().Warnln("Shutdown with error: " + err.Error()) + app.Logger().Warn("Shutdown with error: " + err.Error()) } } } diff --git a/_examples/websocket/secure/main.go b/_examples/websocket/secure/main.go index 95e63bd3..0a67134f 100644 --- a/_examples/websocket/secure/main.go +++ b/_examples/websocket/secure/main.go @@ -40,7 +40,7 @@ func main() { // using the go v1.8's HTTP/2 Push. // Note that you have to listen using ListenTLS in order this to work. if err := ctx.ResponseWriter().Push("/js/chat.js", nil); err != nil { - ctx.Application().Logger().Warnln(err.Error()) + ctx.Application().Logger().Warn(err.Error()) } ctx.ViewData("", clientPage{"Client Page", ctx.Host()}) ctx.View("client.html") diff --git a/context/application.go b/context/application.go index 24372941..5313c721 100644 --- a/context/application.go +++ b/context/application.go @@ -4,7 +4,7 @@ import ( "io" "net/http" - "github.com/sirupsen/logrus" + "github.com/kataras/golog" ) // Application is the context's owner. @@ -14,8 +14,8 @@ type Application interface { // ConfigurationReadOnly returns all the available configuration values can be used on a request. ConfigurationReadOnly() ConfigurationReadOnly - // Logger returns the logrus logger instance(pointer) that is being used inside the "app". - Logger() *logrus.Logger + // Logger returns the golog logger instance(pointer) that is being used inside the "app". + Logger() *golog.Logger // View executes and write the result of a template file to the writer. // diff --git a/context/context.go b/context/context.go index cc3bc659..36c8baa1 100644 --- a/context/context.go +++ b/context/context.go @@ -2231,7 +2231,7 @@ func (ctx *context) BeginTransaction(pipe func(t *Transaction)) { t := newTransaction(ctx) // it calls this *context, so the overriding with a new pool's New of context.Context wil not work here. defer func() { if err := recover(); err != nil { - ctx.Application().Logger().Warnln(errTransactionInterrupted.Format(err).Error()) + ctx.Application().Logger().Warn(errTransactionInterrupted.Format(err).Error()) // complete (again or not , doesn't matters) the scope without loud t.Complete(nil) // we continue as normal, no need to return here* diff --git a/doc.go b/doc.go index 44e4f632..a3d898ca 100644 --- a/doc.go +++ b/doc.go @@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub: Current Version -8.0.7 +8.1.0 Installation diff --git a/iris.go b/iris.go index 53a9c211..588a60f8 100644 --- a/iris.go +++ b/iris.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/sirupsen/logrus" + "github.com/kataras/golog" // context for the handlers "github.com/kataras/iris/context" @@ -33,7 +33,7 @@ import ( const ( // Version is the current version number of the Iris Web Framework. - Version = "8.0.7" + Version = "8.1.0" ) // HTTP status codes as registered with IANA. @@ -137,8 +137,8 @@ type Application struct { // all fields defaults to something that is working, developers don't have to set it. config *Configuration - // the logrus logger instance, defaults to "Info" level messages (all except "Debug") - logger *logrus.Logger + // the golog logger instance, defaults to "Info" level messages (all except "Debug") + logger *golog.Logger // view engine view view.View @@ -163,7 +163,7 @@ func New() *Application { app := &Application{ config: &config, - logger: logrus.New(), + logger: golog.Default, APIBuilder: router.NewAPIBuilder(), Router: router.NewRouter(), } @@ -207,20 +207,19 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly { // These are the different logging levels. You can set the logging level to log // on the application 's instance of logger, obtained with `app.Logger()`. // -// These are conversions from logrus. +// These are conversions from golog. const ( // NoLog level, logs nothing. - // It's the logrus' `PanicLevel` but it never used inside iris so it will never log. - NoLog = logrus.PanicLevel + NoLog = golog.DisableLevel // ErrorLevel level. Logs. Used for errors that should definitely be noted. // Commonly used for hooks to send errors to an error tracking service. - ErrorLevel = logrus.ErrorLevel + ErrorLevel = golog.ErrorLevel // WarnLevel level. Non-critical entries that deserve eyes. - WarnLevel = logrus.WarnLevel + WarnLevel = golog.WarnLevel ) -// Logger returns the logrus logger instance(pointer) that is being used inside the "app". -func (app *Application) Logger() *logrus.Logger { +// Logger returns the golog logger instance(pointer) that is being used inside the "app". +func (app *Application) Logger() *golog.Logger { return app.logger } @@ -264,13 +263,13 @@ func (app *Application) RegisterView(viewEngine view.Engine) { func (app *Application) View(writer io.Writer, filename string, layout string, bindingData interface{}) error { if app.view.Len() == 0 { err := errors.New("view engine is missing, use `RegisterView`") - app.Logger().Errorln(err) + app.Logger().Error(err) return err } err := app.view.ExecuteWriter(writer, filename, layout, bindingData) if err != nil { - app.Logger().Errorln(err) + app.Logger().Error(err) } return err } @@ -328,7 +327,7 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor { // check if different ErrorLog provided, if not bind it with the framework's logger if srv.ErrorLog == nil { - srv.ErrorLog = log.New(app.logger.Out, "[HTTP Server] ", 0) + srv.ErrorLog = log.New(app.logger.Printer.Output, "[HTTP Server] ", 0) } if srv.Addr == "" { @@ -352,7 +351,7 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor { if !app.config.DisableStartupLog { // show the available info to exit from app. - su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Out)) // app.logger.Writer -> Info + su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Printer.Output)) // app.logger.Writer -> Info } if !app.config.DisableInterruptHandler { @@ -543,7 +542,7 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error { // this will block until an error(unless supervisor's DeferFlow called from a Task). err := serve(app) if err != nil { - app.Logger().Errorln(err) + app.Logger().Error(err) } return err } diff --git a/middleware/logger/logger.go b/middleware/logger/logger.go index 3ec01d26..b4796484 100644 --- a/middleware/logger/logger.go +++ b/middleware/logger/logger.go @@ -79,14 +79,15 @@ func (l *requestLoggerMiddleware) ServeHTTP(ctx context.Context) { logFunc(endTime, latency, status, ip, method, path, message) return } - endTimeFormatted := endTime.Format("2006/01/02 - 15:04:05") + if l.config.Columns { + endTimeFormatted := endTime.Format("2006/01/02 - 15:04:05") output := Columnize(endTimeFormatted, latency, status, ip, method, path, message) - ctx.Application().Logger().Out.Write([]byte(output)) + ctx.Application().Logger().Printer.Output.Write([]byte(output)) return } // no new line, the framework's logger is responsible how to render each log. - line := fmt.Sprintf("%s | %v %4v %s %s %s", endTimeFormatted, status, latency, ip, method, path) + line := fmt.Sprintf("%v %4v %s %s %s", status, latency, ip, method, path) if message != nil { line += fmt.Sprintf(" %v", message) } diff --git a/middleware/recover/recover.go b/middleware/recover/recover.go index f725178a..54da827f 100644 --- a/middleware/recover/recover.go +++ b/middleware/recover/recover.go @@ -46,7 +46,7 @@ func New() context.Handler { logMessage += fmt.Sprintf("At Request: %s\n", getRequestLogs(ctx)) logMessage += fmt.Sprintf("Trace: %s\n", err) logMessage += fmt.Sprintf("\n%s", stacktrace) - ctx.Application().Logger().Warnln(logMessage) + ctx.Application().Logger().Warn(logMessage) ctx.StatusCode(500) ctx.StopExecution()