Files
descrybe/apps/api/internal/httpapi/observability.go
T

50 lines
1.2 KiB
Go
Raw Normal View History

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,
)
})
}