50 lines
1.2 KiB
Go
50 lines
1.2 KiB
Go
package httpapi
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"log/slog"
|
||
|
|
"net/http"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
chimw "github.com/go-chi/chi/v5/middleware"
|
||
|
|
)
|
||
|
|
|
||
|
|
// statusRecorder captures the response status for structured request logs.
|
||
|
|
type statusRecorder struct {
|
||
|
|
http.ResponseWriter
|
||
|
|
status int
|
||
|
|
bytes int
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *statusRecorder) WriteHeader(code int) {
|
||
|
|
r.status = code
|
||
|
|
r.ResponseWriter.WriteHeader(code)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *statusRecorder) Write(b []byte) (int, error) {
|
||
|
|
if r.status == 0 {
|
||
|
|
r.status = http.StatusOK
|
||
|
|
}
|
||
|
|
n, err := r.ResponseWriter.Write(b)
|
||
|
|
r.bytes += n
|
||
|
|
return n, err
|
||
|
|
}
|
||
|
|
|
||
|
|
// RequestLogger emits one structured slog line per request with request_id.
|
||
|
|
// Pair with chi middleware.RequestID (already mounted in Router).
|
||
|
|
func RequestLogger(next http.Handler) http.Handler {
|
||
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
start := time.Now()
|
||
|
|
rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
|
||
|
|
next.ServeHTTP(rec, r)
|
||
|
|
slog.Info("http_request",
|
||
|
|
"request_id", chimw.GetReqID(r.Context()),
|
||
|
|
"method", r.Method,
|
||
|
|
"path", r.URL.Path,
|
||
|
|
"status", rec.status,
|
||
|
|
"bytes", rec.bytes,
|
||
|
|
"duration_ms", time.Since(start).Milliseconds(),
|
||
|
|
"remote_ip", r.RemoteAddr,
|
||
|
|
)
|
||
|
|
})
|
||
|
|
}
|