Log slow API requests with server spans and client timing
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"g.fc.run/ai/byre/internal/trace"
|
||||
)
|
||||
|
||||
const slowRequest = 200 * time.Millisecond
|
||||
|
||||
type timedWriter struct {
|
||||
http.ResponseWriter
|
||||
start time.Time
|
||||
trace *trace.Trace
|
||||
status int
|
||||
}
|
||||
|
||||
func (w *timedWriter) WriteHeader(status int) {
|
||||
if w.status == 0 {
|
||||
w.status = status
|
||||
w.Header().Set("Server-Timing", w.trace.Header(time.Since(w.start)))
|
||||
}
|
||||
w.ResponseWriter.WriteHeader(status)
|
||||
}
|
||||
|
||||
func (w *timedWriter) Write(b []byte) (int, error) {
|
||||
if w.status == 0 {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (w *timedWriter) Unwrap() http.ResponseWriter {
|
||||
return w.ResponseWriter
|
||||
}
|
||||
|
||||
func timing(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, t := trace.New(r.Context())
|
||||
tw := &timedWriter{ResponseWriter: w, start: time.Now(), trace: t}
|
||||
next.ServeHTTP(tw, r.WithContext(ctx))
|
||||
took := time.Since(tw.start)
|
||||
if took < slowRequest || tw.status == http.StatusSwitchingProtocols || tw.Header().Get("Content-Type") == "text/event-stream" {
|
||||
return
|
||||
}
|
||||
slog.Info("request slow", "method", r.Method, "path", r.URL.Path, "status", tw.status, "took", took, "spans", t.String())
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user