package middleware import ( "log/slog" "net/http" "time" "git.coopcloud.tech/wiki-cafe/member-console/internal/logging" ) type wrappedWriter struct { http.ResponseWriter statusCode int } func (w *wrappedWriter) WriteHeader(statusCode int) { w.ResponseWriter.WriteHeader(statusCode) w.statusCode = statusCode } // Logging is a middleware function that logs requests with structured logging func Logging() Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // Prepare wrapped writer to capture status code wrapped := &wrappedWriter{ ResponseWriter: w, statusCode: http.StatusOK, } // Get request ID from context requestID := GetRequestID(r.Context()) // Get logger from the application and add request information logger := logging.FromContext(r.Context()) reqLogger := logging.WithValues(logger, slog.String("request_id", requestID), slog.String("method", r.Method), slog.String("path", r.URL.Path), slog.String("remote_ip", r.RemoteAddr), slog.String("user_agent", r.UserAgent()), ) // Store the request-specific logger in context ctx := logging.WithContext(r.Context(), reqLogger) r = r.WithContext(ctx) // Log request start if in debug mode reqLogger.Debug("request started") // Process the request with updated context next.ServeHTTP(wrapped, r) // Calculate duration duration := time.Since(start) // Log request completion with status and duration reqLogger.Info("request completed", slog.Int("status", wrapped.statusCode), slog.Duration("duration", duration), slog.String("duration_human", duration.String()), ) }) } }