Files
nhost/services/storage/middleware/logger.go

80 lines
1.8 KiB
Go

package middleware
import (
"context"
"log/slog"
"time"
"github.com/gin-gonic/gin"
)
type loggerCtxKey struct{}
// Stores the logger in the context.
func LoggerToContext(ctx context.Context, logger *slog.Logger) context.Context {
return context.WithValue(ctx, loggerCtxKey{}, logger)
}
// Retrieves the logger from the context. It creates a new one if it can't be found.
func LoggerFromContext(ctx context.Context) *slog.Logger { //nolint:contextcheck
ginCtx, ok := ctx.(*gin.Context)
if ok {
ctx = ginCtx.Request.Context()
}
logger, ok := ctx.Value(loggerCtxKey{}).(*slog.Logger)
if !ok {
return slog.Default()
}
return logger
}
func Logger(logger *slog.Logger) gin.HandlerFunc {
return func(ctx *gin.Context) {
startTime := time.Now()
trace := TraceFromHTTPHeaders(ctx.Request.Header)
clientIP := ctx.ClientIP()
reqMethod := ctx.Request.Method
reqURL := ctx.Request.RequestURI
logger := logger.With(
slog.Group(
"trace",
slog.String("trace_id", trace.TraceID),
slog.String("span_id", trace.SpanID),
slog.String("parent_span_id", trace.ParentSpanID),
),
slog.Group(
"request",
slog.String("client_ip", clientIP),
slog.String("method", reqMethod),
slog.String("url", reqURL),
),
)
ctx.Request = ctx.Request.WithContext(
LoggerToContext(ctx.Request.Context(), logger),
)
ctx.Next()
latencyTime := time.Since(startTime)
statusCode := ctx.Writer.Status()
logger = logger.With(slog.Group(
"response",
slog.Int("status_code", statusCode),
slog.Duration("latency_time", latencyTime),
slog.Any("errors", ctx.Errors.Errors()),
))
TraceToHTTPHeaders(trace, ctx.Writer.Header())
if len(ctx.Errors.Errors()) > 0 {
logger.ErrorContext(ctx, "call completed with errors")
} else {
logger.InfoContext(ctx, "call completed")
}
}
}