5.1 KiB
5.1 KiB
HTTP Middlewares
All samber/slog HTTP middlewares share a consistent pattern and configuration structure.
Shared Config Fields
Every middleware provides a Config struct with these common fields:
| Field | Type | Default | Purpose |
|---|---|---|---|
DefaultLevel |
slog.Level |
slog.LevelInfo |
Log level for 2xx/3xx responses |
ClientErrorLevel |
slog.Level |
slog.LevelWarn |
Log level for 4xx responses |
ServerErrorLevel |
slog.Level |
slog.LevelError |
Log level for 5xx responses |
WithUserAgent |
bool |
false |
Include User-Agent header |
WithRequestID |
bool |
false |
Include request ID |
WithRequestBody |
bool |
false |
Include request body (capped) |
WithResponseBody |
bool |
false |
Include response body (capped) |
WithRequestHeader |
bool |
false |
Include request headers |
WithResponseHeader |
bool |
false |
Include response headers |
WithSpanID |
bool |
false |
Include OpenTelemetry span ID |
WithTraceID |
bool |
false |
Include OpenTelemetry trace ID |
WithClientIP |
bool |
false |
Include client IP address |
Filters |
[]Filter |
nil |
Request filter functions |
Global configuration variables (set before creating middleware):
RequestBodyMaxSize/ResponseBodyMaxSize— default 64KB eachHiddenRequestHeaders/HiddenResponseHeaders— headers to redactTraceIDKey/SpanIDKey— context key names for OpenTelemetry
Default Log Fields
All middlewares emit these fields by default: method, path, status, latency, request-length, response-length.
Gin — slog-gin
import sloggin "github.com/samber/slog-gin"
// Simple
router := gin.New()
router.Use(sloggin.New(logger))
// With config
router.Use(sloggin.NewWithConfig(logger, sloggin.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
WithUserAgent: true,
Filters: []sloggin.Filter{
sloggin.IgnorePath("/health", "/metrics"),
sloggin.IgnorePathPrefix("/static"),
},
}))
// Custom attributes per request
router.GET("/api/users", func(c *gin.Context) {
sloggin.AddCustomAttributes(c, slog.String("user_id", userID))
c.JSON(200, users)
})
Echo — slog-echo
import slogecho "github.com/samber/slog-echo"
e := echo.New()
e.Use(slogecho.New(logger))
// With config
e.Use(slogecho.NewWithConfig(logger, slogecho.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
Filters: []slogecho.Filter{
slogecho.IgnoreStatus(404),
slogecho.IgnorePath("/health"),
},
}))
// Custom attributes
e.GET("/api/users", func(c echo.Context) error {
slogecho.AddCustomAttributes(c, slog.String("user_id", userID))
return c.JSON(200, users)
})
Fiber — slog-fiber
import slogfiber "github.com/samber/slog-fiber"
app := fiber.New()
app.Use(slogfiber.New(logger))
// With config
app.Use(slogfiber.NewWithConfig(logger, slogfiber.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
Filters: []slogfiber.Filter{
slogfiber.IgnorePath("/health"),
slogfiber.IgnoreStatus(404),
},
}))
// Custom attributes
app.Get("/api/users", func(c fiber.Ctx) error {
slogfiber.AddCustomAttributes(c, slog.String("user_id", userID))
return c.JSON(users)
})
Note: Fiber uses fasthttp, not net/http. Request/response types differ.
Chi — slog-chi
import slogchi "github.com/samber/slog-chi"
router := chi.NewRouter()
router.Use(slogchi.New(logger))
// With config
router.Use(slogchi.NewWithConfig(logger, slogchi.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
Filters: []slogchi.Filter{
slogchi.IgnorePath("/health", "/ready"),
slogchi.IgnoreStatus(401, 404),
},
}))
// Custom attributes
router.Get("/api/users", func(w http.ResponseWriter, r *http.Request) {
slogchi.AddCustomAttributes(r, slog.String("user_id", userID))
json.NewEncoder(w).Encode(users)
})
net/http — slog-http
import sloghttp "github.com/samber/slog-http"
mux := http.NewServeMux()
handler := sloghttp.New(logger)(mux)
http.ListenAndServe(":8080", handler)
Filters
All middlewares support the same filter functions:
sloggin.IgnorePath("/health", "/metrics") // exact path match
sloggin.IgnorePathPrefix("/static", "/assets") // path prefix
sloggin.IgnoreStatus(401, 404) // skip specific status codes
// Custom filter
sloggin.Accept(func(c *gin.Context) bool {
return c.Request.Method != "OPTIONS" // skip CORS preflight
})
Logger Grouping
Wrap the logger with WithGroup("http") to namespace all middleware attributes under an http group:
router.Use(sloggin.New(logger.WithGroup("http")))
// Output: {"http": {"method": "GET", "path": "/api", "status": 200, ...}}