slog-echo

repository·main·Indexed 41 days ago

https://github.com/samber/slog-echo

Middleware for the Echo web framework that enables structured HTTP request logging using Go's standard slog library. Supports customizable log levels for different HTTP status categories, OpenTelemetry SpanID and TraceID integration, and extensive request/response filtering based on method, status, path, and host.

Tokens
4.2K
Snippets
15
Records
21
Agent score
49%

What's inside slog-echo

  1. Overview of slog-echo

    main
    slog-echo is a middleware for the Echo web framework that enables HTTP request logging using the standard Go slog library. It allows you to integrate structured logging directly into your Echo application lifecycle.
  2. Filter logged requests with slogecho.Filter

    main

    You can use slogecho.NewWithFilters to include or exclude logs based on specific criteria. Filters can inspect the echo.Context and the error returned by the handler.

    Commonly used filter functions include:

    • Accept / Ignore (can inspect error)
    • AcceptMethod / IgnoreMethod
    • AcceptStatus / IgnoreStatus
    • AcceptStatusGreaterThan / IgnoreStatusGreaterThan
    • AcceptStatusLessThan / IgnoreStatusLessThan
    • AcceptStatusGreaterThanOrEqual / IgnoreStatusGreaterThanOrEqual
    • AcceptStatusLessThanOrEqual / IgnoreStatusLessThanOrEqual
    • AcceptPath / IgnorePath
    • AcceptPathContains / IgnorePathContains
    • AcceptPathPrefix / IgnorePathPrefix
    • AcceptPathSuffix / IgnorePathSuffix
    • AcceptPathMatch / IgnorePathMatch
    • AcceptHost / IgnoreHost
    • AcceptHostContains / IgnoreHostContains
    • AcceptHostPrefix / IgnoreHostPrefix
    • AcceptHostSuffix / IgnoreHostSuffix
    • AcceptHostMatch / IgnoreHostMatch
    e.Use(
    	slogecho.NewWithFilters(
    		logger,
    		slogecho.Accept(func(c *echo.Context, err error) bool {
    			return err != nil
    		}),
    		slogecho.IgnoreStatus(401, 404),
    	),
    )
  3. Install slog-echo

    main

    Install the middleware using go get depending on your version of the Echo framework.

    • For Echo v5 (current), use the v2 module path.
    • For Echo v4 (legacy), use the base module path.

    Compatibility Requirements:

    • Go version: >= 1.25
    # echo v5 (current)
    go get github.com/samber/slog-echo/v2
    
    # echo v4 (legacy)
    go get github.com/samber/slog-echo
  4. Understand the Filter type and basic logic

    main

    A Filter is a function type used to decide whether a request should be logged or ignored by the middleware. It takes an *echo.Context and an error and returns a bool. If the filter returns true, the request is accepted (logged); if false, it is ignored.

    Basic utility functions allow you to wrap existing filters:

    • Accept(filter Filter): Returns the filter as-is.
    • Ignore(filter Filter): Returns a filter that negates the result of the provided filter.
    type Filter func(ctx *echo.Context, err error) bool
  5. Configure slogecho with Config struct

    main

    The slogecho.Config struct allows you to customize the middleware behavior. You can control log levels for different HTTP status categories, toggle the inclusion of specific request/response attributes (like headers, body, or trace IDs), and provide custom filters or message generators.

    Key configuration fields:

    • DefaultLevel: The log level for successful requests.
    • ClientErrorLevel: The log level for client errors (4xx).
    • ServerErrorLevel: The log level for server errors (5xx).
    • WithUserAgent, WithRequestID, WithRequestBody, WithRequestHeader, WithResponseBody, WithResponseHeader, WithSpanID, WithTraceID, WithClientIP: Boolean flags to include these attributes in the log payload.
    • WithCustomMessage: A function func(c *echo.Context, err error) string to customize the log message.
    • Filters: A slice of slogecho.Filter to include/exclude specific requests.
    type Config struct {
    	DefaultLevel     slog.Level
    	ClientErrorLevel slog.Level
    	ServerErrorLevel slog.Level
    
    	WithUserAgent      bool
    	WithRequestID      bool
    	WithRequestBody    bool
    	WithRequestHeader  bool
    	WithResponseBody   bool
    	WithResponseHeader bool
    	WithSpanID         bool
    	WithTraceID        bool
    	WithClientIP       bool
    	WithCustomMessage  func(c *echo.Context, err error) string
    
    	Filters []Filter
    }
  6. Use custom log levels for different HTTP statuses

    main

    You can define different slog.Level values for successful requests, client errors (4xx), and server errors (5xx) using the Config struct.

    config := slogecho.Config{
    	DefaultLevel:     slog.LevelInfo,
    	ClientErrorLevel: slog.LevelWarn,
    	ServerErrorLevel: slog.LevelError,
    }
    
    e.Use(slogecho.NewWithConfig(logger, config))
  7. Apply slogecho to a single route

    main

    Instead of applying the middleware globally via e.Use(), you can pass slogecho.New(logger) as a middleware argument to a specific route definition.

    e.GET("/", func(c *echo.Context) error {
    	return c.String(http.StatusOK, "Hello, World!")
    }, slogecho.New(logger))
  8. Implement minimal slogecho middleware

    main

    To use slogecho with minimal configuration, create a standard slog.Logger and pass it to slogecho.New(logger). This will log basic request/response metadata like method, path, status, and latency.

    import (
    	"log"
    	"net/http"
    	"os"
    
    	"github.com/labstack/echo/v5"
    	"github.com/labstack/echo/v5/middleware"
    	slogecho "github.com/samber/slog-echo"
    	"log/slog"
    )
    
    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    
    e := echo.New()
    
    e.Use(slogecho.New(logger))
    
    e.Use(middleware.Recover())
    
    e.GET("/", func(c *echo.Context) error {
    	return c.String(http.StatusOK, "Hello, World!")
    })
    
    log.Fatal(e.Start(":4242"))
  9. Enable verbose logging for request/response bodies and headers

    main

    To log full request/response details, set the following flags in slogecho.Config to true:

    • WithRequestBody
    • WithResponseBody
    • WithRequestHeader
    • WithResponseHeader
    config := slogecho.Config{
    	WithRequestBody: true,
    	WithResponseBody: true,
    	WithRequestHeader: true,
    	WithResponseHeader: true,
    }
    
    e.Use(slogecho.NewWithConfig(logger, config))
  10. Enable OTEL (OpenTelemetry) tracing in logs

    main

    To include OpenTelemetry SpanID and TraceID in your logs, use slogecho.NewWithConfig with the corresponding boolean flags set to true in the slogecho.Config.

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    
    config := slogecho.Config{
    	WithSpanID:  true,
    	WithTraceID: true,
    }
    
    e := echo.New()
    e.Use(slogecho.NewWithConfig(logger, config))
  11. Add custom attributes to log entries

    main

    You can add persistent attributes to all logs via the logger itself using logger.With(...), or add attributes to a specific request's log entry using slogecho.AddCustomAttributes(c, ...) within a handler.

    // Add to all logs via the logger
    logger = logger.With("env", "production")
    
    // Inside a route handler, add to the specific request log
    e.GET("/", func(c *echo.Context) error {
    	slogecho.AddCustomAttributes(c, slog.String("foo", "bar"))
    	return c.String(http.StatusOK, "Hello, World!")
    })
  12. Configure the slog-echo middleware with Config

    main

    The Config struct allows you to customize how requests are logged.

    Log Levels

    • DefaultLevel: The level used for successful requests (default: slog.LevelInfo).
    • ClientErrorLevel: The level used for 4xx status codes (default: slog.LevelWarn).
    • ServerErrorLevel: The level used for 5xx status codes (default: slog.LevelError).

    Data Capture Flags

    Set these to true to include specific data in the logs:

    • WithUserAgent: Include the User-Agent header.
    • WithRequestID: Include the Request ID (uses echo.HeaderXRequestID).
    • WithRequestBody: Include the request body (limited to RequestBodyMaxSize, default 64KB).
    • WithRequestHeader: Include request headers (sensitive headers like Authorization and Cookie are automatically hidden).
    • WithResponseBody: Include the response body (limited to ResponseBodyMaxSize, default 64KB).
    • WithResponseHeader: Include response headers (sensitive headers like Set-Cookie are automatically hidden).
    • WithSpanID: Include the OpenTelemetry Span ID.
    • WithTraceID: Include the OpenTelemetry Trace ID.
    • WithClientIP: Include the client IP address.

    Customization

    • WithCustomMessage: A function func(c *echo.Context, err error) string to override the default log message.
    • Filters: A slice of Filter functions to skip logging for specific requests.
    config := slogecho.Config{
    	DefaultLevel:     slog.LevelInfo,
    	ClientErrorLevel: slog.LevelWarn,
    	ServerErrorLevel: slog.LevelError,
    	WithRequestID:    true,
    	WithTraceID:      true,
    	WithSpanID:       true,
    	WithRequestBody:  true,
    }
    
    middleware := slogecho.NewWithConfig(slog.Default(), config)