package middleware import ( "log/slog" "net/http" "time" ) // Logging emits structured request logs. func Logging(logger *slog.Logger) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := &responseWriter{ResponseWriter: w, status: http.StatusOK} next.ServeHTTP(ww, r) logger.LogAttrs(r.Context(), slog.LevelInfo, "request", slog.String("method", r.Method), slog.String("path", r.URL.Path), slog.Int("status", ww.status), slog.Int("bytes", ww.bytes), slog.Duration("latency", time.Since(start)), ) }) } } type responseWriter struct { http.ResponseWriter status int bytes int } func (w *responseWriter) WriteHeader(statusCode int) { w.status = statusCode w.ResponseWriter.WriteHeader(statusCode) } func (w *responseWriter) Write(b []byte) (int, error) { n, err := w.ResponseWriter.Write(b) w.bytes += n return n, err }