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
- Variables
- func Chi(logger core.Logger, opts ...*Options) func(http.Handler) http.Handler
- func DebugContext(ctx context.Context, template string, args ...any)
- func DefaultBodySanitizer(contentType string, body []byte) []byte
- func DefaultErrorHandler(err *MiddlewareError) (statusCode int, response interface{})
- func DevelopmentErrorHandler(err *MiddlewareError) (statusCode int, response interface{})
- func Echo(logger core.Logger, opts ...*Options) echo.MiddlewareFunc
- func ErrorContext(ctx context.Context, template string, args ...any)
- func FatalContext(ctx context.Context, template string, args ...any)
- func Fiber(logger core.Logger, opts ...*Options) fiber.Handler
- func FromContext(ctx context.Context) core.Logger
- func Gin(logger core.Logger, opts ...*Options) gin.HandlerFunc
- func InfoContext(ctx context.Context, template string, args ...any)
- func InformationContext(ctx context.Context, template string, args ...any)
- func LivenessHandler() http.HandlerFunc
- func LoggerFromEchoContext(c echo.Context) core.Logger
- func LoggerFromFiberContext(c *fiber.Ctx) core.Logger
- func LoggerFromGinContext(c *gin.Context) core.Logger
- func MetricsMiddleware(recorder MetricsRecorder) func(http.Handler) http.Handler
- func Middleware(opts *Options) func(http.Handler) http.Handler
- func NewTracingClient(format TraceHeaderFormat) *http.Client
- func NoOpBodySanitizer(contentType string, body []byte) []byte
- func PropagateTraceContext(next http.Handler, opts ...CorrelationOptions) http.Handler
- func ReadinessHandler(checks ...HealthChecker) http.HandlerFunc
- func RequestIDFromContext(ctx context.Context) string
- func RequestIDFromEchoContext(c echo.Context) string
- func RequestIDFromFiberContext(c *fiber.Ctx) string
- func RequestIDFromGinContext(c *gin.Context) string
- func ResetPoolStats()
- func VerboseContext(ctx context.Context, template string, args ...any)
- func WarnContext(ctx context.Context, template string, args ...any)
- func WarningContext(ctx context.Context, template string, args ...any)
- func WithContext(ctx context.Context, key string, value any) context.Context
- func WithFieldsContext(ctx context.Context, fields map[string]any) context.Context
- type AdaptiveSampler
- type AlwaysSampler
- type BatchMetricsRecorder
- func (b *BatchMetricsRecorder) Close() error
- func (b *BatchMetricsRecorder) RecordBodySize(direction string, size int)
- func (b *BatchMetricsRecorder) RecordPanic(method, path string)
- func (b *BatchMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)
- func (b *BatchMetricsRecorder) Stats() (batchSize int, lastFlush time.Time)
- type BodySanitizer
- type BodySizeMetric
- type Check
- type CompositeMode
- type CompositeSampler
- type CorrelationOptions
- type CounterSampler
- type DynamicPathSampler
- func (s *DynamicPathSampler) AddRule(rule PathSamplingRule)
- func (s *DynamicPathSampler) GetRules() []PathSamplingRule
- func (s *DynamicPathSampler) RemoveRule(pattern string) bool
- func (s *DynamicPathSampler) SetAllowEscapes(allow bool)
- func (s *DynamicPathSampler) SetCaseSensitive(sensitive bool)
- func (s *DynamicPathSampler) SetOnChange(fn func(oldRules, newRules []PathSamplingRule))
- func (s *DynamicPathSampler) ShouldSample(r *http.Request) bool
- func (s *DynamicPathSampler) UpdateRuleRate(pattern string, newRate float64) bool
- func (s *DynamicPathSampler) UpdateRules(rules []PathSamplingRule)
- type ErrorHandler
- type ErrorType
- type FieldExtractor
- type HealthCheckHandler
- func (h *HealthCheckHandler) AddCheck(name string, checker HealthChecker) *HealthCheckHandler
- func (h *HealthCheckHandler) IncrementErrorCount()
- func (h *HealthCheckHandler) IncrementRequestCount()
- func (h *HealthCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (h *HealthCheckHandler) WithEnvironment(env string) *HealthCheckHandler
- func (h *HealthCheckHandler) WithMetrics(include bool) *HealthCheckHandler
- func (h *HealthCheckHandler) WithVersion(version string) *HealthCheckHandler
- type HealthChecker
- type HealthMetrics
- type HealthStatus
- type MetricsRecorder
- type MiddlewareError
- func NewBodyCaptureError(err error, direction string) *MiddlewareError
- func NewInternalError(message string, cause error) *MiddlewareError
- func NewPanicError(panicValue interface{}, method, path, requestID string) *MiddlewareError
- func NewTimeoutError(path string, duration string) *MiddlewareError
- func NewValidationError(message string, details interface{}) *MiddlewareError
- func (e *MiddlewareError) Error() string
- func (e *MiddlewareError) Reset()
- func (e *MiddlewareError) Unwrap() error
- func (e *MiddlewareError) WithDetails(details interface{}) *MiddlewareError
- func (e *MiddlewareError) WithRequestInfo(method, path, requestID string) *MiddlewareError
- func (e *MiddlewareError) WithStackTrace() *MiddlewareError
- type NeverSampler
- type NoOpMetricsRecorder
- type Options
- type PanicMetric
- type PathSampler
- type PathSamplerBuilder
- func (b *PathSamplerBuilder) Always(pattern string) *PathSamplerBuilder
- func (b *PathSamplerBuilder) Build() *PathSampler
- func (b *PathSamplerBuilder) CaseInsensitive() *PathSamplerBuilder
- func (b *PathSamplerBuilder) DefaultAllow() *PathSamplerBuilder
- func (b *PathSamplerBuilder) DefaultDeny() *PathSamplerBuilder
- func (b *PathSamplerBuilder) Never(pattern string) *PathSamplerBuilder
- func (b *PathSamplerBuilder) Sometimes(pattern string, rate float64) *PathSamplerBuilder
- func (b *PathSamplerBuilder) WithEscapes() *PathSamplerBuilder
- func (b *PathSamplerBuilder) WithSegments(pattern string, rate float64) *PathSamplerBuilder
- type PathSamplingRule
- type PoolStats
- type PrometheusMetricsRecorder
- type RateSampler
- type RequestLogger
- func (rl *RequestLogger) Request() *http.Request
- func (rl *RequestLogger) WithError(err error) *RequestLogger
- func (rl *RequestLogger) WithOperation(operation string) *RequestLogger
- func (rl *RequestLogger) WithResource(resourceType, resourceID string) *RequestLogger
- func (rl *RequestLogger) WithSession(sessionID string) *RequestLogger
- func (rl *RequestLogger) WithTenant(tenantID string) *RequestLogger
- func (rl *RequestLogger) WithUser(userID string) *RequestLogger
- type RequestMetric
- type Sampler
- type SimpleMetricsRecorder
- func (s *SimpleMetricsRecorder) GetMetrics() ([]RequestMetric, []PanicMetric, []BodySizeMetric)
- func (s *SimpleMetricsRecorder) RecordBodySize(direction string, size int)
- func (s *SimpleMetricsRecorder) RecordPanic(method, path string)
- func (s *SimpleMetricsRecorder) RecordRequest(method, path string, statusCode int, duration time.Duration)
- type TraceContext
- type TraceHeaderFormat
- type TraceRoundTripper
Constants ¶
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" )
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
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 ¶
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 } }, } )
var EnablePooling = true
EnablePooling controls whether object pooling is enabled
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 ¶
Chi creates a Chi middleware for request logging Chi uses standard net/http middleware, so we can reuse our core implementation
func DebugContext ¶
DebugContext logs a debug message using the logger from context
func DefaultBodySanitizer ¶
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 ¶
ErrorContext logs an error message using the logger from context
func FatalContext ¶
FatalContext logs a fatal message using the logger from context
func FromContext ¶
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 ¶
InfoContext logs an information message using the logger from context
func InformationContext ¶
InformationContext is an alias for InfoContext
func LivenessHandler ¶
func LivenessHandler() http.HandlerFunc
LivenessHandler returns a simple liveness check handler
func LoggerFromEchoContext ¶
LoggerFromEchoContext retrieves the logger from Echo context
func LoggerFromFiberContext ¶
LoggerFromFiberContext retrieves the logger from Fiber context
func LoggerFromGinContext ¶
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 ¶
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 ¶
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 ¶
RequestIDFromContext retrieves the request ID from the context
func RequestIDFromEchoContext ¶
RequestIDFromEchoContext retrieves the request ID from Echo context
func RequestIDFromFiberContext ¶
RequestIDFromFiberContext retrieves the request ID from Fiber context
func RequestIDFromGinContext ¶
RequestIDFromGinContext retrieves the request ID from Gin context
func VerboseContext ¶
VerboseContext logs a verbose message using the logger from context
func WarnContext ¶
WarnContext logs a warning message using the logger from context
func WarningContext ¶
WarningContext is an alias for WarnContext
func WithContext ¶
WithContext adds structured fields to the logger in context and returns a new 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
type BodySanitizer ¶
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 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 ¶
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 ¶
DefaultOptions returns middleware options with sensible defaults
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 ¶
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 ¶
func (s *SimpleMetricsRecorder) GetMetrics() ([]RequestMetric, []PanicMetric, []BodySizeMetric)
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