62 lines
1.4 KiB
Go
62 lines
1.4 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type ctxKey string
|
|
|
|
const requestIDKey ctxKey = "request_id"
|
|
|
|
func RequestID(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requestID := r.Header.Get("X-Request-Id")
|
|
if requestID == "" {
|
|
requestID = uuid.NewString()
|
|
}
|
|
w.Header().Set("X-Request-Id", requestID)
|
|
ctx := context.WithValue(r.Context(), requestIDKey, requestID)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
|
|
func RequestIDFromContext(ctx context.Context) string {
|
|
val := ctx.Value(requestIDKey)
|
|
if val == nil {
|
|
return ""
|
|
}
|
|
id, _ := val.(string)
|
|
return id
|
|
}
|
|
|
|
func Logging(logger *slog.Logger) func(http.Handler) http.Handler {
|
|
return func(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}
|
|
next.ServeHTTP(ww, r)
|
|
logger.Info("request",
|
|
"method", r.Method,
|
|
"path", r.URL.Path,
|
|
"status", ww.status,
|
|
"duration_ms", time.Since(start).Milliseconds(),
|
|
"request_id", RequestIDFromContext(r.Context()),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
status int
|
|
}
|
|
|
|
func (w *responseWriter) WriteHeader(status int) {
|
|
w.status = status
|
|
w.ResponseWriter.WriteHeader(status)
|
|
}
|