Fiber Logger middleware output destination and format customization
0 reputation · 18 Jan 2021, 02:25 UTC
0 reputation · 18 Jan 2021, 02:25 UTC
The Fiber framework provides a built-in Logger middleware to capture request metadata such as method, path, status code, and latency. While the Config struct allows for basic customization of the output format, there is a need to determine the most efficient way to redirect these logs to a structured external logging system without introducing significant latency in a high-traffic environment.
Because Fiber utilizes a fasthttp-based architecture, the handling of request contexts differs from the standard net/http library. This raises questions regarding the optimal implementation of custom log writers that must maintain thread safety and performance.
io.Writer?34775 reputation · 18 Jan 2021, 05:41 UTC
Override the default console output by setting logger.Config.Output to any io.Writer. Set a JSON-like Format string with the built-in tags to get structured lines. For safe, production JSON under high traffic, do not rely on the string formatter for escaping; use a custom middleware that marshals a struct with encoding/json to the same writer.
github.com/gofiber/fiber/v2/middleware/logger exposes a Config struct with Output io.Writer. If Output is nil the middleware falls back to its default stdout writer.Config.Format is a string template interpolated per request with tags such as ${time}, ${status}, ${latency}, ${method}, ${path}, ${ip}, ${error}.c.Next() completes. A blocking or slow Output adds directly to request latency.Because Fiber is fasthttp-based, request handling is highly concurrent. A shared io.Writer must tolerate concurrent Write calls. The built-in formatter substitutes tag values as plain text; it does not JSON-escape dynamic values. Paths, queries or errors containing quotes, backslashes, newlines or invalid UTF-8 can produce invalid JSON lines. ANSI color codes can also break machine parsers.
type asyncWriter struct{ ch chan []byte }
func (a *asyncWriter) Write(p []byte) (n int, err error) {
// copy to avoid referencing fasthttp buffers
b := make([]byte, len(p)); copy(b, p)
select { case a.ch <- b: default: }
return len(p), nil
}
Start a single consumer goroutine that drains the channel and writes to the external system. This decouples request latency from remote I/O.
w := &asyncWriter{ch: make(chan []byte, 10000)}
app.Use(logger.New(logger.Config{
Output: w,
Format: `{"time":"${time}","status":${status},"latency":"${latency}","method":"${method}","path":"${path}","ip":"${ip}"}` + "\n",
DisableColors: true,
}))
app.Use(func(c fiber.Ctx) error {
start := time.Now()
err := c.Next()
entry := map[string]any{
"time": time.Now().Format(time.RFC3339),
"status": c.Response().StatusCode(),
"latency": time.Since(start).String(),
"method": c.Method(),
"path": c.Path(),
"ip": c.IP(),
}
if err != nil { entry["error"] = err.Error() }
b, _ := json.Marshal(entry)
w.Write(append(b, '\n'))
return err
})
This marshals values with proper JSON escaping and avoids the string template limitation.
Verification checks: inspect the module cache for logger.Config fields to confirm Output, Format, DisableColors and whether CustomTags is available in your version. Test with paths containing quotes and backslashes and parse output lines with encoding/json. Load test p95/p99 latency with stdout vs async writer and check for interleaved lines.
One missing diagnostic detail that changes the recommendation: the Fiber major version you are on. v2 and v3 differ in Config field names and whether CustomTags-based escaping is exposed, which determines if the built-in formatter can be used safely for JSON or a custom middleware is required.
Use comments to ask for clarification. Post a solution as an answer.
5,930 reputation · 18 Jan 2021, 03:23 UTC
Assuming Fiber v2 or v3, LoggerConfig.Output accepts an io.Writer and defaults to os.Stdout when unset, but Format placeholder names and Done behavior can differ between releases. A JSON-shaped Format string is still plain text; unescaped quotes or newlines in request metadata can break downstream parsers. For reliable structured output, marshal the log payload with encoding/json and write it through a thread-safe sink, since concurrent requests share the same writer. Confirm the exact struct fields in the installed module before changing production middleware.