Skip to content

Don't use placeholder values for the controller and action in the http.route example#2717

Closed
lmolkova wants to merge 1 commit intoopen-telemetry:mainfrom
lmolkova:clarify-http-route
Closed

Don't use placeholder values for the controller and action in the http.route example#2717
lmolkova wants to merge 1 commit intoopen-telemetry:mainfrom
lmolkova:clarify-http-route

Conversation

@lmolkova
Copy link
Copy Markdown
Member

@lmolkova lmolkova commented Sep 3, 2025

Fixes #2616

Using {controller}/{action}/... in http.route examples turns out to be confusing - according to #2616 it creates the impression that it should be used verbatim, while the intention is to report the route information available from HTTP server framework which usually contains full-text controller/actions.

The #2616 suggests to fix span name description, but I still struggle to understand what's missing there - it just tells to use HTTP route:

The <span id="target-placeholder">`{target}`</span> SHOULD be one of the following:
- [`http.route`](/docs/registry/attributes/http.md) for HTTP Server spans
- [`url.template`](/docs/registry/attributes/url.md) for HTTP Client spans if enabled and available (![Development](https://img.shields.io/badge/-development-blue))
- Other value MAY be provided through custom hooks at span start time or later.
Instrumentation MUST NOT default to using URI path as a `{target}`.

@lmolkova lmolkova requested review from a team as code owners September 3, 2025 23:13
@lmolkova lmolkova requested review from a team as code owners September 3, 2025 23:13
@lmolkova lmolkova changed the title Don't use placeholders in http.route example Don't use placeholder values for the controller and action in the http.route example Sep 3, 2025
@RassK
Copy link
Copy Markdown

RassK commented Sep 4, 2025

Suggestion for http.route standardization example my-controller/my-action/{id?} to remove all route transformers and constraints also. (? is a constraint, like :string or :int)

? for sure causes another issue. Can execute just my-controller/my-action/ and hit the same route as {controller}/{action}/{id?} . So in this case {id} should not be used.

request: http://example.org/my-controller/my-action
route template: {controller}/{action/{id?}
http.route: my-controller/my-action

request: http://example.org/my-controller/my-action/5
route template: {controller}/{action/{id?}
http.route: my-controller/my-action/{id}

@lmolkova
Copy link
Copy Markdown
Member Author

lmolkova commented Sep 4, 2025

@RassK HTTP conventions don't define any semantics for HTTP route - the value is coming from the HTTP frameworks. Do you think there a better way to describe it than

brief: >
The matched route, that is, the path template in the format used by the respective server framework.
examples: ['/users/:userID?', '{controller}/{action}/{id?}']
note: >
MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.
SHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.

?

Given it's stable, we won't be able to standardize the format.

Copy link
Copy Markdown
Member

@Kielek Kielek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

IMO it will reduce friction related to the recommendation what should be real outcome for http.route and the span name.

@RassK
Copy link
Copy Markdown

RassK commented Sep 4, 2025

@RassK HTTP conventions don't define any semantics for HTTP route - the value is coming from the HTTP frameworks. Do you think there a better way to describe it than

Yes, I see no direct conventions. I'm interpreting it like that: There is a spec for http server span name, and if the http.route must be included (if exists) in the span name, then span naming spec is a constraint to http.route.

https://github.com/open-telemetry/opentelemetry-specification/blob/v1.47.0/specification/trace/api.md#span

The span name concisely identifies the work represented by the Span, for example, an RPC method name, a function name, or the name of a subtask or stage within a larger computation. The span name SHOULD be the most general string that identifies a (statistically) interesting class of Spans, rather than individual Span instances while still being human-readable. That is, "get_user" is a reasonable name, while "get_user/314159", where "314159" is a user ID, is not a good name due to its high cardinality. Generality SHOULD be prioritized over human-readability.

This could be seen constraining http.route not to include framework specifics (like ?, :int, :string, :transformer). Since framework specifics does not follow "The span name SHOULD be the most general string that identifies a (statistically) interesting class of Spans".

Suggestions

Some help from chatgpt:

Attribute Type Description
http.route string The matched route template for the request, with dynamic path segments replaced by {param} placeholders. MUST be low-cardinality and independent of framework syntax. Example: /users/{userId}, /articles/{articleId}/comments.

Rules:

  • Replace dynamic path segments (IDs, UUIDs, slugs, etc.) with {param}.
  • Normalize all placeholders to {param} format, regardless of framework (:id, , {id}).
  • Omit optional markers (?) — always record the general case.
  • Include all parent segments that are part of the matched route.
  • MUST NOT include actual values from requests (e.g., /users/314159).

Examples:

  • Express /users/:id → /users/{id}
  • Django /articles/int:id/edit/ → /articles/{id}/edit
  • ASP.NET {controller}/{action}/{id?} (resolved to Users/Get/42) → /users/get/{id}
  • Spring Boot /orders/{orderId} → /orders/{orderId}

@matt-hensley
Copy link
Copy Markdown
Contributor

In the case of a route template like {controller}/{action}/{id?}, I'd personally categorize all 3 parameters as dynamic. I can see how others may consider controller and action static, as there are a finite set of values for most applications.

Some additional detail might leave less room for interpretation. Here is an attempt:

The matched route template for the request. This MUST be low-cardinality and include all static path segments, with dynamic path segments represented with placeholders.

Along with a footnote defining static vs dynamic and examples for common frameworks like @RassK commented:

A static path segment is a part of the route template with a fixed, low-cardinality value. This includes literal strings like /users/ and placeholders that are constrained to a finite, predefined set of values {controller} or {action}.

A dynamic path segment is a placeholder for a value that can have high cardinality and is not constrained to a predefined list like {id}.
<table of examples>

@lmolkova
Copy link
Copy Markdown
Member Author

lmolkova commented Sep 4, 2025

@matt-hensley @RassK makes sense, would you be willing to send a PR? I can close this one.

@matt-hensley
Copy link
Copy Markdown
Contributor

@lmolkova opened #2734 for consideration

@lmolkova
Copy link
Copy Markdown
Member Author

lmolkova commented Sep 4, 2025

closing in favor of #2734

@lmolkova lmolkova closed this Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Improve guidelines to HTTP span name generation

4 participants