1package server
 2
 3import (
 4	"log/slog"
 5	"net/http"
 6	"time"
 7)
 8
 9func (s *Server) loggingHandler(next http.Handler) http.Handler {
10	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11		if s.logger == nil {
12			next.ServeHTTP(w, r)
13			return
14		}
15
16		start := time.Now()
17		lrw := &loggingResponseWriter{ResponseWriter: w, statusCode: http.StatusOK}
18		s.logger.Debug("HTTP request",
19			slog.String("method", r.Method),
20			slog.String("path", r.URL.Path),
21			slog.String("remote_addr", r.RemoteAddr),
22			slog.String("user_agent", r.UserAgent()),
23		)
24
25		next.ServeHTTP(lrw, r)
26		duration := time.Since(start)
27
28		s.logger.Debug("HTTP response",
29			slog.String("method", r.Method),
30			slog.String("path", r.URL.Path),
31			slog.Int("status", lrw.statusCode),
32			slog.Duration("duration", duration),
33			slog.String("remote_addr", r.RemoteAddr),
34			slog.String("user_agent", r.UserAgent()),
35		)
36	})
37}
38
39type loggingResponseWriter struct {
40	http.ResponseWriter
41	statusCode int
42}
43
44func (lrw *loggingResponseWriter) WriteHeader(code int) {
45	lrw.statusCode = code
46	lrw.ResponseWriter.WriteHeader(code)
47}
48
49func (lrw *loggingResponseWriter) Unwrap() http.ResponseWriter {
50	return lrw.ResponseWriter
51}