feat: Emit low-cardinality http.client span names for fetch and XHR - #23682
feat: Emit low-cardinality http.client span names for fetch and XHR#23682chargome wants to merge 2 commits into
Conversation
With span streaming, `http.client` spans are named `{method} {url.domain}` instead of
`{method} {sanitized-url}`, falling back to the method alone when there is no domain.
Covers `instrumentFetchRequest` in `@sentry/core`, browser XHR, and `http.client.stream`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
bugbot run |
size-limit report 📦
|
`parseUrl` returns the raw authority, so `user:pass@host:port` could reach the XHR span name and `server.address`. Strip it, and set `url.domain` on browser fetch and XHR spans so the value in the streamed name is filterable. `fetchStreamPerformance` now uses the client it receives in `setup` instead of `getClient()`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit bdcfbb5. Configure here.
| if (!hasSpanStreamingEnabled(client)) { | ||
| span.updateName(`${httpMethod} ${httpUrl} (${_getGraphQLOperation(graphqlBody)})`); | ||
| } | ||
|
|
There was a problem hiding this comment.
Bug: When span streaming is enabled, the GraphQL operation name is not added as an attribute to the span, losing valuable information for tracing and observability.
Severity: HIGH
Suggested Fix
In _updateSpanWithGraphQLData, when hasSpanStreamingEnabled(client) is true, the GraphQL operation information should be set as an attribute on the span. After getting the operationInfo, add a call like span.setAttribute('graphql.operation.name', operationInfo) to ensure the data is captured on the span, aligning the implementation with the documented behavior.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: packages/browser/src/integrations/graphqlClient.ts#L89-L92
Potential issue: When span streaming is enabled, the `_updateSpanWithGraphQLData`
function correctly avoids updating the span name to maintain low cardinality. However,
it fails to capture the GraphQL operation information (e.g., "query GetUser") as a span
attribute. The code calculates `operationInfo` but never attaches it to the span when
`hasSpanStreamingEnabled(client)` is true. This contradicts the migration documentation,
which states this information should be available on the `graphql.operation.name`
attribute. As a result, users lose the ability to differentiate between GraphQL
operations in their traces, impacting observability.
Did we get this right? 👍 / 👎 to inform future reviews.
| const streamedName = domain ? `${method} ${domain}` : method; | ||
| const streamSpan = startInactiveSpan({ | ||
| name: `${method} ${sanitizedUrl}`, | ||
| name: hasSpanStreamingEnabled(client) ? streamedName : `${method} ${sanitizedUrl}`, |
There was a problem hiding this comment.
q: The sanitizedUrl also takes care of "data: URLs", should the streamedName solely be domains?
Edit: seems like the PR description covers that part
| // name or attribute. | ||
| const host = parsedUrl?.host?.replace(/^.*@/, ''); | ||
| // Unlike `server.address`, `url.domain` excludes the port. | ||
| const domain = host?.replace(/:\d+$/, ''); |
There was a problem hiding this comment.
q: This works differently than in the fetchStreamPerformance integration, is that intended?
The other code I mean:
const domain = parsedUrl && !isURLObjectRelative(parsedUrl) ? parsedUrl.hostname : undefined;
With span streaming,
http.clientspans are named{method} {url.domain}(GET api.example.com)instead of
{method} {sanitized-url}, falling back to the method alone when there is no domain(relative and data URLs).
traceLifecycle: 'static'is unchanged.Covers
instrumentFetchRequestin@sentry/core(browser, bun, cloudflare, vercel-edge), browserXHR, and
http.client.stream.node:httpand undici follow separately.Spans also get a
url.domainattribute in both lifecycles, so the value in the name staysfilterable — same as the
resource.*port.Ref #23527