package middleware import ( "strconv" "time" "ResendIt/internal/logger" "github.com/gin-gonic/gin" "github.com/rs/zerolog" ) // StructuredLogger returns a gin middleware that logs HTTP requests in JSON format func StructuredLogger() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery method := c.Request.Method c.Next() latency := time.Since(start) status := c.Writer.Status() clientIP := c.ClientIP() userAgent := c.Request.UserAgent() requestID := c.GetString("request_id") evt := logger.Log.Info(). Str("type", "http_request"). Str("method", method). Str("path", path). Str("query", query). Int("status", status). Dur("latency_ms", latency). Str("client_ip", clientIP). Str("user_agent", userAgent). Str("request_id", requestID) if len(c.Errors) > 0 { evt = evt.Str("error", c.Errors.ByType(gin.ErrorTypePrivate).String()) } if userID, exists := c.Get("user_id"); exists { evt = evt.Str("user_id", userID.(string)) } if username, exists := c.Get("username"); exists { evt = evt.Str("username", username.(string)) } evt.Msg("") } } // RequestIDMiddleware adds a unique request ID to each request func RequestIDMiddleware() gin.HandlerFunc { return func(c *gin.Context) { requestID := c.GetHeader("X-Request-ID") if requestID == "" { requestID = generateRequestID() } c.Set("request_id", requestID) c.Header("X-Request-ID", requestID) c.Next() } } func generateRequestID() string { // Simple request ID generation - could use uuid package for more entropy return strconv.FormatInt(time.Now().UnixNano(), 36) } // StructuredLog returns a child logger with HTTP context for use in handlers func StructuredLog(c *gin.Context) zerolog.Logger { log := logger.Log.With(). Str("type", "app_log"). Str("request_id", c.GetString("request_id")) if userID, exists := c.Get("user_id"); exists { log = log.Str("user_id", userID.(string)) } if username, exists := c.Get("username"); exists { log = log.Str("username", username.(string)) } return log.Logger() }