package middleware import ( "net/http" "time" chimiddleware "github.com/go-chi/chi/v5/middleware" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) func Logger(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} // Den Logger in den Kontext hängen, damit log.Ctx(r.Context()) in den // Handlern etwas findet – und damit jede Zeile aus einer Anfrage die // Kennung dieser Anfrage trägt. Ohne das schreibt log.Ctx gar nicht // (zerolog gibt dann einen abgeschalteten Logger zurück), und mit // einem globalen Standard allein ließe sich nicht mehr zuordnen, // welche Meldung zu welchem Aufruf gehört. l := log.Logger.With(). Str("request_id", chimiddleware.GetReqID(r.Context())). Logger() r = r.WithContext(l.WithContext(r.Context())) next.ServeHTTP(ww, r) level := zerolog.InfoLevel if ww.status >= 500 { level = zerolog.ErrorLevel } else if ww.status >= 400 { level = zerolog.WarnLevel } log.WithLevel(level). Str("method", r.Method). Str("path", r.URL.Path). Int("status", ww.status). Dur("duration", time.Since(start)). Str("ip", r.RemoteAddr). Msg("") }) } type responseWriter struct { http.ResponseWriter status int } func (rw *responseWriter) WriteHeader(status int) { rw.status = status rw.ResponseWriter.WriteHeader(status) }