package httpapp import ( "context" "crypto/rand" "encoding/hex" "log" "net/http" "time" ) type ctxKey string const requestIDKey ctxKey = "reqid" func requestID(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { id := r.Header.Get("X-Request-Id") if id == "" { id = newReqID() } w.Header().Set("X-Request-Id", id) ctx := context.WithValue(r.Context(), requestIDKey, id) next.ServeHTTP(w, r.WithContext(ctx)) }) } func logging(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) d := time.Since(start) id, _ := r.Context().Value(requestIDKey).(string) log.Printf("%s %s %s rid=%s dur=%s", r.RemoteAddr, r.Method, r.URL.Path, id, d) }) } func newReqID() string { var b [16]byte if _, err := rand.Read(b[:]); err != nil { // Fallback to timestamp-based ID if crypto/rand fails (extremely rare) log.Printf("rand.Read failed, using fallback: %v", err) return hex.EncodeToString([]byte(time.Now().Format(time.RFC3339Nano))) } return hex.EncodeToString(b[:]) }