zaphttp is a Go library that provides structured logging for HTTP requests using zap. It creates a per-request logger that automatically has things like a trace ID injected into it.
- Per-request logger injection
- OpenTelemetry integration
- Flexible log formatting
- Built-in support for formats like Elastic Common Schema (ECS) and Google Cloud logging
- Customizable per-request logger behavior
go get github.com/marnixbouhuis/zaphttp
logger := zap.NewExample() zap.ReplaceGlobals(logger) defer func() { _ = logger.Sync() }() mux := http.NewServeMux() mux.HandleFunc("/demo/{$}", func(w http.ResponseWriter, req *http.Request) { // Optional, get the logger for this request from the context. // If you are using opentelemetry, the trace ID is automatically injected into each log message. l := zaphttp.FromContext(req.Context()) // Optional, log something with the request logger. l.Info("Some message!") w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("Hello world!")) }) requestLogger := zaphttp.NewHandler( zaphttp.WithLogger(logger), // If no logger is supplied, zap.L(), will be used. zaphttp.WithTraceFormatter(zaphttp.ElasticCommonSchemaFormatter), // If no format for trace metadata is supplied, ECS is used. zaphttp.WithRequestFormatter(zaphttp.ElasticCommonSchemaFormatter), // If no format for request metadata is supplied, ECS is used. ) s := &http.Server{ Addr: ":8080", ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, Handler: requestLogger(mux), // Wrap the mux, all requests will now be logged. } // Do graceful shutdown of HTTP server here... if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { logger.Error("Failed to start server", zap.Error(err)) }
Every request received by the HTTP server is now logged.
The main component is the NewHandler() function that creates a middleware to wrap your HTTP handlers.
Options:
WithLogger(logger *zap.Logger)- Set a custom logger (default:zap.L())WithTraceFormatter(formatter TraceFormatter)- Set a custom trace formatter (default: ECS)WithRequestFormatter(formatter RequestFormatter)- Set a custom request formatter (default: ECS)WithPerRequestLogger(fn PerRequestLoggerFunc)- Customize how the per-request logger is createdWithPerRequestFilter(fn PerRequestFilterFunc)- Customize which requests should be logged (default: all requests)
Formatters determine how request and trace information is structured in the logs.
Built-in formatters:
ElasticCommonSchemaFormatter- Formats logs according to the Elastic Common SchemaNewGoogleCloudFormatter(projectID)- Formats logs for Google Cloud LoggingNoopFormatter- Disables all extra fields
The per-request logger is injected into the request context and can be retrieved using FromContext(). It automatically includes:
- Trace ID (if using OpenTelemetry)
- Custom fields added by the per-request logger function
This project is licensed under the MIT License - see the LICENSE.md file for details.