fix otel http instrumentation span naming (#2)

Reviewed-on: #2
Co-authored-by: Ryan D McGuire <ryand_mcguire@sweetwater.com>
Co-committed-by: Ryan D McGuire <ryand_mcguire@sweetwater.com>
This commit is contained in:
2025-08-27 14:32:16 +00:00
committed by Ryan McGuire
parent ede5bc92f7
commit f5cb3456b1

View File

@@ -10,6 +10,7 @@ import (
"net"
"net/http"
"os"
"regexp"
"strings"
"time"
@@ -25,11 +26,12 @@ import (
)
var (
httpMeter metric.Meter
httpTracer trace.Tracer
defReadTimeout = 10 * time.Second
defWriteTimeout = 10 * time.Second
defIdleTimeout = 15 * time.Second
httpMeter metric.Meter
httpTracer trace.Tracer
httpPatternWithMethodRegexp = regexp.MustCompile(`(\w+) .*`)
defReadTimeout = 10 * time.Second
defWriteTimeout = 10 * time.Second
defIdleTimeout = 15 * time.Second
)
func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
@@ -39,19 +41,12 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
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...)
otelHandleFunc("/health", healthChecks)
otelHandleFunc("/", healthChecks)
mux.HandleFunc("/health", healthChecks)
mux.HandleFunc("/", healthChecks)
for _, f := range opts.Funcs {
otelHandleFunc(f.Path, f.HandlerFunc)
mux.HandleFunc(f.Path, f.HandlerFunc)
}
// Prometheus metrics endpoint
@@ -74,12 +69,12 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
if h.StripPrefix {
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
// NOTE: Add any other span exclusions here
// Add OTEL instrumentation, filter noise, set span names
handler := otelhttp.NewHandler(mux, "/",
// TODO: Make configurable similar to config.http.LogExcludePathRegexps
otelhttp.WithFilter(func(r *http.Request) bool {
switch r.URL.Path {
case "/health":
@@ -89,6 +84,18 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
default:
return true
}
}),
otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string {
endpoint := r.URL.Path
if _, pattern := mux.Handler(r); pattern != "" {
endpoint = pattern
}
if httpPatternWithMethodRegexp.MatchString(endpoint) {
return endpoint
}
return fmt.Sprintf("%s %s", r.Method, endpoint)
}))
// Set timeouts from defaults, override