internal/middleware_logger/middleware_logger.go (58 lines of code) (raw):

package middleware_logger //nolint:staticcheck import ( "log/slog" "net/http" "os" "time" "gitlab.com/gitlab-org/gitlab-zoekt-indexer/internal/dev_debug" ) func SlogMiddleware(logger *slog.Logger) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // Wrap the ResponseWriter to capture the status and any potential errors ww := &enhancedWriter{ResponseWriter: w, status: http.StatusOK} // Process the request next.ServeHTTP(ww, r) // Log the request details duration := time.Since(start) logFields := []any{ "method", r.Method, "path", r.URL.Path, "host", r.Host, "status", ww.status, "duration_ms", duration.Milliseconds(), } // Include error message if available if ww.errMessage != "" { logFields = append(logFields, "error", ww.errMessage) logger.Error("HTTP request", logFields...) return } logger.Info("HTTP request", logFields...) }) } } func SetUpLogger() *slog.Logger { level := slog.LevelInfo if dev_debug.IsEnabled() { level = slog.LevelDebug } logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: level})) slog.SetDefault(logger) return logger } // enhancedWriter wraps http.ResponseWriter to capture the HTTP status code and any error messages. type enhancedWriter struct { http.ResponseWriter status int errMessage string } func (w *enhancedWriter) WriteHeader(code int) { w.status = code if code >= 400 { // Capture error status codes w.errMessage = http.StatusText(code) } w.ResponseWriter.WriteHeader(code) } // Use Write to capture error messages written directly to the response body func (w *enhancedWriter) Write(b []byte) (int, error) { if w.status >= 400 && w.errMessage == "" { w.errMessage = string(b) // Capture body content as error message } return w.ResponseWriter.Write(b) }