diff --git a/internal/logging/gin_logger.go b/internal/logging/gin_logger.go index f09ea879..9bfef8ad 100644 --- a/internal/logging/gin_logger.go +++ b/internal/logging/gin_logger.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "runtime/debug" + "strings" "time" "github.com/gin-gonic/gin" @@ -14,28 +15,42 @@ import ( log "github.com/sirupsen/logrus" ) +// aiAPIPrefixes defines path prefixes for AI API requests that should have request ID tracking. +var aiAPIPrefixes = []string{ + "/v1/chat/completions", + "/v1/completions", + "/v1/messages", + "/v1/responses", + "/v1beta/models/", + "/api/provider/", +} + const skipGinLogKey = "__gin_skip_request_logging__" // GinLogrusLogger returns a Gin middleware handler that logs HTTP requests and responses // using logrus. It captures request details including method, path, status code, latency, -// client IP, and any error messages, formatted with request ID for correlation. +// client IP, and any error messages. Request ID is only added for AI API requests. // -// Output format: [2025-12-23 20:14:10] [info ] [a1b2c3d4] 200 | 23.559s | 144.34.236.116 | POST "/v1/messages?beta=true" +// Output format (AI API): [2025-12-23 20:14:10] [info ] | a1b2c3d4 | 200 | 23.559s | ... +// Output format (others): [2025-12-23 20:14:10] [info ] | -------- | 200 | 23.559s | ... // // Returns: // - gin.HandlerFunc: A middleware handler for request logging func GinLogrusLogger() gin.HandlerFunc { return func(c *gin.Context) { - requestID := GenerateRequestID() - SetGinRequestID(c, requestID) - - ctx := WithRequestID(c.Request.Context(), requestID) - c.Request = c.Request.WithContext(ctx) - start := time.Now() path := c.Request.URL.Path raw := util.MaskSensitiveQuery(c.Request.URL.RawQuery) + // Only generate request ID for AI API paths + var requestID string + if isAIAPIPath(path) { + requestID = GenerateRequestID() + SetGinRequestID(c, requestID) + ctx := WithRequestID(c.Request.Context(), requestID) + c.Request = c.Request.WithContext(ctx) + } + c.Next() if shouldSkipGinRequestLogging(c) { @@ -63,7 +78,13 @@ func GinLogrusLogger() gin.HandlerFunc { logLine = logLine + " | " + errorMessage } - entry := log.WithField("request_id", requestID) + var entry *log.Entry + if requestID != "" { + entry = log.WithField("request_id", requestID) + } else { + entry = log.WithField("request_id", "--------") + } + switch { case statusCode >= http.StatusInternalServerError: entry.Error(logLine) @@ -75,6 +96,16 @@ func GinLogrusLogger() gin.HandlerFunc { } } +// isAIAPIPath checks if the given path is an AI API endpoint that should have request ID tracking. +func isAIAPIPath(path string) bool { + for _, prefix := range aiAPIPrefixes { + if strings.HasPrefix(path, prefix) { + return true + } + } + return false +} + // GinLogrusRecovery returns a Gin middleware handler that recovers from panics and logs // them using logrus. When a panic occurs, it captures the panic value, stack trace, // and request path, then returns a 500 Internal Server Error response to the client.