Request ID middleware for net/http services
Go
package main
import (
"context"
"crypto/rand"
"encoding/hex"
"log"
"net/http"
)
type ctxKey string
const RequestIDKey ctxKey = "request-id"
// RequestID reuses an incoming X-Request-ID header or generates a new one.
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 == "" {
buf := make([]byte, 8)
if _, err := rand.Read(buf); err != nil {
http.Error(w, "cannot generate id", http.StatusInternalServerError)
return
}
id = hex.EncodeToString(buf)
}
w.Header().Set("X-Request-ID", id)
next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), RequestIDKey, id)))
})
}
func main() {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("request_id=%v path=%s", r.Context().Value(RequestIDKey), r.URL.Path)
_, _ = w.Write([]byte("ok\n"))
})
http.Handle("/", RequestID(handler))
log.Fatal(http.ListenAndServe(":8080", nil))
}