Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic route/pattern naming for http.ServeMux #6193

Open
roobre opened this issue Oct 4, 2024 · 2 comments
Open

Automatic route/pattern naming for http.ServeMux #6193

roobre opened this issue Oct 4, 2024 · 2 comments
Labels
area: instrumentation Related to an instrumentation package enhancement New feature or request instrumentation: otelhttp

Comments

@roobre
Copy link

roobre commented Oct 4, 2024

Problem Statement

Go recently added more sophisticated pattern matching to http.ServeMux, including matching methods and path variables. I think this patterns can make good span names: They are descriptive, but also bounded (unlike request paths).

Furthermore, in Go 1.23, http.ServeMux populates http.Request.Pattern, making the pattern that matched a request available for handlers and, more importantly, middlewares. It would be great if otelhttp provided, out of the box, an option to automatically name spans from http.ServeMux patterns.

Proposed Solution

A middleware can be used to name spans using the mux pattern that matched:

// spanNameFromPattern is a simple middleware that sets the name of the span in the request context to the pattern used
// to match this request.
func spanNameFromPattern(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Call handler first, so http.ServeMux can populate r.Pattern
		next.ServeHTTP(w, r)
		// Set span name after the fact. As long as this middleware is used within otelhttp.Handler, the span should
		// still be open and thus renameable.
		trace.SpanFromContext(r.Context()).SetName(r.Pattern)
	})
}

I'm currently using this in this fashion:

handler = otelhttp.NewHandler(
	// Instead of using a span name formatter, this middleware sets the span name using the mux pattern.
	spanNameFromPattern(handler),
	"http",
	// More options...
)

I think this could be a nice addition to the otelhttp package, so users don't need to write spanNameFromPattern on their own. We could fashion it as an option, which transparently adds this middleware:

handler = otelhttp.NewHandler(
	handler,
	"http",
	otelhttp.WithSpanNameFromMuxPattern(), // Tentative name.
)

Or perhaps expose it as a middleware itself:

handler = otelhttp.NewHandler(
	otelhttp.SpanNamer(handler), // VERY tentative name.
	"http",
)

Furthermore, I think some more sophistication could be added to the middleware, for example checking if the pattern already includes a method, and add it if it doesn't.

Alternatives

Have users write this middleware themselves, or set span names manually in application logic.

Additional Context

I'd be happy to make a PR to otelhttp if you think this can be useful to have in there :)

@roobre roobre added area: instrumentation Related to an instrumentation package enhancement New feature or request instrumentation: otelhttp labels Oct 4, 2024
@dmathieu
Copy link
Member

dmathieu commented Oct 4, 2024

We should definitely support mux's routing pattern in otelhttp.
However, as you mention, we can only retrieve that information starting in Go 1.23. So we can't implement it until we drop support for Go 1.22.
We will do that when 1.24 drops. See our compatibility policy.

@roobre
Copy link
Author

roobre commented Oct 5, 2024

Hey @dmathieu, that makes sense. I suppose there is a way to add this functionality and prevent it from breaking 1.30 using a clever assortment of build tag and noop implementations, but that would still require bumping the go version.

Looking forward to see this implemented on 1.24!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: instrumentation Related to an instrumentation package enhancement New feature or request instrumentation: otelhttp
Projects
None yet
Development

No branches or pull requests

2 participants