// Package logger provides HTTP middleware and context utilities for logging. package logger import ( "context" "git.dcentral.systems/toolz/goplt/pkg/logger" "github.com/gin-gonic/gin" "github.com/google/uuid" ) const ( // RequestIDHeader is the HTTP header name for request ID. RequestIDHeader = "X-Request-ID" ) // ContextKey is a custom type for context keys to avoid collisions. // It is exported so modules can use it for setting context values. type ContextKey string const ( requestIDKey ContextKey = "request_id" userIDKey ContextKey = "user_id" ) // RequestIDMiddleware creates a Gin middleware that: // 1. Generates a unique request ID for each request (or uses existing one from header) // 2. Adds the request ID to the request context // 3. Adds the request ID to the response headers // 4. Makes the request ID available for logging func RequestIDMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Check if request ID already exists in header requestID := c.GetHeader(RequestIDHeader) // Generate new request ID if not present if requestID == "" { requestID = uuid.New().String() } // Add request ID to context ctx := context.WithValue(c.Request.Context(), requestIDKey, requestID) c.Request = c.Request.WithContext(ctx) // Add request ID to response header c.Header(RequestIDHeader, requestID) // Continue processing c.Next() } } // RequestIDFromContext extracts the request ID from the context. func RequestIDFromContext(ctx context.Context) string { if requestID, ok := ctx.Value(requestIDKey).(string); ok { return requestID } return "" } // SetRequestID sets the request ID in the context. func SetRequestID(ctx context.Context, requestID string) context.Context { return context.WithValue(ctx, requestIDKey, requestID) } // SetUserID sets the user ID in the context. func SetUserID(ctx context.Context, userID string) context.Context { return context.WithValue(ctx, userIDKey, userID) } // UserIDFromContext extracts the user ID from the context. func UserIDFromContext(ctx context.Context) string { if userID, ok := ctx.Value(userIDKey).(string); ok { return userID } return "" } // LoggingMiddleware creates a Gin middleware that logs HTTP requests. // It uses the logger from the context and includes request ID. func LoggingMiddleware(l logger.Logger) gin.HandlerFunc { return func(c *gin.Context) { // Get logger with context log := l.WithContext(c.Request.Context()) // Log request log.Info("HTTP request", logger.String("method", c.Request.Method), logger.String("path", c.Request.URL.Path), logger.String("remote_addr", c.ClientIP()), ) // Process request c.Next() // Log response log.Info("HTTP response", logger.Int("status", c.Writer.Status()), logger.Int("size", c.Writer.Size()), ) } }