42 lines
1.8 KiB
Go
42 lines
1.8 KiB
Go
package tracing
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/go-logr/logr"
|
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
|
"go.opentelemetry.io/otel/propagation"
|
|
)
|
|
|
|
// HTTPMiddleware returns middleware that opens a server span per request
|
|
// (named from the mux route pattern once routing has happened) and hands
|
|
// handlers a request context whose logf.FromContext logger is base enriched
|
|
// with the trace context. Incoming W3C traceparent headers are honored, so
|
|
// clients see their own trace continue into the operator. /healthz is never
|
|
// traced. With tracing disabled the middleware degrades to injecting base
|
|
// unenriched — handlers can rely on logf.FromContext either way.
|
|
func HTTPMiddleware(operation string, base logr.Logger, opts ...Option) func(http.Handler) http.Handler {
|
|
o := newOptions(opts)
|
|
return func(next http.Handler) http.Handler {
|
|
inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
r2 := r.WithContext(ContextWithLogger(r.Context(), base))
|
|
next.ServeHTTP(w, r2)
|
|
// WithContext copies the request, so the mux recorded the matched
|
|
// route on r2; surface it to otelhttp, which renames the span
|
|
// from r.Pattern after the handler returns.
|
|
r.Pattern = r2.Pattern
|
|
})
|
|
otelOpts := []otelhttp.Option{
|
|
otelhttp.WithFilter(func(r *http.Request) bool { return r.URL.Path != "/healthz" }),
|
|
// Explicit propagators: deterministic regardless of whether the
|
|
// global propagator has been installed (tests, disabled tracing).
|
|
otelhttp.WithPropagators(propagation.NewCompositeTextMapPropagator(
|
|
propagation.TraceContext{}, propagation.Baggage{})),
|
|
}
|
|
if o.tp != nil {
|
|
otelOpts = append(otelOpts, otelhttp.WithTracerProvider(o.tp))
|
|
}
|
|
return otelhttp.NewHandler(inner, operation, otelOpts...)
|
|
}
|
|
}
|