package server import ( "mal/internal/observability" "time" "github.com/gin-gonic/gin" ) func RequestLogger(metrics *observability.Metrics) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() route := c.FullPath() if route == "" { route = path } duration := time.Since(start) metrics.ObserveHTTPRequest(c.Request.Method, route, c.Writer.Status(), duration) level := observability.LogLevelInfo status := c.Writer.Status() if status >= 500 { level = observability.LogLevelError } else if status >= 400 { level = observability.LogLevelWarn } fields := map[string]any{ "client_ip": c.ClientIP(), "duration_ms": float64(duration.Microseconds()) / 1000, "method": c.Request.Method, "path": path, "request_id": c.Writer.Header().Get(requestIDHeader), "status": status, } privateErrors := c.Errors.ByType(gin.ErrorTypePrivate) var logErr error if len(privateErrors) > 0 { logErr = privateErrors.Last().Err } if route != path { fields["route"] = route } if query != "" { fields["query"] = query } if size := c.Writer.Size(); size >= 0 { fields["bytes"] = size } if errors := privateErrors.String(); errors != "" { fields["errors"] = errors } observability.LogContext( c.Request.Context(), level, "http_request", "http", c.Request.Method+" "+path, fields, logErr, ) } }