From 3938c68e048b0d0d88de268e07fc8a8fde25cd8f Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Mon, 3 Nov 2025 10:57:12 +0100 Subject: [PATCH 1/4] otelhttp: deprecate the WithRouteTag option --- instrumentation/net/http/otelhttp/doc.go | 3 +- instrumentation/net/http/otelhttp/handler.go | 3 + .../net/http/otelhttp/handler_example_test.go | 64 +++++++++---------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/instrumentation/net/http/otelhttp/doc.go b/instrumentation/net/http/otelhttp/doc.go index 56b24b982ae..1c9aa3ff425 100644 --- a/instrumentation/net/http/otelhttp/doc.go +++ b/instrumentation/net/http/otelhttp/doc.go @@ -2,6 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 // Package otelhttp provides an http.Handler and functions that are intended -// to be used to add tracing by wrapping existing handlers (with Handler) and -// routes WithRouteTag. +// to be used to add tracing by wrapping existing handlers. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" diff --git a/instrumentation/net/http/otelhttp/handler.go b/instrumentation/net/http/otelhttp/handler.go index fef83b42fe1..f58e79f8439 100644 --- a/instrumentation/net/http/otelhttp/handler.go +++ b/instrumentation/net/http/otelhttp/handler.go @@ -224,6 +224,9 @@ func (h *middleware) metricAttributesFromRequest(r *http.Request) []attribute.Ke // WithRouteTag annotates spans and metrics with the provided route name // with HTTP route attribute. +// +// Deprecated: spans are automatically annotated with the route attribute. +// To annotate metrics, use the `WithMetricAttributesFn` option. func WithRouteTag(route string, h http.Handler) http.Handler { attr := semconv.NewHTTPServer(nil).Route(route) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/instrumentation/net/http/otelhttp/handler_example_test.go b/instrumentation/net/http/otelhttp/handler_example_test.go index f77a57037a4..c10ad789870 100644 --- a/instrumentation/net/http/otelhttp/handler_example_test.go +++ b/instrumentation/net/http/otelhttp/handler_example_test.go @@ -44,43 +44,41 @@ func ExampleNewHandler() { } var mux http.ServeMux - mux.Handle("/hello/", - otelhttp.WithRouteTag("/hello/:name", http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - labeler, _ := otelhttp.LabelerFromContext(ctx) + mux.Handle("/hello/", http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + labeler, _ := otelhttp.LabelerFromContext(ctx) - var name string - // Wrap another function in its own span - if err := func(ctx context.Context) error { - ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("exampleTracer").Start(ctx, "figureOutName") - defer span.End() + var name string + // Wrap another function in its own span + if err := func(ctx context.Context) error { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("exampleTracer").Start(ctx, "figureOutName") + defer span.End() - var err error - name, err = figureOutName(ctx, r.URL.Path[1:]) - return err - }(ctx); err != nil { - log.Println("error figuring out name: ", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - labeler.Add(attribute.Bool("error", true)) - return - } + var err error + name, err = figureOutName(ctx, r.URL.Path[1:]) + return err + }(ctx); err != nil { + log.Println("error figuring out name: ", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + labeler.Add(attribute.Bool("error", true)) + return + } - d, err := io.ReadAll(r.Body) - if err != nil { - log.Println("error reading body: ", err) - w.WriteHeader(http.StatusBadRequest) - labeler.Add(attribute.Bool("error", true)) - return - } + d, err := io.ReadAll(r.Body) + if err != nil { + log.Println("error reading body: ", err) + w.WriteHeader(http.StatusBadRequest) + labeler.Add(attribute.Bool("error", true)) + return + } - n, err := io.WriteString(w, "Hello, "+name+"!\nYou sent me this:\n"+string(d)) - if err != nil { - log.Printf("error writing reply after %d bytes: %s", n, err) - labeler.Add(attribute.Bool("error", true)) - } - }), - ), + n, err := io.WriteString(w, "Hello, "+name+"!\nYou sent me this:\n"+string(d)) + if err != nil { + log.Printf("error writing reply after %d bytes: %s", n, err) + labeler.Add(attribute.Bool("error", true)) + } + }), ) if err := http.ListenAndServe(":7777", From 69732557a0c9afe785e59a786c54b730895cc27f Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Mon, 3 Nov 2025 11:04:49 +0100 Subject: [PATCH 2/4] add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39479c4cc31..531bf6715d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Improve performance by reducing allocations in the gRPC stats handler in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#8035) +### Deprecated + +- `WithRouteTag` in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` is deprecated. + The route is already added automatically for spans. For metrics, the alternative is to use the `WithMetricAttributesFn` option. (#8117) + ### Removed - Drop support for [Go 1.23]. (#7831) From cd79383e1e8dc56c9ded3b1459fbf4eb9f0f0ca0 Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Mon, 3 Nov 2025 11:14:58 +0100 Subject: [PATCH 3/4] remove WithRouteTag from dice example --- examples/dice/instrumented/main.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/examples/dice/instrumented/main.go b/examples/dice/instrumented/main.go index 4a3ade11d0d..a0cfb310612 100644 --- a/examples/dice/instrumented/main.go +++ b/examples/dice/instrumented/main.go @@ -71,17 +71,9 @@ func run() error { func newHTTPHandler() http.Handler { mux := http.NewServeMux() - // handleFunc is a replacement for mux.HandleFunc - // which enriches the handler's HTTP instrumentation with the pattern as the http.route. - handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { - // Configure the "http.route" for the HTTP instrumentation. - handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) - mux.Handle(pattern, handler) - } - // Register handlers. - handleFunc("/rolldice/", rolldice) - handleFunc("/rolldice/{player}", rolldice) + mux.Handle("/rolldice", http.HandlerFunc(rolldice)) + mux.Handle("/rolldice/{player}", http.HandlerFunc(rolldice)) // Add HTTP instrumentation for the whole server. handler := otelhttp.NewHandler(mux, "/") From 4591075ec0c14c767a32fc64d4877d258fe2ce87 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Tue, 4 Nov 2025 09:12:05 +0100 Subject: [PATCH 4/4] Update CHANGELOG.md Co-authored-by: Tyler Yahn --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 531bf6715d5..a96968ceb28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Deprecated - `WithRouteTag` in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` is deprecated. - The route is already added automatically for spans. For metrics, the alternative is to use the `WithMetricAttributesFn` option. (#8117) + The route is already added automatically for spans. + For metrics, the alternative is to use the `WithMetricAttributesFn` option. (#8117) ### Removed