refactors OpenTelemetry HTTP instrumentation by centralizing handler wrapping, adding span name formatting, and filtering health and metrics paths.

This commit is contained in:
2025-08-27 10:04:05 -04:00
parent ede5bc92f7
commit 00cb0d0421

View File

@@ -39,19 +39,12 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
mux = &http.ServeMux{} mux = &http.ServeMux{}
) )
// NOTE: Wraps handle func with otelhttp handler and
// inserts route tag
otelHandleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) {
handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc))
mux.Handle(pattern, handler) // Associate pattern with handler
}
healthChecks := handleHealthCheckFunc(opts.Ctx, opts.HealthChecks...) healthChecks := handleHealthCheckFunc(opts.Ctx, opts.HealthChecks...)
otelHandleFunc("/health", healthChecks) mux.HandleFunc("/health", healthChecks)
otelHandleFunc("/", healthChecks) mux.HandleFunc("/", healthChecks)
for _, f := range opts.Funcs { for _, f := range opts.Funcs {
otelHandleFunc(f.Path, f.HandlerFunc) mux.HandleFunc(f.Path, f.HandlerFunc)
} }
// Prometheus metrics endpoint // Prometheus metrics endpoint
@@ -74,12 +67,12 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
if h.StripPrefix { if h.StripPrefix {
h.Handler = http.StripPrefix(h.Prefix[:len(h.Prefix)-1], h.Handler) h.Handler = http.StripPrefix(h.Prefix[:len(h.Prefix)-1], h.Handler)
} }
mux.Handle(h.Prefix, h.Handler) mux.Handle(h.Prefix, otelhttp.WithRouteTag(h.Prefix, h.Handler))
} }
// Add OTEL, skip health-check spans // Add OTEL instrumentation, filter noise, set span names
// NOTE: Add any other span exclusions here
handler := otelhttp.NewHandler(mux, "/", handler := otelhttp.NewHandler(mux, "/",
// TODO: Make configurable similar to config.http.LogExcludePathRegexps
otelhttp.WithFilter(func(r *http.Request) bool { otelhttp.WithFilter(func(r *http.Request) bool {
switch r.URL.Path { switch r.URL.Path {
case "/health": case "/health":
@@ -89,6 +82,14 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
default: default:
return true return true
} }
}),
otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string {
_, pattern := mux.Handler(r)
if pattern != "" {
return pattern // Use the route pattern as the span name, e.g., "/users/{id}"
}
// Fallback to the default naming convention if no route is found.
return operation + " " + r.URL.Path
})) }))
// Set timeouts from defaults, override // Set timeouts from defaults, override