Rename fields to match expressjs/morgan

pull/3333/head
Juan Calderon-Perez 2025-03-09 23:15:26 -04:00
parent 8c9313dc96
commit b479e966b6
5 changed files with 83 additions and 87 deletions

View File

@ -55,13 +55,13 @@ app.Use(logger.New(logger.Config{
}))
// Custom File Writer
file, err := os.OpenFile("./123.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
accessLog, err := os.OpenFile("./access.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
log.Fatalf("error opening access.log file: %v", err)
}
defer file.Close()
defer accessLog.Close()
app.Use(logger.New(logger.Config{
Output: file,
Stream: accessLog,
}))
// Add Custom Tags
@ -115,7 +115,7 @@ func main() {
// Use the logger middleware with zerolog logger
app.Use(logger.New(logger.Config{
Output: logger.LoggerToWriter(zap, log.LevelDebug),
Stream: logger.LoggerToWriter(zap, log.LevelDebug),
}))
// Define a route
@ -129,7 +129,7 @@ func main() {
```
:::tip
Writing to os.File is goroutine-safe, but if you are using a custom Output that is not goroutine-safe, make sure to implement locking to properly serialize writes.
Writing to os.File is goroutine-safe, but if you are using a custom Stream that is not goroutine-safe, make sure to implement locking to properly serialize writes.
:::
## Config
@ -138,33 +138,30 @@ Writing to os.File is goroutine-safe, but if you are using a custom Output that
| Property | Type | Description | Default |
|:-----------------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------|
| Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
| Filter | `func(fiber.Ctx) bool` | Filter is a function that is called before writing the log string to `Output`. If it returns true, the log will be skipped; otherwise, the log will be written. | `nil` |
| Done | `func(fiber.Ctx, []byte)` | Done is a function that is called after the log string for a request is written to Output, and pass the log string as parameter. | `nil` |
| Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
| Skip | `func(fiber.Ctx) bool` | Skip is a function to determine if logging is skipped or written to Stream. | `nil` |
| Done | `func(fiber.Ctx, []byte)` | Done is a function that is called after the log string for a request is written to Stream, and pass the log string as parameter. | `nil` |
| CustomTags | `map[string]LogFunc` | tagFunctions defines the custom tag action. | `map[string]LogFunc` |
| Format | `string` | Format defines the logging tags. | `[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}\n` |
| TimeFormat | `string` | TimeFormat defines the time format for log timestamps. | `15:04:05` |
| TimeZone | `string` | TimeZone can be specified, such as "UTC" and "America/New_York" and "Asia/Chongqing", etc | `"Local"` |
| TimeInterval | `time.Duration` | TimeInterval is the delay before the timestamp is updated. | `500 * time.Millisecond` |
| Output | `io.Writer` | Output is a writer where logs are written. | `os.Stdout` |
| Stream | `io.Writer` | Stream is a writer where logs are written. | `os.Stdout` |
| LoggerFunc | `func(c fiber.Ctx, data *Data, cfg Config) error` | Custom logger function for integration with logging libraries (Zerolog, Zap, Logrus, etc). Defaults to Fiber's default logger if not defined. | `see default_logger.go defaultLoggerInstance` |
| DisableColors | `bool` | DisableColors defines if the logs output should be colorized. | `false` |
| enableColors | `bool` | Internal field for enabling colors in the log output. (This is not a user-configurable field) | - |
| enableLatency | `bool` | Internal field for enabling latency measurement in logs. (This is not a user-configurable field) | - |
| timeZoneLocation | `*time.Location` | Internal field for the time zone location. (This is not a user-configurable field) | - |
## Default Config
```go
var ConfigDefault = Config{
Next: nil,
Filter nil,
Skip nil,
Done: nil,
Format: "[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}\n",
TimeFormat: "15:04:05",
TimeZone: "Local",
TimeInterval: 500 * time.Millisecond,
Output: os.Stdout,
Stream: os.Stdout,
DisableColors: false,
LoggerFunc: defaultLoggerInstance,
}

View File

@ -912,14 +912,14 @@ func main() {
</details>
The `Filter` is a function that is called before writing the log string to `Output`. If it returns true, the log will be skipped; otherwise, the log will be written.
The `Skip` is a function to determine if logging is skipped or written to `Stream`.
<details>
<summary>Example</summary>
<summary>Example Usage</summary>
```go
app.Use(logger.New(logger.Config{
Filter: func(c fiber.Ctx) bool {
Skip: func(c fiber.Ctx) bool {
// Skip logging HTTP 200 requests
return c.Response().StatusCode() == fiber.StatusOK
},
@ -928,8 +928,8 @@ app.Use(logger.New(logger.Config{
```go
app.Use(logger.New(logger.Config{
Filter: func(c fiber.Ctx) bool {
// Only log errors
Skip: func(c fiber.Ctx) bool {
// Only log errors, similar to an error.log
return c.Response().StatusCode() < 400
},
}))

View File

@ -10,21 +10,20 @@ import (
// Config defines the config for middleware.
type Config struct {
// Output is a writer where logs are written
// Stream is a writer where logs are written
//
// Default: os.Stdout
Output io.Writer
Stream io.Writer
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: nil
Next func(c fiber.Ctx) bool
// Filter is a function that is called before writing the log string to Output,
// If it returns true, the log will be skipped; otherwise, the log will be written.
// Skip is a function to determine if logging is skipped or written to Stream.
//
// Optional. Default: nil
Filter func(c fiber.Ctx) bool
Skip func(c fiber.Ctx) bool
// Done is a function that is called after the log string for a request is written to Output,
// and pass the log string as parameter.
@ -104,13 +103,13 @@ type LogFunc func(output Buffer, c fiber.Ctx, data *Data, extraParam string) (in
// ConfigDefault is the default config
var ConfigDefault = Config{
Next: nil,
Filter: nil,
Skip: nil,
Done: nil,
Format: defaultFormat,
TimeFormat: "15:04:05",
TimeZone: "Local",
TimeInterval: 500 * time.Millisecond,
Output: os.Stdout,
Stream: os.Stdout,
BeforeHandlerFunc: beforeHandlerFunc,
LoggerFunc: defaultLoggerInstance,
enableColors: true,
@ -133,8 +132,8 @@ func configDefault(config ...Config) Config {
if cfg.Next == nil {
cfg.Next = ConfigDefault.Next
}
if cfg.Filter == nil {
cfg.Filter = ConfigDefault.Filter
if cfg.Skip == nil {
cfg.Skip = ConfigDefault.Skip
}
if cfg.Done == nil {
cfg.Done = ConfigDefault.Done
@ -151,8 +150,8 @@ func configDefault(config ...Config) Config {
if int(cfg.TimeInterval) <= 0 {
cfg.TimeInterval = ConfigDefault.TimeInterval
}
if cfg.Output == nil {
cfg.Output = ConfigDefault.Output
if cfg.Stream == nil {
cfg.Stream = ConfigDefault.Stream
}
if cfg.BeforeHandlerFunc == nil {
@ -164,7 +163,7 @@ func configDefault(config ...Config) Config {
}
// Enable colors if no custom format or output is given
if !cfg.DisableColors && cfg.Output == ConfigDefault.Output {
if !cfg.DisableColors && cfg.Stream == ConfigDefault.Stream {
cfg.enableColors = true
}

View File

@ -17,7 +17,7 @@ import (
func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
// Check if Filter is defined and call it.
// Now, if Filter(c) == true, we SKIP logging:
if cfg.Filter != nil && cfg.Filter(c) {
if cfg.Skip != nil && cfg.Skip(c) {
return nil // Skip logging if Filter returns true
}
@ -97,7 +97,7 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
}
// Write buffer to output
writeLog(cfg.Output, buf.Bytes())
writeLog(cfg.Stream, buf.Bytes())
if cfg.Done != nil {
cfg.Done(c, buf.Bytes())
@ -131,7 +131,7 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
buf.WriteString(err.Error())
}
writeLog(cfg.Output, buf.Bytes())
writeLog(cfg.Stream, buf.Bytes())
if cfg.Done != nil {
cfg.Done(c, buf.Bytes())
@ -147,9 +147,9 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
func beforeHandlerFunc(cfg Config) {
// If colors are enabled, check terminal compatibility
if cfg.enableColors {
cfg.Output = colorable.NewColorableStdout()
cfg.Stream = colorable.NewColorableStdout()
if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) {
cfg.Output = colorable.NewNonColorable(os.Stdout)
cfg.Stream = colorable.NewNonColorable(os.Stdout)
}
}
}

View File

@ -71,7 +71,7 @@ func Test_Logger(t *testing.T) {
app.Use(New(Config{
Format: "${error}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(_ fiber.Ctx) error {
@ -94,7 +94,7 @@ func Test_Logger_locals(t *testing.T) {
app.Use(New(Config{
Format: "${locals:demo}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -184,10 +184,10 @@ func Test_Logger_Filter(t *testing.T) {
// Return true to skip logging for all requests != 404
app.Use(New(Config{
Filter: func(c fiber.Ctx) bool {
Skip: func(c fiber.Ctx) bool {
return c.Response().StatusCode() != fiber.StatusNotFound
},
Output: &logOutput,
Stream: &logOutput,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/nonexistent", nil))
@ -206,10 +206,10 @@ func Test_Logger_Filter(t *testing.T) {
// Return true to skip logging for all requests == 200
app.Use(New(Config{
Filter: func(c fiber.Ctx) bool {
Skip: func(c fiber.Ctx) bool {
return c.Response().StatusCode() == fiber.StatusOK
},
Output: &logOutput,
Stream: &logOutput,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -232,10 +232,10 @@ func Test_Logger_Filter(t *testing.T) {
// Filter always returns true => skip all logs
app.Use(New(Config{
Filter: func(_ fiber.Ctx) bool {
Skip: func(_ fiber.Ctx) bool {
return true // always skip
},
Output: &logOutput,
Stream: &logOutput,
}))
app.Get("/something", func(c fiber.Ctx) error {
@ -257,10 +257,10 @@ func Test_Logger_Filter(t *testing.T) {
// Filter always returns false => never skip logs
app.Use(New(Config{
Filter: func(_ fiber.Ctx) bool {
Skip: func(_ fiber.Ctx) bool {
return false // never skip
},
Output: &logOutput,
Stream: &logOutput,
}))
app.Get("/always", func(c fiber.Ctx) error {
@ -282,10 +282,10 @@ func Test_Logger_Filter(t *testing.T) {
// Filter returns true (skip logs) if the request path is /healthz
app.Use(New(Config{
Filter: func(c fiber.Ctx) bool {
Skip: func(c fiber.Ctx) bool {
return c.Path() == "/healthz"
},
Output: &logOutput,
Stream: &logOutput,
}))
// Normal route
@ -375,7 +375,7 @@ func Test_Logger_LoggerToWriter(t *testing.T) {
app.Use("/"+level, New(Config{
Format: "${error}",
Output: LoggerToWriter(logger, tc.
Stream: LoggerToWriter(logger, tc.
level),
}))
@ -417,7 +417,7 @@ func Test_Logger_ErrorOutput_WithoutColor(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
Output: o,
Stream: o,
DisableColors: true,
}))
@ -434,7 +434,7 @@ func Test_Logger_ErrorOutput(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
Output: o,
Stream: o,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
@ -453,7 +453,7 @@ func Test_Logger_All(t *testing.T) {
app.Use(New(Config{
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
Output: buf,
Stream: buf,
}))
// Alias colors
@ -499,7 +499,7 @@ func Test_Logger_WithLatency(t *testing.T) {
app := fiber.New()
logger := New(Config{
Output: buff,
Stream: buff,
Format: "${latency}",
})
app.Use(logger)
@ -544,7 +544,7 @@ func Test_Logger_WithLatency_DefaultFormat(t *testing.T) {
app := fiber.New()
logger := New(Config{
Output: buff,
Stream: buff,
})
app.Use(logger)
@ -594,7 +594,7 @@ func Test_Query_Params(t *testing.T) {
app.Use(New(Config{
Format: "${queryParams}",
Output: buf,
Stream: buf,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil))
@ -615,7 +615,7 @@ func Test_Response_Body(t *testing.T) {
app.Use(New(Config{
Format: "${resBody}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -649,7 +649,7 @@ func Test_Request_Body(t *testing.T) {
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf,
Stream: buf,
}))
app.Post("/", func(c fiber.Ctx) error {
@ -677,7 +677,7 @@ func Test_Logger_AppendUint(t *testing.T) {
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -752,7 +752,7 @@ func Test_Response_Header(t *testing.T) {
}))
app.Use(New(Config{
Format: "${respHeader:X-Request-ID}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!")
@ -775,7 +775,7 @@ func Test_Req_Header(t *testing.T) {
app.Use(New(Config{
Format: "${reqHeader:test}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!")
@ -799,7 +799,7 @@ func Test_ReqHeader_Header(t *testing.T) {
app.Use(New(Config{
Format: "${reqHeader:test}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!")
@ -830,7 +830,7 @@ func Test_CustomTags(t *testing.T) {
return output.WriteString(customTag)
},
},
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!")
@ -854,7 +854,7 @@ func Test_Logger_ByteSent_Streaming(t *testing.T) {
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf,
Stream: buf,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -900,7 +900,7 @@ func Test_Logger_EnableColors(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
Output: o,
Stream: o,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
@ -923,7 +923,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test")
@ -935,7 +935,7 @@ func Benchmark_Logger(b *testing.B) {
b.Run("DefaultFormat", func(bb *testing.B) {
app := fiber.New()
app.Use(New(Config{
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -946,7 +946,7 @@ func Benchmark_Logger(b *testing.B) {
b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
app := fiber.New()
app.Use(New(Config{
Output: io.Discard,
Stream: io.Discard,
DisableColors: true,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -960,7 +960,7 @@ func Benchmark_Logger(b *testing.B) {
logger := fiberlog.DefaultLogger()
logger.SetOutput(io.Discard)
app.Use(New(Config{
Output: LoggerToWriter(logger, fiberlog.LevelDebug),
Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -972,7 +972,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test")
@ -985,7 +985,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${locals:demo}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Locals("demo", "johndoe")
@ -998,7 +998,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${locals:demo}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/int", func(c fiber.Ctx) error {
c.Locals("demo", 55)
@ -1015,7 +1015,7 @@ func Benchmark_Logger(b *testing.B) {
io.Discard.Write(logString) //nolint:errcheck // ignore error
}
},
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/logging", func(ctx fiber.Ctx) error {
return ctx.SendStatus(fiber.StatusOK)
@ -1027,7 +1027,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -1039,7 +1039,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("Connection", "keep-alive")
@ -1068,7 +1068,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${resBody}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Sample response body")
@ -1091,7 +1091,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test")
@ -1103,7 +1103,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
b.Run("DefaultFormat", func(bb *testing.B) {
app := fiber.New()
app.Use(New(Config{
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -1116,7 +1116,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
logger := fiberlog.DefaultLogger()
logger.SetOutput(io.Discard)
app.Use(New(Config{
Output: LoggerToWriter(logger, fiberlog.LevelDebug),
Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -1127,7 +1127,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
app := fiber.New()
app.Use(New(Config{
Output: io.Discard,
Stream: io.Discard,
DisableColors: true,
}))
app.Get("/", func(c fiber.Ctx) error {
@ -1140,7 +1140,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test")
@ -1153,7 +1153,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${locals:demo}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Locals("demo", "johndoe")
@ -1166,7 +1166,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${locals:demo}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/int", func(c fiber.Ctx) error {
c.Locals("demo", 55)
@ -1183,7 +1183,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
io.Discard.Write(logString) //nolint:errcheck // ignore error
}
},
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/logging", func(ctx fiber.Ctx) error {
return ctx.SendStatus(fiber.StatusOK)
@ -1195,7 +1195,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
@ -1207,7 +1207,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
c.Set("Connection", "keep-alive")
@ -1236,7 +1236,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New()
app.Use(New(Config{
Format: "${resBody}",
Output: io.Discard,
Stream: io.Discard,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Sample response body")