Files

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 each
  • HiddenRequestHeaders / HiddenResponseHeaders — headers to redact
  • TraceIDKey / 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, ...}}