Skip to content

Strip query string from uri low-cardinality key in DefaultClientRequestObservationConvention#36646

Closed
anuragg-saxenaa wants to merge 1 commit intospring-projects:mainfrom
anuragg-saxenaa:fix/issue-36547-uri-tag-query-cardinality
Closed

Strip query string from uri low-cardinality key in DefaultClientRequestObservationConvention#36646
anuragg-saxenaa wants to merge 1 commit intospring-projects:mainfrom
anuragg-saxenaa:fix/issue-36547-uri-tag-query-cardinality

Conversation

@anuragg-saxenaa
Copy link
Copy Markdown

Summary

extractPath() in DefaultClientRequestObservationConvention stripped the scheme and host but preserved the query string. When HTTP Interface clients (@HttpExchange) use @RequestParam parameters, Spring injects URI template placeholders like {queryParam-category} into the query string. Because these differ per combination of present/absent optional parameters and per list length, the uri low-cardinality tag inherits combinatorial or even unbounded cardinality — defeating the purpose of the tag and causing Prometheus metric explosion.

Changes

  • spring-web DefaultClientRequestObservationConvention.extractPath(): strip everything from ? onward
  • spring-webflux DefaultClientRequestObservationConvention.extractPath(): same fix

Path template variables ({id}) continue to be preserved since they identify distinct endpoint routes. The full URI (including query string) is already captured in the http.url high-cardinality key, so no observability information is lost.

Behavior change

Before:

uri="/resource/{id}?queryKey={queryValue}"    (high cardinality — varies per param combination)

After:

uri="/resource/{id}"    (low cardinality — matches server-side behavior)

This is consistent with how server-side @RequestMapping with @RequestParam already behaves (uri="/api/v1/items" regardless of query parameters).

Fixes #36547

…RequestObservationConvention (spring-projects#36547)

extractPath() stripped the scheme and authority from a URI template but
preserved the query string. When HTTP Interface clients add @RequestParam
parameters, Spring injects placeholders like {queryParam-category} into
the URI template query string. Because these placeholders differ per
combination of present/absent optional parameters and per list length,
the uri low-cardinality tag inherits that cardinality — defeating the
purpose of the low-cardinality key and causing metric explosion.

Strip everything from '?' onward in extractPath() so the uri tag
contains only the path portion. Path variables ({id}) continue to be
preserved. The full URI (including query) is already captured in the
http.url high-cardinality key, so no information is lost.

Same fix applied to both spring-web and spring-webflux implementations.
Tests updated to assert the new (correct) behaviour.

Fixes spring-projects#36547

Signed-off-by: anuragg-saxenaa <anuragg.saxenaa@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 12, 2026
@bclozel
Copy link
Copy Markdown
Member

bclozel commented Apr 13, 2026

Declining because this would be breaking behavior. See #36547 (comment)

@bclozel bclozel closed this Apr 13, 2026
@bclozel bclozel added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 13, 2026
@anuragg-saxenaa
Copy link
Copy Markdown
Author

Thanks for the explanation @bclozel — you're right, stripping query params globally would break valid use cases like /users?profile=full being intentionally tracked as a distinct URI pattern.

The cardinality issue is specific to @HttpExchange auto-generating {queryParam-*} placeholders. A more targeted fix would indeed belong there rather than in the observation convention. Closing this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: declined A suggestion or change that we don't feel we should currently apply

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DefaultClientRequestObservationConvention produces combinatorial URI tag cardinality with optional @RequestParam

3 participants