middleware

package module
v0.0.0-...-93f8639 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2025 License: MIT Imports: 23 Imported by: 0

README

mtlog HTTP Middleware

HTTP request/response logging middleware for Go web frameworks using mtlog structured logging.

Features

  • 🚀 Support for multiple frameworks: net/http, Gin, Echo, Fiber, Chi
  • 🔍 Automatic request ID generation and propagation
  • ⏱️ Request latency tracking with configurable units
  • 📊 Customizable log levels based on HTTP status codes
  • 🎯 Selective path skipping (e.g., health checks)
  • 🔗 Context injection for nested logging
  • 📝 Configurable request field logging
  • 🛡️ Request/response body logging with sanitization
  • 📈 Advanced sampling strategies (rate, adaptive, path-based)
  • 🎛️ Custom field extractors for dynamic context
  • 💥 Panic recovery with stack traces
  • 📊 Metrics integration (Prometheus/OpenTelemetry ready)
  • 🔧 Request logger helper for fluent API
  • ✅ Options validation for fail-fast configuration

Installation

go get github.com/willibrandon/mtlog/adapters/middleware

Quick Start

net/http
import (
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/adapters/middleware"
)

logger := mtlog.New(mtlog.WithConsole())
mw := middleware.Middleware(middleware.DefaultOptions(logger))

handler := mw(yourHandler)
http.ListenAndServe(":8080", handler)
Gin
import (
    "github.com/gin-gonic/gin"
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/adapters/middleware"
)

logger := mtlog.New(mtlog.WithConsole())
router := gin.New()
router.Use(middleware.Gin(logger))
Echo
import (
    "github.com/labstack/echo/v4"
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/adapters/middleware"
)

logger := mtlog.New(mtlog.WithConsole())
e := echo.New()
e.Use(middleware.Echo(logger))
Fiber
import (
    "github.com/gofiber/fiber/v2"
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/adapters/middleware"
)

logger := mtlog.New(mtlog.WithConsole())
app := fiber.New()
app.Use(middleware.Fiber(logger))
Chi
import (
    "github.com/go-chi/chi/v5"
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/adapters/middleware"
)

logger := mtlog.New(mtlog.WithConsole())
r := chi.NewRouter()
r.Use(middleware.Chi(logger))

Performance Characteristics

The middleware is highly optimized for production use with minimal overhead:

  • Skip paths: ~98ns, 4 allocations (near-zero overhead)
  • Sampled out: ~333ns, 37 allocations (when request is not logged)
  • Full logging: ~2.4μs, 56 allocations (complete request logging)
  • Memory per request: ~4.4KB average
  • Raw handler baseline: ~102ns (for comparison)

The middleware adds approximately 2.3μs of overhead to each logged request, which is negligible for most HTTP services. Skip paths and sampling can further reduce this overhead for high-traffic endpoints.

Allocation Breakdown
  • ResponseWriter wrapper: 6 allocations
  • UUID generation: 2 allocations
  • Context operations: 4 allocations
  • Logger.With() calls: ~8 allocations per field
  • Template args slice: 1 allocation

Configuration Options

options := &middleware.Options{
    Logger:            logger,           // mtlog logger instance
    GenerateRequestID: true,             // Auto-generate request IDs
    RequestIDHeader:   "X-Request-ID",   // Header for request ID
    SkipPaths:         []string{         // Paths to skip logging
        "/health",
        "/metrics",
    },
    RequestFields: []string{             // Fields to include in logs
        "method",
        "path", 
        "ip",
        "user_agent",
        "referer",
        "proto",
        "host",
    },
    LatencyField: "duration_ms",         // Field name for latency
    LatencyUnit:  "ms",                  // Unit: ms, us, ns, s
    CustomLevelFunc: func(statusCode int) core.LogEventLevel {
        switch {
        case statusCode >= 500:
            return core.ErrorLevel
        case statusCode >= 400:
            return core.WarningLevel
        default:
            return core.InformationLevel
        }
    },
    
    // Advanced features
    LogRequestBody:  true,                // Log request bodies
    LogResponseBody: true,                // Log response bodies
    MaxBodySize:     4096,                // Max body size to log
    BodySanitizer:   middleware.DefaultBodySanitizer, // Sanitize sensitive fields
    
    // Sampling
    Sampler: middleware.NewPathSamplerBuilder().
        Never("/health").
        Never("/metrics").
        Sometimes("/api/status", 0.1).
        Always("*").
        Build(),
    
    // Custom field extraction
    CustomFields: []middleware.FieldExtractor{
        middleware.UserIDFromHeader,
        middleware.TraceIDFromContext,
        middleware.TenantIDFromSubdomain,
    },
    
    // Metrics recording
    MetricsRecorder: myMetricsRecorder,
    
    // Panic handling
    PanicHandler: func(w http.ResponseWriter, r *http.Request, err any) {
        // Custom panic response
    },
}

Advanced Features

Body Logging and Sanitization

Log request and response bodies with automatic sanitization of sensitive fields:

options := &middleware.Options{
    LogRequestBody:  true,
    LogResponseBody: true,
    MaxBodySize:     2048,
    BodySanitizer:   middleware.DefaultBodySanitizer, // Redacts passwords, tokens, etc.
}

The default sanitizer automatically redacts common sensitive fields in JSON payloads. You can also create custom sanitizers:

options.BodySanitizer = middleware.RegexBodySanitizer(
    regexp.MustCompile(`"credit_card":\s*"[^"]+"`),
    regexp.MustCompile(`"ssn":\s*"[^"]+"`),
)
Sampling Strategies

Control which requests get logged to manage log volume:

// Rate-based sampling (log 10% of requests)
options.Sampler = middleware.NewRateSampler(0.1)

// Adaptive sampling (target 100 logs per second)
options.Sampler = middleware.NewAdaptiveSampler(100)

// Path-based sampling with glob patterns
options.Sampler = middleware.NewPathSamplerBuilder().
    CaseInsensitive().
    Never("/health*").           // Never log health checks
    Sometimes("/api/status", 0.1). // Log 10% of status checks
    Always("/api/*/debug").       // Always log debug endpoints
    Sometimes("*", 0.5).          // Log 50% of everything else
    Build()

// Composite sampling (AND/OR logic)
options.Sampler = middleware.NewCompositeSampler(
    middleware.CompositeAND,
    middleware.NewRateSampler(0.5),
    middleware.NewPathSampler(rules),
)
Custom Field Extractors

Extract dynamic fields from requests:

options.CustomFields = []middleware.FieldExtractor{
    // Pre-defined extractors
    middleware.UserIDFromHeader,
    middleware.SessionIDFromCookie,
    middleware.TraceIDFromContext,
    middleware.TenantIDFromSubdomain,
    middleware.APIVersionFromPath,
    middleware.GeoLocationFromHeaders,
    middleware.DeviceTypeFromUserAgent,
    
    // Custom extractor
    {
        Name: "AccountId",
        Extract: func(r *http.Request) any {
            // Your custom logic
            return r.Header.Get("X-Account-ID")
        },
    },
}
Request Logger Helper

Use the fluent API for request-scoped logging:

func handler(w http.ResponseWriter, r *http.Request) {
    logger := middleware.GetRequestLogger(r).
        WithUser("user-123").
        WithOperation("CreateOrder").
        WithResource("Order", "ord-456")
    
    logger.Information("Processing order creation")
    
    if err := processOrder(); err != nil {
        logger.WithError(err).Error("Order creation failed")
    }
}
Context Helpers

Simplified logging with context:

func handler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    
    // Simple logging
    middleware.InfoContext(ctx, "Processing request")
    middleware.ErrorContext(ctx, "Failed to process: {Error}", err)
    
    // Add fields to context logger
    ctx = middleware.WithFieldsContext(ctx, map[string]any{
        "UserId": "user-123",
        "Action": "UpdateProfile",
    })
    
    middleware.InfoContext(ctx, "User action completed")
}
Metrics Integration

Record HTTP metrics for monitoring:

// Implement the MetricsRecorder interface
type MyMetrics struct {
    // Your metrics implementation
}

func (m *MyMetrics) RecordRequest(method, path string, statusCode int, duration time.Duration) {
    // Record to Prometheus, StatsD, etc.
}

options.MetricsRecorder = &MyMetrics{}

The middleware provides a SimpleMetricsRecorder for testing and basic in-memory metrics.

Performance Optimization with Object Pooling

The middleware includes object pooling to reduce allocations in high-throughput scenarios. Object pools are enabled by default but can be controlled via the EnablePooling variable.

Pooled Objects

The following objects are automatically pooled:

  • MiddlewareError: Structured error objects
  • responseWriter: HTTP response wrapper structs
  • RequestMetric: Metrics recording structs
  • bytes.Buffer: Buffers used for body capture
Pooling Configuration
import "github.com/willibrandon/mtlog/adapters/middleware"

// Enable/disable pooling globally (default: true)
middleware.EnablePooling = true

// Get pool statistics
stats := middleware.GetPoolStats()
fmt.Printf("Error pool hits: %d\n", stats.ErrorPoolHits)

// Reset pool statistics
middleware.ResetPoolStats()
Performance Benefits

Benchmarks show significant allocation reduction with pooling enabled:

BenchmarkMiddleware/WithoutPooling-8    1000000   1523 ns/op   512 B/op   8 allocs/op
BenchmarkMiddleware/WithPooling-8       2000000    758 ns/op   128 B/op   2 allocs/op
Best Practices for High-Throughput
  1. Keep pooling enabled for production workloads

  2. Use batch metrics recording for high request volumes:

    batchRecorder := middleware.NewBatchMetricsRecorder(
        func(metrics []middleware.RequestMetric) {
            // Flush to your metrics backend
        },
        5*time.Second, // Flush interval
        1000,          // Batch size
    )
    defer batchRecorder.Close()
    
    options.MetricsRecorder = batchRecorder
    
  3. Configure appropriate sampling for verbose endpoints:

    sampler := middleware.NewDynamicPathSampler([]middleware.PathSamplingRule{
        {Pattern: "/health", Rate: 0.0},     // Skip health checks
        {Pattern: "/metrics", Rate: 0.0},    // Skip metrics
        {Pattern: "/api/v1/*", Rate: 1.0},   // Log all API calls
        {Pattern: "*", Rate: 0.1},           // Sample 10% of others
    })
    options.Sampler = sampler
    

Context Integration

The middleware injects the logger and request ID into the request context, allowing for nested logging within handlers:

net/http & Chi
func handler(w http.ResponseWriter, r *http.Request) {
    logger := middleware.FromContext(r.Context())
    requestID := middleware.RequestIDFromContext(r.Context())
    
    if logger != nil {
        logger.Information("Processing request", "RequestId", requestID)
    }
}
Gin
func handler(c *gin.Context) {
    logger := middleware.LoggerFromGinContext(c)
    requestID := middleware.RequestIDFromGinContext(c)
    
    if logger != nil {
        logger.Information("Processing request", "RequestId", requestID)
    }
}
Echo
func handler(c echo.Context) error {
    logger := middleware.LoggerFromEchoContext(c)
    requestID := middleware.RequestIDFromEchoContext(c)
    
    if logger != nil {
        logger.Information("Processing request", "RequestId", requestID)
    }
    return nil
}
Fiber
func handler(c *fiber.Ctx) error {
    logger := middleware.LoggerFromFiberContext(c)
    requestID := middleware.RequestIDFromFiberContext(c)
    
    if logger != nil {
        logger.Information("Processing request", "RequestId", requestID)
    }
    return nil
}

Log Output Example

[2025-01-21 10:15:23] INF HTTP GET /api/users responded 200 in 15ms Method=GET Path=/api/users StatusCode=200 duration_ms=15 Size=256 IP=192.168.1.1 RequestId=550e8400-e29b-41d4-a716-446655440000
[2025-01-21 10:15:24] WRN HTTP POST /api/users responded 400 in 5ms Method=POST Path=/api/users StatusCode=400 duration_ms=5 Size=45 Error="invalid email format"
[2025-01-21 10:15:25] ERR HTTP GET /error responded 500 in 2ms Method=GET Path=/error StatusCode=500 duration_ms=2 Size=21 Error="database connection failed"

Running Examples

The package includes complete examples for each supported framework:

# net/http example
go run examples/middleware/nethttp/main.go

# Gin example
go run examples/middleware/gin/main.go

# Echo example
go run examples/middleware/echo/main.go

# Fiber example
go run examples/middleware/fiber/main.go

# Chi example
go run examples/middleware/chi/main.go

Each example runs on port 8080 and includes:

  • / - Home endpoint
  • /api/users - List users (GET)
  • /api/users - Create user (POST)
  • /api/users/{id} - Get/Update/Delete user
  • /error - Simulated error endpoint
  • /health - Health check (skipped by middleware)

Testing

Run the test suite:

go test -v ./adapters/middleware/...

License

MIT License - See the main mtlog repository for details.

Documentation

Overview

Package middleware provides HTTP middleware for automatic request/response logging with mtlog. It supports standard net/http and popular web frameworks including Gin, Echo, Fiber, and Chi.

Index

Constants

View Source
const (
	// TraceIDContextKey is the context key for trace ID
	TraceIDContextKey correlationKey = "trace-id"

	// SpanIDContextKey is the context key for span ID
	SpanIDContextKey correlationKey = "span-id"

	// ParentSpanIDContextKey is the context key for parent span ID
	ParentSpanIDContextKey correlationKey = "parent-span-id"

	// CorrelationIDContextKey is the context key for correlation ID
	CorrelationIDContextKey correlationKey = "correlation-id"

	// TraceContextKey is the context key for the full TraceContext
	TraceContextKey correlationKey = "trace-context"
)
View Source
const (
	// W3C Trace Context headers
	HeaderTraceParent = "Traceparent"
	HeaderTraceState  = "Tracestate"

	// X-Ray headers
	HeaderXRayTraceID = "X-Amzn-Trace-Id"

	// B3 headers (Zipkin)
	HeaderB3TraceID      = "X-B3-TraceId"
	HeaderB3SpanID       = "X-B3-SpanId"
	HeaderB3ParentSpanID = "X-B3-ParentSpanId"
	HeaderB3Sampled      = "X-B3-Sampled"
	HeaderB3             = "B3"

	// Custom headers
	HeaderTraceID       = "X-Trace-ID"
	HeaderSpanID        = "X-Span-ID"
	HeaderParentSpanID  = "X-Parent-Span-ID"
	HeaderCorrelationID = "X-Correlation-ID"
	HeaderRequestID     = "X-Request-ID"
)

Common trace headers

View Source
const (
	// LoggerContextKey is used to store the logger in request context
	LoggerContextKey contextKey = "mtlog.logger"
	// RequestIDContextKey is used to store the request ID in context
	RequestIDContextKey contextKey = "mtlog.request_id"
)

Variables

View Source
var (
	// UserIDFromHeader extracts user ID from X-User-ID header
	UserIDFromHeader = FieldExtractor{
		Name: "UserId",
		Extract: func(r *http.Request) any {
			if userID := r.Header.Get("X-User-ID"); userID != "" {
				return userID
			}
			return nil
		},
	}

	// UserIDFromAuthHeader extracts user ID from Authorization header (Bearer token)
	// This is a simple example - in production you'd parse the JWT
	UserIDFromAuthHeader = FieldExtractor{
		Name: "UserId",
		Extract: func(r *http.Request) any {
			auth := r.Header.Get("Authorization")
			if strings.HasPrefix(auth, "Bearer ") {

				return "user-from-token"
			}
			return nil
		},
	}

	// SessionIDFromCookie extracts session ID from session cookie
	SessionIDFromCookie = FieldExtractor{
		Name: "SessionId",
		Extract: func(r *http.Request) any {
			if cookie, err := r.Cookie("session_id"); err == nil {
				return cookie.Value
			}
			return nil
		},
	}

	// TraceIDFromContext extracts trace ID from context (for distributed tracing)
	TraceIDFromContext = FieldExtractor{
		Name: "TraceId",
		Extract: func(r *http.Request) any {
			if traceID := r.Context().Value("trace-id"); traceID != nil {
				return traceID
			}

			if traceID := r.Header.Get("X-Trace-ID"); traceID != "" {
				return traceID
			}
			if traceID := r.Header.Get("X-B3-TraceId"); traceID != "" {
				return traceID
			}
			return nil
		},
	}

	// SpanIDFromContext extracts span ID from context
	SpanIDFromContext = FieldExtractor{
		Name: "SpanId",
		Extract: func(r *http.Request) any {
			if spanID := r.Context().Value("span-id"); spanID != nil {
				return spanID
			}
			if spanID := r.Header.Get("X-B3-SpanId"); spanID != "" {
				return spanID
			}
			return nil
		},
	}

	// TenantIDFromHeader extracts tenant ID for multi-tenant applications
	TenantIDFromHeader = FieldExtractor{
		Name: "TenantId",
		Extract: func(r *http.Request) any {
			if tenantID := r.Header.Get("X-Tenant-ID"); tenantID != "" {
				return tenantID
			}
			return nil
		},
	}

	// TenantIDFromSubdomain extracts tenant ID from subdomain
	TenantIDFromSubdomain = FieldExtractor{
		Name: "TenantId",
		Extract: func(r *http.Request) any {
			host := r.Host
			if idx := strings.Index(host, "."); idx > 0 {
				subdomain := host[:idx]

				if subdomain != "www" && subdomain != "api" {
					return subdomain
				}
			}
			return nil
		},
	}

	// APIVersionFromHeader extracts API version from header
	APIVersionFromHeader = FieldExtractor{
		Name: "ApiVersion",
		Extract: func(r *http.Request) any {
			if version := r.Header.Get("X-API-Version"); version != "" {
				return version
			}

			if accept := r.Header.Get("Accept"); strings.Contains(accept, "version=") {
				parts := strings.Split(accept, "version=")
				if len(parts) > 1 {
					return strings.Split(parts[1], ";")[0]
				}
			}
			return nil
		},
	}

	// APIVersionFromPath extracts API version from URL path (e.g., /v1/users, /v2.1/items)
	APIVersionFromPath = FieldExtractor{
		Name: "ApiVersion",
		Extract: func(r *http.Request) any {
			path := r.URL.Path
			if strings.HasPrefix(path, "/v") {
				parts := strings.Split(path[1:], "/")
				if len(parts) > 0 && strings.HasPrefix(parts[0], "v") {
					version := parts[0]

					if len(version) > 1 {
						versionNum := version[1:]
						isValid := true
						hasDigit := false

						for i, ch := range versionNum {
							if ch >= '0' && ch <= '9' {
								hasDigit = true
							} else if ch == '.' {

								if i == 0 || i == len(versionNum)-1 {
									isValid = false
									break
								}

								if i > 0 && versionNum[i-1] == '.' {
									isValid = false
									break
								}
							} else {

								isValid = false
								break
							}
						}

						if isValid && hasDigit {
							return version
						}
					}
				}
			}
			return nil
		},
	}

	// ClientIDFromHeader extracts OAuth client ID
	ClientIDFromHeader = FieldExtractor{
		Name: "ClientId",
		Extract: func(r *http.Request) any {
			if clientID := r.Header.Get("X-Client-ID"); clientID != "" {
				return clientID
			}
			return nil
		},
	}

	// CorrelationIDFromHeader extracts correlation ID for request tracking
	CorrelationIDFromHeader = FieldExtractor{
		Name: "CorrelationId",
		Extract: func(r *http.Request) any {

			for _, header := range []string{"X-Correlation-ID", "X-Request-ID", "X-Trace-ID"} {
				if id := r.Header.Get(header); id != "" {
					return id
				}
			}
			return nil
		},
	}

	// GeoLocationFromHeaders extracts geo information from CDN headers
	GeoLocationFromHeaders = FieldExtractor{
		Name: "GeoLocation",
		Extract: func(r *http.Request) any {
			location := make(map[string]string)

			if country := r.Header.Get("CF-IPCountry"); country != "" {
				location["Country"] = country
			}

			if country := r.Header.Get("CloudFront-Viewer-Country"); country != "" {
				location["Country"] = country
			}
			if region := r.Header.Get("CloudFront-Viewer-Country-Region"); region != "" {
				location["Region"] = region
			}

			if country := r.Header.Get("X-Country-Code"); country != "" {
				location["Country"] = country
			}

			if len(location) > 0 {
				return location
			}
			return nil
		},
	}

	// DeviceTypeFromUserAgent extracts device type from User-Agent
	DeviceTypeFromUserAgent = FieldExtractor{
		Name: "DeviceType",
		Extract: func(r *http.Request) any {
			ua := strings.ToLower(r.UserAgent())
			switch {
			case strings.Contains(ua, "mobile"):
				return "mobile"
			case strings.Contains(ua, "tablet"):
				return "tablet"
			case strings.Contains(ua, "bot"):
				return "bot"
			case strings.Contains(ua, "curl") || strings.Contains(ua, "wget"):
				return "cli"
			default:
				if ua != "" {
					return "desktop"
				}
				return nil
			}
		},
	}
)
View Source
var EnablePooling = true

EnablePooling controls whether object pooling is enabled

View Source
var SensitiveFieldNames = []string{
	"password", "passwd", "pwd", "secret", "token", "apikey", "api_key",
	"access_token", "refresh_token", "private_key", "credit_card",
	"card_number", "cvv", "ssn", "social_security", "tax_id",
}

SensitiveFieldNames are common field names that contain sensitive data

Functions

func Chi

func Chi(logger core.Logger, opts ...*Options) func(http.Handler) http.Handler

Chi creates a Chi middleware for request logging Chi uses standard net/http middleware, so we can reuse our core implementation

func DebugContext

func DebugContext(ctx context.Context, template string, args ...any)

DebugContext logs a debug message using the logger from context

func DefaultBodySanitizer

func DefaultBodySanitizer(contentType string, body []byte) []byte

DefaultBodySanitizer redacts sensitive fields in JSON payloads

func DefaultErrorHandler

func DefaultErrorHandler(err *MiddlewareError) (statusCode int, response interface{})

DefaultErrorHandler provides a default error handling implementation

func DevelopmentErrorHandler

func DevelopmentErrorHandler(err *MiddlewareError) (statusCode int, response interface{})

DevelopmentErrorHandler provides detailed error information for development

func Echo

func Echo(logger core.Logger, opts ...*Options) echo.MiddlewareFunc

Echo creates an Echo middleware for request logging

func ErrorContext

func ErrorContext(ctx context.Context, template string, args ...any)

ErrorContext logs an error message using the logger from context

func FatalContext

func FatalContext(ctx context.Context, template string, args ...any)

FatalContext logs a fatal message using the logger from context

func Fiber

func Fiber(logger core.Logger, opts ...*Options) fiber.Handler

Fiber creates a Fiber middleware for request logging

func FromContext

func FromContext(ctx context.Context) core.Logger

FromContext retrieves the logger from the request context

func Gin

func Gin(logger core.Logger, opts ...*Options) gin.HandlerFunc

Gin creates a Gin middleware for request logging

func InfoContext

func InfoContext(ctx context.Context, template string, args ...any)

InfoContext logs an information message using the logger from context

func InformationContext

func InformationContext(ctx context.Context, template string, args ...any)

InformationContext is an alias for InfoContext

func LivenessHandler

func LivenessHandler() http.HandlerFunc

LivenessHandler returns a simple liveness check handler

func LoggerFromEchoContext

func LoggerFromEchoContext(c echo.Context) core.Logger

LoggerFromEchoContext retrieves the logger from Echo context

func LoggerFromFiberContext

func LoggerFromFiberContext(c *fiber.Ctx) core.Logger

LoggerFromFiberContext retrieves the logger from Fiber context

func LoggerFromGinContext

func LoggerFromGinContext(c *gin.Context) core.Logger

LoggerFromGinContext retrieves the logger from Gin context

func MetricsMiddleware

func MetricsMiddleware(recorder MetricsRecorder) func(http.Handler) http.Handler

MetricsMiddleware wraps a handler to record metrics

func Middleware

func Middleware(opts *Options) func(http.Handler) http.Handler

Middleware creates a standard net/http middleware with the given options

func NewTracingClient

func NewTracingClient(format TraceHeaderFormat) *http.Client

NewTracingClient creates an HTTP client that propagates trace context

func NoOpBodySanitizer

func NoOpBodySanitizer(contentType string, body []byte) []byte

NoOpBodySanitizer returns the body unchanged

func PropagateTraceContext

func PropagateTraceContext(next http.Handler, opts ...CorrelationOptions) http.Handler

PropagateTraceContext creates middleware for trace context propagation

func ReadinessHandler

func ReadinessHandler(checks ...HealthChecker) http.HandlerFunc

ReadinessHandler returns a readiness check handler with custom checks

func RequestIDFromContext

func RequestIDFromContext(ctx context.Context) string

RequestIDFromContext retrieves the request ID from the context

func RequestIDFromEchoContext

func RequestIDFromEchoContext(c echo.Context) string

RequestIDFromEchoContext retrieves the request ID from Echo context

func RequestIDFromFiberContext

func RequestIDFromFiberContext(c *fiber.Ctx) string

RequestIDFromFiberContext retrieves the request ID from Fiber context

func RequestIDFromGinContext

func RequestIDFromGinContext(c *gin.Context) string

RequestIDFromGinContext retrieves the request ID from Gin context

func ResetPoolStats

func ResetPoolStats()

ResetPoolStats resets all pool statistics

func VerboseContext

func VerboseContext(ctx context.Context, template string, args ...any)

VerboseContext logs a verbose message using the logger from context

func WarnContext

func WarnContext(ctx context.Context, template string, args ...any)

WarnContext logs a warning message using the logger from context

func WarningContext

func WarningContext(ctx context.Context, template string, args ...any)

WarningContext is an alias for WarnContext

func WithContext

func WithContext(ctx context.Context, key string, value any) context.Context

WithContext adds structured fields to the logger in context and returns a new context

func WithFieldsContext

func WithFieldsContext(ctx context.Context, fields map[string]any) context.Context

WithFieldsContext adds multiple structured fields to the logger in context

Types

type AdaptiveSampler

type AdaptiveSampler struct {
	// contains filtered or unexported fields
}

AdaptiveSampler adjusts sampling rate based on request volume

func NewAdaptiveSampler

func NewAdaptiveSampler(targetPerSecond float64) *AdaptiveSampler

NewAdaptiveSampler creates a sampler that aims for a target logging rate

func (*AdaptiveSampler) ShouldSample

func (s *AdaptiveSampler) ShouldSample(r *http.Request) bool

type AlwaysSampler

type AlwaysSampler struct{}

AlwaysSampler logs every request

func (*AlwaysSampler) ShouldSample

func (s *AlwaysSampler) ShouldSample(r *http.Request) bool

type BatchMetricsRecorder

type BatchMetricsRecorder struct {
	// contains filtered or unexported fields
}

BatchMetricsRecorder batches metrics for high-throughput scenarios

func NewBatchMetricsRecorder

func NewBatchMetricsRecorder(flush func([]RequestMetric), interval time.Duration, maxBatch int) *BatchMetricsRecorder

NewBatchMetricsRecorder creates a new batch metrics recorder

func (*BatchMetricsRecorder) Close

func (b *BatchMetricsRecorder) Close() error

Close stops the batch recorder and flushes remaining metrics

func (*BatchMetricsRecorder) RecordBodySize

func (b *BatchMetricsRecorder) RecordBodySize(direction string, size int)

RecordBodySize records body size (could be batched separately if needed)

func (*BatchMetricsRecorder) RecordPanic

func (b *BatchMetricsRecorder) RecordPanic(method, path string)

RecordPanic records a panic metric

func (*BatchMetricsRecorder) RecordRequest

func (b *BatchMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)

RecordRequest records a request metric

func (*BatchMetricsRecorder) Stats

func (b *BatchMetricsRecorder) Stats() (batchSize int, lastFlush time.Time)

Stats returns current batch statistics

type BodySanitizer

type BodySanitizer func(contentType string, body []byte) []byte

BodySanitizer defines a function that sanitizes request/response bodies

func RegexBodySanitizer

func RegexBodySanitizer(patterns ...*regexp.Regexp) BodySanitizer

RegexBodySanitizer creates a sanitizer that uses regex patterns

type BodySizeMetric

type BodySizeMetric struct {
	Direction string
	Size      int
	Timestamp time.Time
}

type Check

type Check struct {
	Status  string `json:"status"`
	Message string `json:"message,omitempty"`
	Error   string `json:"error,omitempty"`
	Latency int64  `json:"latency_ms,omitempty"`
}

Check represents a health check result

type CompositeMode

type CompositeMode int
const (
	CompositeAND CompositeMode = iota // All samplers must agree
	CompositeOR                       // Any sampler can approve
)

type CompositeSampler

type CompositeSampler struct {
	// contains filtered or unexported fields
}

CompositeSampler combines multiple samplers with AND/OR logic

func NewCompositeSampler

func NewCompositeSampler(mode CompositeMode, samplers ...Sampler) *CompositeSampler

NewCompositeSampler creates a sampler that combines multiple samplers

func (*CompositeSampler) ShouldSample

func (s *CompositeSampler) ShouldSample(r *http.Request) bool

type CorrelationOptions

type CorrelationOptions struct {
	// GenerateTraceID generates a new trace ID if none exists
	GenerateTraceID bool

	// GenerateSpanID generates a new span ID for each request
	GenerateSpanID bool

	// PropagateDownstream propagates trace context to downstream services
	PropagateDownstream bool

	// HeaderFormat specifies which header format to use
	HeaderFormat TraceHeaderFormat

	// Logger for correlation events
	Logger core.Logger

	// CustomTraceIDGenerator allows custom trace ID generation
	CustomTraceIDGenerator func() string

	// CustomSpanIDGenerator allows custom span ID generation
	CustomSpanIDGenerator func() string

	// ExtractBaggage extracts additional context from headers
	ExtractBaggage bool

	// BaggagePrefix is the header prefix for baggage items
	BaggagePrefix string
}

CorrelationOptions configures correlation middleware

type CounterSampler

type CounterSampler struct {
	// contains filtered or unexported fields
}

CounterSampler logs every Nth request

func NewCounterSampler

func NewCounterSampler(n uint64) *CounterSampler

NewCounterSampler creates a sampler that logs every nth request

func (*CounterSampler) ShouldSample

func (s *CounterSampler) ShouldSample(r *http.Request) bool

type DynamicPathSampler

type DynamicPathSampler struct {
	// contains filtered or unexported fields
}

DynamicPathSampler allows runtime changes to sampling rules

func NewDynamicPathSampler

func NewDynamicPathSampler(rules []PathSamplingRule) *DynamicPathSampler

NewDynamicPathSampler creates a new dynamic path sampler

func (*DynamicPathSampler) AddRule

func (s *DynamicPathSampler) AddRule(rule PathSamplingRule)

AddRule adds a new rule at runtime

func (*DynamicPathSampler) GetRules

func (s *DynamicPathSampler) GetRules() []PathSamplingRule

GetRules returns a copy of the current rules

func (*DynamicPathSampler) RemoveRule

func (s *DynamicPathSampler) RemoveRule(pattern string) bool

RemoveRule removes a rule by pattern

func (*DynamicPathSampler) SetAllowEscapes

func (s *DynamicPathSampler) SetAllowEscapes(allow bool)

SetAllowEscapes updates escape handling

func (*DynamicPathSampler) SetCaseSensitive

func (s *DynamicPathSampler) SetCaseSensitive(sensitive bool)

SetCaseSensitive updates case sensitivity

func (*DynamicPathSampler) SetOnChange

func (s *DynamicPathSampler) SetOnChange(fn func(oldRules, newRules []PathSamplingRule))

SetOnChange sets a callback for rule changes

func (*DynamicPathSampler) ShouldSample

func (s *DynamicPathSampler) ShouldSample(r *http.Request) bool

ShouldSample checks if a request should be sampled

func (*DynamicPathSampler) UpdateRuleRate

func (s *DynamicPathSampler) UpdateRuleRate(pattern string, newRate float64) bool

UpdateRuleRate updates the sampling rate for a specific pattern

func (*DynamicPathSampler) UpdateRules

func (s *DynamicPathSampler) UpdateRules(rules []PathSamplingRule)

UpdateRules updates the sampling rules at runtime

type ErrorHandler

type ErrorHandler func(err *MiddlewareError) (statusCode int, response interface{})

ErrorHandler handles middleware errors

type ErrorType

type ErrorType string

ErrorType represents the type of error that occurred

const (
	// ErrorTypePanic indicates a panic occurred in the handler
	ErrorTypePanic ErrorType = "panic"

	// ErrorTypeBodyCapture indicates an error capturing request/response body
	ErrorTypeBodyCapture ErrorType = "body_capture"

	// ErrorTypeTimeout indicates a request timeout
	ErrorTypeTimeout ErrorType = "timeout"

	// ErrorTypeValidation indicates a validation error
	ErrorTypeValidation ErrorType = "validation"

	// ErrorTypeInternal indicates an internal server error
	ErrorTypeInternal ErrorType = "internal"

	// ErrorTypeExternal indicates an external service error
	ErrorTypeExternal ErrorType = "external"
)

type FieldExtractor

type FieldExtractor struct {
	Name    string
	Extract func(r *http.Request) any
}

FieldExtractor extracts custom fields from requests

func CombineExtractors

func CombineExtractors(extractors ...FieldExtractor) []FieldExtractor

CombineExtractors combines multiple extractors

type HealthCheckHandler

type HealthCheckHandler struct {
	// contains filtered or unexported fields
}

HealthCheckHandler creates a dedicated health check handler

func NewHealthCheckHandler

func NewHealthCheckHandler(logger core.Logger) *HealthCheckHandler

NewHealthCheckHandler creates a new health check handler

func (*HealthCheckHandler) AddCheck

func (h *HealthCheckHandler) AddCheck(name string, checker HealthChecker) *HealthCheckHandler

AddCheck adds a health check

func (*HealthCheckHandler) IncrementErrorCount

func (h *HealthCheckHandler) IncrementErrorCount()

IncrementErrorCount increments the error counter

func (*HealthCheckHandler) IncrementRequestCount

func (h *HealthCheckHandler) IncrementRequestCount()

IncrementRequestCount increments the request counter

func (*HealthCheckHandler) ServeHTTP

func (h *HealthCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles health check requests

func (*HealthCheckHandler) WithEnvironment

func (h *HealthCheckHandler) WithEnvironment(env string) *HealthCheckHandler

WithEnvironment sets the environment name

func (*HealthCheckHandler) WithMetrics

func (h *HealthCheckHandler) WithMetrics(include bool) *HealthCheckHandler

WithMetrics enables/disables metrics in health response

func (*HealthCheckHandler) WithVersion

func (h *HealthCheckHandler) WithVersion(version string) *HealthCheckHandler

WithVersion sets the application version

type HealthChecker

type HealthChecker func() Check

HealthChecker performs health checks

func DatabaseHealthChecker

func DatabaseHealthChecker(name string, pingFunc func() error) HealthChecker

DatabaseHealthChecker creates a health checker for database connections

func DiskSpaceHealthChecker

func DiskSpaceHealthChecker(minFreeGB float64) HealthChecker

DiskSpaceHealthChecker creates a health checker for disk space

func HTTPHealthChecker

func HTTPHealthChecker(name, url string, timeout time.Duration) HealthChecker

HTTPHealthChecker creates a health checker for HTTP endpoints

type HealthMetrics

type HealthMetrics struct {
	RequestsTotal     int64   `json:"requests_total"`
	RequestsPerSecond float64 `json:"requests_per_second"`
	ErrorRate         float64 `json:"error_rate"`
	MemoryMB          uint64  `json:"memory_mb"`
	GoroutineCount    int     `json:"goroutine_count"`
}

HealthMetrics contains runtime metrics

type HealthStatus

type HealthStatus struct {
	Status      string           `json:"status"`
	Timestamp   time.Time        `json:"timestamp"`
	Uptime      string           `json:"uptime"`
	Checks      map[string]Check `json:"checks,omitempty"`
	Version     string           `json:"version,omitempty"`
	Environment string           `json:"environment,omitempty"`
	Metrics     *HealthMetrics   `json:"metrics,omitempty"`
}

HealthStatus represents the health status of the application

type MetricsRecorder

type MetricsRecorder interface {
	// RecordRequest records metrics for a completed HTTP request
	RecordRequest(method, path string, statusCode int, duration time.Duration)

	// RecordPanic records a panic occurrence
	RecordPanic(method, path string)

	// RecordBodySize records request/response body sizes
	RecordBodySize(direction string, size int)
}

MetricsRecorder records HTTP metrics for observability

type MiddlewareError

type MiddlewareError struct {
	Type       ErrorType   `json:"type"`
	Message    string      `json:"message"`
	Cause      error       `json:"-"`
	StatusCode int         `json:"status_code,omitempty"`
	RequestID  string      `json:"request_id,omitempty"`
	Path       string      `json:"path,omitempty"`
	Method     string      `json:"method,omitempty"`
	StackTrace string      `json:"stack_trace,omitempty"`
	Details    interface{} `json:"details,omitempty"`
}

MiddlewareError represents a structured error in the middleware

func NewBodyCaptureError

func NewBodyCaptureError(err error, direction string) *MiddlewareError

NewBodyCaptureError creates a new body capture error

func NewInternalError

func NewInternalError(message string, cause error) *MiddlewareError

NewInternalError creates a new internal error

func NewPanicError

func NewPanicError(panicValue interface{}, method, path, requestID string) *MiddlewareError

NewPanicError creates a new panic error

func NewTimeoutError

func NewTimeoutError(path string, duration string) *MiddlewareError

NewTimeoutError creates a new timeout error

func NewValidationError

func NewValidationError(message string, details interface{}) *MiddlewareError

NewValidationError creates a new validation error

func (*MiddlewareError) Error

func (e *MiddlewareError) Error() string

Error implements the error interface

func (*MiddlewareError) Reset

func (e *MiddlewareError) Reset()

Reset clears all fields of the MiddlewareError for reuse

func (*MiddlewareError) Unwrap

func (e *MiddlewareError) Unwrap() error

Unwrap returns the underlying error

func (*MiddlewareError) WithDetails

func (e *MiddlewareError) WithDetails(details interface{}) *MiddlewareError

WithDetails adds additional details to the error

func (*MiddlewareError) WithRequestInfo

func (e *MiddlewareError) WithRequestInfo(method, path, requestID string) *MiddlewareError

WithRequestInfo adds request information to the error

func (*MiddlewareError) WithStackTrace

func (e *MiddlewareError) WithStackTrace() *MiddlewareError

WithStackTrace adds a stack trace to the error

type NeverSampler

type NeverSampler struct{}

NeverSampler never logs requests (useful for testing)

func (*NeverSampler) ShouldSample

func (s *NeverSampler) ShouldSample(r *http.Request) bool

type NoOpMetricsRecorder

type NoOpMetricsRecorder struct{}

NoOpMetricsRecorder is a metrics recorder that does nothing

func (*NoOpMetricsRecorder) RecordBodySize

func (n *NoOpMetricsRecorder) RecordBodySize(direction string, size int)

func (*NoOpMetricsRecorder) RecordPanic

func (n *NoOpMetricsRecorder) RecordPanic(method, path string)

func (*NoOpMetricsRecorder) RecordRequest

func (n *NoOpMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)

type Options

type Options struct {
	// Logger is the mtlog logger to use
	Logger core.Logger

	// RequestFields specifies which request fields to log
	RequestFields []string

	// LatencyField specifies the field name for request duration
	LatencyField string

	// LatencyUnit specifies the unit for latency (ms, us, ns)
	LatencyUnit string

	// RequestIDHeader specifies the header to check for existing request ID
	RequestIDHeader string

	// GenerateRequestID enables automatic request ID generation
	GenerateRequestID bool

	// SkipPaths specifies paths to skip logging (e.g., health checks)
	SkipPaths []string

	// LogRequestBody enables request body logging
	LogRequestBody bool

	// LogResponseBody enables response body logging
	LogResponseBody bool

	// MaxBodySize limits body logging size (in bytes)
	MaxBodySize int

	// CustomLevelFunc allows custom log level based on status code
	CustomLevelFunc func(statusCode int) core.LogEventLevel

	// BodySanitizer sanitizes request/response bodies before logging
	BodySanitizer BodySanitizer

	// CustomFields are additional fields to extract from requests
	CustomFields []FieldExtractor

	// Sampler determines which requests to log
	Sampler Sampler

	// PanicHandler handles panics in the request handler
	PanicHandler func(w http.ResponseWriter, r *http.Request, err any)

	// TimeoutHandler is called when a request is close to timing out
	TimeoutHandler func(r *http.Request, remaining time.Duration)

	// MetricsRecorder records HTTP metrics
	MetricsRecorder MetricsRecorder

	// BeforeRequest is called before processing the request
	BeforeRequest func(r *http.Request, logger core.Logger)

	// AfterRequest is called after processing the request
	AfterRequest func(r *http.Request, statusCode int, duration time.Duration, logger core.Logger)

	// ErrorHandler handles structured errors
	ErrorHandler ErrorHandler
}

Options configures the middleware behavior

func DefaultOptions

func DefaultOptions(logger core.Logger) *Options

DefaultOptions returns middleware options with sensible defaults

func (*Options) Validate

func (opts *Options) Validate() error

Validate checks that the options are valid

type PanicMetric

type PanicMetric struct {
	Method    string
	Path      string
	Timestamp time.Time
}

type PathSampler

type PathSampler struct {
	// contains filtered or unexported fields
}

PathSampler samples based on path patterns

func NewExplicitPathSampler

func NewExplicitPathSampler(rules []PathSamplingRule) *PathSampler

NewExplicitPathSampler creates a sampler that only logs paths matching explicit rules

func NewPathSampler

func NewPathSampler(rules []PathSamplingRule) *PathSampler

NewPathSampler creates a sampler with path-specific rules (defaults to allowing non-matching paths)

func (*PathSampler) ShouldSample

func (s *PathSampler) ShouldSample(r *http.Request) bool

type PathSamplerBuilder

type PathSamplerBuilder struct {
	// contains filtered or unexported fields
}

PathSamplerBuilder for fluent configuration

func NewPathSamplerBuilder

func NewPathSamplerBuilder() *PathSamplerBuilder

NewPathSamplerBuilder creates a new builder for PathSampler

func (*PathSamplerBuilder) Always

func (b *PathSamplerBuilder) Always(pattern string) *PathSamplerBuilder

Always logs all requests matching the pattern

func (*PathSamplerBuilder) Build

func (b *PathSamplerBuilder) Build() *PathSampler

Build creates the configured PathSampler

func (*PathSamplerBuilder) CaseInsensitive

func (b *PathSamplerBuilder) CaseInsensitive() *PathSamplerBuilder

CaseInsensitive enables case-insensitive pattern matching

func (*PathSamplerBuilder) DefaultAllow

func (b *PathSamplerBuilder) DefaultAllow() *PathSamplerBuilder

DefaultAllow configures the sampler to log all requests that don't match any rules (default)

func (*PathSamplerBuilder) DefaultDeny

func (b *PathSamplerBuilder) DefaultDeny() *PathSamplerBuilder

DefaultDeny configures the sampler to only log requests that match explicit rules

func (*PathSamplerBuilder) Never

func (b *PathSamplerBuilder) Never(pattern string) *PathSamplerBuilder

Never logs requests matching the pattern

func (*PathSamplerBuilder) Sometimes

func (b *PathSamplerBuilder) Sometimes(pattern string, rate float64) *PathSamplerBuilder

Sometimes logs a percentage of requests matching the pattern

func (*PathSamplerBuilder) WithEscapes

func (b *PathSamplerBuilder) WithEscapes() *PathSamplerBuilder

WithEscapes enables escaped special characters in patterns

func (*PathSamplerBuilder) WithSegments

func (b *PathSamplerBuilder) WithSegments(pattern string, rate float64) *PathSamplerBuilder

WithSegments ensures * doesn't match across path segments

type PathSamplingRule

type PathSamplingRule struct {
	Pattern       string  // Glob pattern for path matching
	Rate          float64 // Sampling rate for matching paths
	MatchSegments bool    // If true, * won't match across / boundaries
}

PathSamplingRule defines sampling behavior for specific paths

type PoolStats

type PoolStats struct {
	ErrorPoolHits    uint64
	ErrorPoolMisses  uint64
	WriterPoolHits   uint64
	WriterPoolMisses uint64
	MetricPoolHits   uint64
	MetricPoolMisses uint64
	BufferPoolHits   uint64
	BufferPoolMisses uint64
}

PoolStats provides statistics about pool usage

func GetPoolStats

func GetPoolStats() PoolStats

GetPoolStats returns current pool usage statistics

type PrometheusMetricsRecorder

type PrometheusMetricsRecorder struct {
}

PrometheusMetricsRecorder records metrics for Prometheus This is a stub that users can implement with actual Prometheus client

func (*PrometheusMetricsRecorder) RecordBodySize

func (p *PrometheusMetricsRecorder) RecordBodySize(direction string, size int)

func (*PrometheusMetricsRecorder) RecordPanic

func (p *PrometheusMetricsRecorder) RecordPanic(method, path string)

func (*PrometheusMetricsRecorder) RecordRequest

func (p *PrometheusMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)

type RateSampler

type RateSampler struct {
	// contains filtered or unexported fields
}

RateSampler logs a percentage of requests

func NewRateSampler

func NewRateSampler(rate float64) *RateSampler

NewRateSampler creates a sampler that logs a percentage of requests rate should be between 0.0 and 1.0 (e.g., 0.1 for 10%) The random number generator uses a cryptographically secure seed for unpredictability.

func (*RateSampler) ShouldSample

func (s *RateSampler) ShouldSample(r *http.Request) bool

type RequestLogger

type RequestLogger struct {
	core.Logger
	// contains filtered or unexported fields
}

RequestLogger provides a fluent API for request-scoped logging

func GetRequestLogger

func GetRequestLogger(r *http.Request) *RequestLogger

GetRequestLogger retrieves or creates a logger for the request

func (*RequestLogger) Request

func (rl *RequestLogger) Request() *http.Request

Request returns the underlying HTTP request

func (*RequestLogger) WithError

func (rl *RequestLogger) WithError(err error) *RequestLogger

WithError adds error details to the logger

func (*RequestLogger) WithOperation

func (rl *RequestLogger) WithOperation(operation string) *RequestLogger

WithOperation adds operation name to the logger

func (*RequestLogger) WithResource

func (rl *RequestLogger) WithResource(resourceType, resourceID string) *RequestLogger

WithResource adds resource type/name to the logger

func (*RequestLogger) WithSession

func (rl *RequestLogger) WithSession(sessionID string) *RequestLogger

WithSession adds session ID to the logger

func (*RequestLogger) WithTenant

func (rl *RequestLogger) WithTenant(tenantID string) *RequestLogger

WithTenant adds tenant ID to the logger (for multi-tenant apps)

func (*RequestLogger) WithUser

func (rl *RequestLogger) WithUser(userID string) *RequestLogger

WithUser adds user ID to the logger

type RequestMetric

type RequestMetric struct {
	Method     string
	Path       string
	StatusCode int
	Duration   time.Duration
	Timestamp  time.Time
}

func (*RequestMetric) Reset

func (m *RequestMetric) Reset()

Reset clears all fields of the RequestMetric for reuse

type Sampler

type Sampler interface {
	// ShouldSample returns true if the request should be logged
	ShouldSample(r *http.Request) bool
}

Sampler determines whether a request should be logged. Implementations MUST be thread-safe as ShouldSample may be called concurrently from multiple goroutines.

type SimpleMetricsRecorder

type SimpleMetricsRecorder struct {
	// contains filtered or unexported fields
}

SimpleMetricsRecorder provides basic in-memory metrics (useful for testing)

func NewSimpleMetricsRecorder

func NewSimpleMetricsRecorder(maxRequests int) *SimpleMetricsRecorder

NewSimpleMetricsRecorder creates a simple in-memory metrics recorder

func (*SimpleMetricsRecorder) GetMetrics

GetMetrics returns a copy of the collected metrics

func (*SimpleMetricsRecorder) RecordBodySize

func (s *SimpleMetricsRecorder) RecordBodySize(direction string, size int)

func (*SimpleMetricsRecorder) RecordPanic

func (s *SimpleMetricsRecorder) RecordPanic(method, path string)

func (*SimpleMetricsRecorder) RecordRequest

func (s *SimpleMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)

type TraceContext

type TraceContext struct {
	TraceID       string            `json:"trace_id"`
	SpanID        string            `json:"span_id"`
	ParentSpanID  string            `json:"parent_span_id,omitempty"`
	CorrelationID string            `json:"correlation_id,omitempty"`
	Sampled       bool              `json:"sampled"`
	Baggage       map[string]string `json:"baggage,omitempty"`
}

TraceContext holds distributed tracing information

func GetTraceContext

func GetTraceContext(ctx context.Context) *TraceContext

GetTraceContext retrieves the trace context from the request context

type TraceHeaderFormat

type TraceHeaderFormat int

TraceHeaderFormat specifies the trace header format

const (
	// FormatCustom uses simple X-Trace-ID headers
	FormatCustom TraceHeaderFormat = iota

	// FormatW3C uses W3C Trace Context format
	FormatW3C

	// FormatB3 uses Zipkin B3 format
	FormatB3

	// FormatB3Single uses Zipkin B3 single header format
	FormatB3Single

	// FormatXRay uses AWS X-Ray format
	FormatXRay
)

type TraceRoundTripper

type TraceRoundTripper struct {
	Transport http.RoundTripper
	Format    TraceHeaderFormat
}

TraceRoundTripper adds trace context to outgoing HTTP requests

func (*TraceRoundTripper) RoundTrip

func (t *TraceRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper

Directories

Path Synopsis
examples
advanced command
chi command
echo command
fiber command
gin command
nethttp command
ultimate command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL