47 lines
1.1 KiB
Go
47 lines
1.1 KiB
Go
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[:])
|
|
}
|