🔥 feat: Add Skip function to logger middleware (#3333)

* 🔥 Feature(logger): Add Filter option to logger middleware

* 📚 Doc(logger): Clarify Filter middleware description

* 🚨 Test(logger): Enhance logger filter test with parallel subtests

* 🔒 Test(logger): Add mutex to prevent race conditions in logger test

* 🔥 Feature(logger): Add Filter option to logger middleware

* 📚 Doc(logger): Clarify Filter middleware description

* 🚨 Test(logger): Enhance logger filter test with parallel subtests

* 🔒 Test(logger): Add mutex to prevent race conditions in logger test

* 🚨 Test(logger): Refactor logger test to improve test isolation

* Fix issue with unit-tests

* Update middleware/logger/logger_test.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Apply logger filter as soon as possible

* 📚 Doc: Add logger filter configuration example to whats_new.md

* 📚 Doc: Update logger filter documentation in whats_new.md

* 📚 Doc: Update logger filter documentation and examples

* 🩹 Fix: improve what_new.md

* Update logic for Filter() in Logger middleware. Add more unit-tests

* Rename fields to match expressjs/morgan

* Update middleware/logger/default_logger.go

---------

Co-authored-by: Juan Calderon-Perez <jgcalderonperez@protonmail.com>
Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: RW <rene@gofiber.io>
pull/3348/head
JIeJaitt 2025-03-10 16:06:11 +08:00 committed by GitHub
parent 1b26cf6b5e
commit c0599ee1d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 243 additions and 63 deletions

View File

@ -55,13 +55,13 @@ app.Use(logger.New(logger.Config{
})) }))
// Custom File Writer // 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 { 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{ app.Use(logger.New(logger.Config{
Output: file, Stream: accessLog,
})) }))
// Add Custom Tags // Add Custom Tags
@ -115,7 +115,7 @@ func main() {
// Use the logger middleware with zerolog logger // Use the logger middleware with zerolog logger
app.Use(logger.New(logger.Config{ app.Use(logger.New(logger.Config{
Output: logger.LoggerToWriter(zap, log.LevelDebug), Stream: logger.LoggerToWriter(zap, log.LevelDebug),
})) }))
// Define a route // Define a route
@ -129,7 +129,7 @@ func main() {
``` ```
:::tip :::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 ## Config
@ -138,31 +138,30 @@ Writing to os.File is goroutine-safe, but if you are using a custom Output that
| Property | Type | Description | Default | | Property | Type | Description | Default |
|:-----------------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------| |:-----------------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------|
| Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | | Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `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` | | 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` | | 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` | | 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` | | 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"` | | 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` | | 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` | | 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` | | 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 ## Default Config
```go ```go
var ConfigDefault = Config{ var ConfigDefault = Config{
Next: nil, Next: nil,
Skip nil,
Done: nil, Done: nil,
Format: "[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}\n", Format: "[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}\n",
TimeFormat: "15:04:05", TimeFormat: "15:04:05",
TimeZone: "Local", TimeZone: "Local",
TimeInterval: 500 * time.Millisecond, TimeInterval: 500 * time.Millisecond,
Output: os.Stdout, Stream: os.Stdout,
DisableColors: false, DisableColors: false,
LoggerFunc: defaultLoggerInstance, LoggerFunc: defaultLoggerInstance,
} }

View File

@ -912,6 +912,31 @@ func main() {
</details> </details>
The `Skip` is a function to determine if logging is skipped or written to `Stream`.
<details>
<summary>Example Usage</summary>
```go
app.Use(logger.New(logger.Config{
Skip: func(c fiber.Ctx) bool {
// Skip logging HTTP 200 requests
return c.Response().StatusCode() == fiber.StatusOK
},
}))
```
```go
app.Use(logger.New(logger.Config{
Skip: func(c fiber.Ctx) bool {
// Only log errors, similar to an error.log
return c.Response().StatusCode() < 400
},
}))
```
</details>
### Filesystem ### Filesystem
We've decided to remove filesystem middleware to clear up the confusion between static and filesystem middleware. We've decided to remove filesystem middleware to clear up the confusion between static and filesystem middleware.

View File

@ -10,16 +10,21 @@ import (
// Config defines the config for middleware. // Config defines the config for middleware.
type Config struct { type Config struct {
// Output is a writer where logs are written // Stream is a writer where logs are written
// //
// Default: os.Stdout // Default: os.Stdout
Output io.Writer Stream io.Writer
// Next defines a function to skip this middleware when returned true. // Next defines a function to skip this middleware when returned true.
// //
// Optional. Default: nil // Optional. Default: nil
Next func(c fiber.Ctx) bool Next func(c fiber.Ctx) bool
// Skip is a function to determine if logging is skipped or written to Stream.
//
// Optional. Default: nil
Skip func(c fiber.Ctx) bool
// Done is a function that is called after the log string for a request is written to Output, // 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. // and pass the log string as parameter.
// //
@ -98,12 +103,13 @@ type LogFunc func(output Buffer, c fiber.Ctx, data *Data, extraParam string) (in
// ConfigDefault is the default config // ConfigDefault is the default config
var ConfigDefault = Config{ var ConfigDefault = Config{
Next: nil, Next: nil,
Skip: nil,
Done: nil, Done: nil,
Format: defaultFormat, Format: defaultFormat,
TimeFormat: "15:04:05", TimeFormat: "15:04:05",
TimeZone: "Local", TimeZone: "Local",
TimeInterval: 500 * time.Millisecond, TimeInterval: 500 * time.Millisecond,
Output: os.Stdout, Stream: os.Stdout,
BeforeHandlerFunc: beforeHandlerFunc, BeforeHandlerFunc: beforeHandlerFunc,
LoggerFunc: defaultLoggerInstance, LoggerFunc: defaultLoggerInstance,
enableColors: true, enableColors: true,
@ -126,6 +132,9 @@ func configDefault(config ...Config) Config {
if cfg.Next == nil { if cfg.Next == nil {
cfg.Next = ConfigDefault.Next cfg.Next = ConfigDefault.Next
} }
if cfg.Skip == nil {
cfg.Skip = ConfigDefault.Skip
}
if cfg.Done == nil { if cfg.Done == nil {
cfg.Done = ConfigDefault.Done cfg.Done = ConfigDefault.Done
} }
@ -141,8 +150,8 @@ func configDefault(config ...Config) Config {
if int(cfg.TimeInterval) <= 0 { if int(cfg.TimeInterval) <= 0 {
cfg.TimeInterval = ConfigDefault.TimeInterval cfg.TimeInterval = ConfigDefault.TimeInterval
} }
if cfg.Output == nil { if cfg.Stream == nil {
cfg.Output = ConfigDefault.Output cfg.Stream = ConfigDefault.Stream
} }
if cfg.BeforeHandlerFunc == nil { if cfg.BeforeHandlerFunc == nil {
@ -154,7 +163,7 @@ func configDefault(config ...Config) Config {
} }
// Enable colors if no custom format or output is given // 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 cfg.enableColors = true
} }

View File

@ -15,6 +15,12 @@ import (
// default logger for fiber // default logger for fiber
func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error { func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
// Check if Skip is defined and call it.
// Now, if Skip(c) == true, we SKIP logging:
if cfg.Skip != nil && cfg.Skip(c) {
return nil // Skip logging if Skip returns true
}
// Alias colors // Alias colors
colors := c.App().Config().ColorScheme colors := c.App().Config().ColorScheme
@ -91,7 +97,7 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
} }
// Write buffer to output // Write buffer to output
writeLog(cfg.Output, buf.Bytes()) writeLog(cfg.Stream, buf.Bytes())
if cfg.Done != nil { if cfg.Done != nil {
cfg.Done(c, buf.Bytes()) cfg.Done(c, buf.Bytes())
@ -125,7 +131,7 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
buf.WriteString(err.Error()) buf.WriteString(err.Error())
} }
writeLog(cfg.Output, buf.Bytes()) writeLog(cfg.Stream, buf.Bytes())
if cfg.Done != nil { if cfg.Done != nil {
cfg.Done(c, buf.Bytes()) cfg.Done(c, buf.Bytes())
@ -141,9 +147,9 @@ func defaultLoggerInstance(c fiber.Ctx, data *Data, cfg Config) error {
func beforeHandlerFunc(cfg Config) { func beforeHandlerFunc(cfg Config) {
// If colors are enabled, check terminal compatibility // If colors are enabled, check terminal compatibility
if cfg.enableColors { 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())) { 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{ app.Use(New(Config{
Format: "${error}", Format: "${error}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(_ fiber.Ctx) error { app.Get("/", func(_ fiber.Ctx) error {
@ -94,7 +94,7 @@ func Test_Logger_locals(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${locals:demo}", Format: "${locals:demo}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -171,6 +171,147 @@ func Test_Logger_Done(t *testing.T) {
require.Positive(t, buf.Len(), 0) require.Positive(t, buf.Len(), 0)
} }
// Test_Logger_Filter tests the Filter functionality of the logger middleware.
// It verifies that logs are written or skipped based on the filter condition.
func Test_Logger_Filter(t *testing.T) {
t.Parallel()
t.Run("Test Not Found", func(t *testing.T) {
t.Parallel()
app := fiber.New()
logOutput := bytes.Buffer{}
// Return true to skip logging for all requests != 404
app.Use(New(Config{
Skip: func(c fiber.Ctx) bool {
return c.Response().StatusCode() != fiber.StatusNotFound
},
Stream: &logOutput,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/nonexistent", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
// Expect logs for the 404 request
require.Contains(t, logOutput.String(), "404")
})
t.Run("Test OK", func(t *testing.T) {
t.Parallel()
app := fiber.New()
logOutput := bytes.Buffer{}
// Return true to skip logging for all requests == 200
app.Use(New(Config{
Skip: func(c fiber.Ctx) bool {
return c.Response().StatusCode() == fiber.StatusOK
},
Stream: &logOutput,
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusOK, resp.StatusCode)
// We skip logging for status == 200, so "200" should not appear
require.NotContains(t, logOutput.String(), "200")
})
t.Run("Always Skip", func(t *testing.T) {
t.Parallel()
app := fiber.New()
logOutput := bytes.Buffer{}
// Filter always returns true => skip all logs
app.Use(New(Config{
Skip: func(_ fiber.Ctx) bool {
return true // always skip
},
Stream: &logOutput,
}))
app.Get("/something", func(c fiber.Ctx) error {
return c.Status(fiber.StatusTeapot).SendString("I'm a teapot")
})
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/something", nil))
require.NoError(t, err)
// Expect NO logs
require.Empty(t, logOutput.String())
})
t.Run("Never Skip", func(t *testing.T) {
t.Parallel()
app := fiber.New()
logOutput := bytes.Buffer{}
// Filter always returns false => never skip logs
app.Use(New(Config{
Skip: func(_ fiber.Ctx) bool {
return false // never skip
},
Stream: &logOutput,
}))
app.Get("/always", func(c fiber.Ctx) error {
return c.Status(fiber.StatusTeapot).SendString("Teapot again")
})
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/always", nil))
require.NoError(t, err)
// Expect some logging - check any substring
require.Contains(t, logOutput.String(), strconv.Itoa(fiber.StatusTeapot))
})
t.Run("Skip /healthz", func(t *testing.T) {
t.Parallel()
app := fiber.New()
logOutput := bytes.Buffer{}
// Filter returns true (skip logs) if the request path is /healthz
app.Use(New(Config{
Skip: func(c fiber.Ctx) bool {
return c.Path() == "/healthz"
},
Stream: &logOutput,
}))
// Normal route
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello World!")
})
// Health route
app.Get("/healthz", func(c fiber.Ctx) error {
return c.SendString("OK")
})
// Request to "/" -> should be logged
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
require.NoError(t, err)
require.Contains(t, logOutput.String(), "200")
// Reset output buffer
logOutput.Reset()
// Request to "/healthz" -> should be skipped
_, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/healthz", nil))
require.NoError(t, err)
require.Empty(t, logOutput.String())
})
}
// go test -run Test_Logger_ErrorTimeZone // go test -run Test_Logger_ErrorTimeZone
func Test_Logger_ErrorTimeZone(t *testing.T) { func Test_Logger_ErrorTimeZone(t *testing.T) {
t.Parallel() t.Parallel()
@ -234,7 +375,7 @@ func Test_Logger_LoggerToWriter(t *testing.T) {
app.Use("/"+level, New(Config{ app.Use("/"+level, New(Config{
Format: "${error}", Format: "${error}",
Output: LoggerToWriter(logger, tc. Stream: LoggerToWriter(logger, tc.
level), level),
})) }))
@ -276,7 +417,7 @@ func Test_Logger_ErrorOutput_WithoutColor(t *testing.T) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: o, Stream: o,
DisableColors: true, DisableColors: true,
})) }))
@ -293,7 +434,7 @@ func Test_Logger_ErrorOutput(t *testing.T) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: o, Stream: o,
})) }))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
@ -312,7 +453,7 @@ func Test_Logger_All(t *testing.T) {
app.Use(New(Config{ 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}", 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 // Alias colors
@ -358,7 +499,7 @@ func Test_Logger_WithLatency(t *testing.T) {
app := fiber.New() app := fiber.New()
logger := New(Config{ logger := New(Config{
Output: buff, Stream: buff,
Format: "${latency}", Format: "${latency}",
}) })
app.Use(logger) app.Use(logger)
@ -403,7 +544,7 @@ func Test_Logger_WithLatency_DefaultFormat(t *testing.T) {
app := fiber.New() app := fiber.New()
logger := New(Config{ logger := New(Config{
Output: buff, Stream: buff,
}) })
app.Use(logger) app.Use(logger)
@ -453,7 +594,7 @@ func Test_Query_Params(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${queryParams}", Format: "${queryParams}",
Output: buf, Stream: buf,
})) }))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil)) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil))
@ -474,7 +615,7 @@ func Test_Response_Body(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${resBody}", Format: "${resBody}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -508,7 +649,7 @@ func Test_Request_Body(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf, Stream: buf,
})) }))
app.Post("/", func(c fiber.Ctx) error { app.Post("/", func(c fiber.Ctx) error {
@ -536,7 +677,7 @@ func Test_Logger_AppendUint(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -611,7 +752,7 @@ func Test_Response_Header(t *testing.T) {
})) }))
app.Use(New(Config{ app.Use(New(Config{
Format: "${respHeader:X-Request-ID}", Format: "${respHeader:X-Request-ID}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!") return c.SendString("Hello fiber!")
@ -634,7 +775,7 @@ func Test_Req_Header(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${reqHeader:test}", Format: "${reqHeader:test}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!") return c.SendString("Hello fiber!")
@ -658,7 +799,7 @@ func Test_ReqHeader_Header(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${reqHeader:test}", Format: "${reqHeader:test}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!") return c.SendString("Hello fiber!")
@ -689,7 +830,7 @@ func Test_CustomTags(t *testing.T) {
return output.WriteString(customTag) return output.WriteString(customTag)
}, },
}, },
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello fiber!") return c.SendString("Hello fiber!")
@ -713,7 +854,7 @@ func Test_Logger_ByteSent_Streaming(t *testing.T) {
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: buf, Stream: buf,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -759,7 +900,7 @@ func Test_Logger_EnableColors(t *testing.T) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: o, Stream: o,
})) }))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
@ -782,7 +923,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test") c.Set("test", "test")
@ -794,7 +935,7 @@ func Benchmark_Logger(b *testing.B) {
b.Run("DefaultFormat", func(bb *testing.B) { b.Run("DefaultFormat", func(bb *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -805,7 +946,7 @@ func Benchmark_Logger(b *testing.B) {
b.Run("DefaultFormatDisableColors", func(bb *testing.B) { b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: io.Discard, Stream: io.Discard,
DisableColors: true, DisableColors: true,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -819,7 +960,7 @@ func Benchmark_Logger(b *testing.B) {
logger := fiberlog.DefaultLogger() logger := fiberlog.DefaultLogger()
logger.SetOutput(io.Discard) logger.SetOutput(io.Discard)
app.Use(New(Config{ app.Use(New(Config{
Output: LoggerToWriter(logger, fiberlog.LevelDebug), Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -831,7 +972,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}", Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test") c.Set("test", "test")
@ -844,7 +985,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${locals:demo}", Format: "${locals:demo}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Locals("demo", "johndoe") c.Locals("demo", "johndoe")
@ -857,7 +998,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${locals:demo}", Format: "${locals:demo}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/int", func(c fiber.Ctx) error { app.Get("/int", func(c fiber.Ctx) error {
c.Locals("demo", 55) c.Locals("demo", 55)
@ -874,7 +1015,7 @@ func Benchmark_Logger(b *testing.B) {
io.Discard.Write(logString) //nolint:errcheck // ignore error io.Discard.Write(logString) //nolint:errcheck // ignore error
} }
}, },
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/logging", func(ctx fiber.Ctx) error { app.Get("/logging", func(ctx fiber.Ctx) error {
return ctx.SendStatus(fiber.StatusOK) return ctx.SendStatus(fiber.StatusOK)
@ -886,7 +1027,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ 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}", 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 { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -898,7 +1039,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("Connection", "keep-alive") c.Set("Connection", "keep-alive")
@ -927,7 +1068,7 @@ func Benchmark_Logger(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${resBody}", Format: "${resBody}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Sample response body") return c.SendString("Sample response body")
@ -950,7 +1091,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test") c.Set("test", "test")
@ -962,7 +1103,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
b.Run("DefaultFormat", func(bb *testing.B) { b.Run("DefaultFormat", func(bb *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -975,7 +1116,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
logger := fiberlog.DefaultLogger() logger := fiberlog.DefaultLogger()
logger.SetOutput(io.Discard) logger.SetOutput(io.Discard)
app.Use(New(Config{ app.Use(New(Config{
Output: LoggerToWriter(logger, fiberlog.LevelDebug), Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -986,7 +1127,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
b.Run("DefaultFormatDisableColors", func(bb *testing.B) { b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Output: io.Discard, Stream: io.Discard,
DisableColors: true, DisableColors: true,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
@ -999,7 +1140,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}", Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("test", "test") c.Set("test", "test")
@ -1012,7 +1153,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${locals:demo}", Format: "${locals:demo}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Locals("demo", "johndoe") c.Locals("demo", "johndoe")
@ -1025,7 +1166,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${locals:demo}", Format: "${locals:demo}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/int", func(c fiber.Ctx) error { app.Get("/int", func(c fiber.Ctx) error {
c.Locals("demo", 55) c.Locals("demo", 55)
@ -1042,7 +1183,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
io.Discard.Write(logString) //nolint:errcheck // ignore error io.Discard.Write(logString) //nolint:errcheck // ignore error
} }
}, },
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/logging", func(ctx fiber.Ctx) error { app.Get("/logging", func(ctx fiber.Ctx) error {
return ctx.SendStatus(fiber.StatusOK) return ctx.SendStatus(fiber.StatusOK)
@ -1054,7 +1195,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ 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}", 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 { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!") return c.SendString("Hello, World!")
@ -1066,7 +1207,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${bytesReceived} ${bytesSent} ${status}", Format: "${bytesReceived} ${bytesSent} ${status}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
c.Set("Connection", "keep-alive") c.Set("Connection", "keep-alive")
@ -1095,7 +1236,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
app := fiber.New() app := fiber.New()
app.Use(New(Config{ app.Use(New(Config{
Format: "${resBody}", Format: "${resBody}",
Output: io.Discard, Stream: io.Discard,
})) }))
app.Get("/", func(c fiber.Ctx) error { app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Sample response body") return c.SendString("Sample response body")