sp4-verify-1770325799/pkg/middleware/tracing.go
jordan e3a1892ca7
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
ci/woodpecker/manual/woodpecker Pipeline was successful
Initialize project from skeleton template
2026-02-05 21:10:01 +00:00

75 lines
1.9 KiB
Go

package middleware
import (
"net/http"
"strings"
"github.com/google/uuid"
"git.threesix.ai/jordan/sp4-verify-1770325799/pkg/httpcontext"
"git.threesix.ai/jordan/sp4-verify-1770325799/pkg/logging"
)
// Trace ID headers in priority order.
const (
TraceIDHeader = "X-Trace-ID"
CloudTraceHeader = "X-Cloud-Trace-Context"
)
// Tracing returns middleware that extracts or generates trace IDs.
//
// Checks headers in order:
// 1. X-Trace-ID - direct trace ID
// 2. X-Cloud-Trace-Context - GCP format "TRACE_ID/SPAN_ID;o=OPTIONS"
// 3. Generates a new UUID if none found
//
// The trace ID is stored in context via httpcontext.SetTraceID and
// logging.WithTraceID, and set in the X-Trace-ID response header.
//
// Usage:
//
// r.Use(middleware.RequestID())
// r.Use(middleware.Tracing())
// r.Use(middleware.RequestLogger(logger))
func Tracing() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
traceID := extractTraceID(r)
if traceID == "" {
traceID = uuid.New().String()
}
// Store in context
ctx := httpcontext.SetTraceID(r.Context(), traceID)
ctx = logging.WithTraceID(ctx, traceID)
// Set response header
w.Header().Set(TraceIDHeader, traceID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// extractTraceID tries to extract a trace ID from known headers.
func extractTraceID(r *http.Request) string {
// X-Trace-ID takes priority
if traceID := r.Header.Get(TraceIDHeader); traceID != "" {
return traceID
}
// X-Cloud-Trace-Context format: "TRACE_ID/SPAN_ID;o=OPTIONS"
if cloudTrace := r.Header.Get(CloudTraceHeader); cloudTrace != "" {
if idx := strings.IndexByte(cloudTrace, '/'); idx > 0 {
return cloudTrace[:idx]
}
if idx := strings.IndexByte(cloudTrace, ';'); idx > 0 {
return cloudTrace[:idx]
}
return cloudTrace
}
return ""
}