-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat: Emit low-cardinality http.client span names for node:http and undici #23690
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
Changes from all commits
8899d62
1c6aa69
11b7548
7c485a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| import type { Span, SpanAttributes } from '../../types/span'; | ||
| import { getClient } from '../../currentScopes'; | ||
| import { hasSpanStreamingEnabled } from '../../tracing/spans/hasSpanStreamingEnabled'; | ||
| import { HTTP_SPAN_NAME_FALLBACK } from '../../tracing/spans/spanNames'; | ||
| import { filterCollectedUrl } from '../../utils/data-collection/filterCollectedUrl'; | ||
| import { getContentLengthFromHeaders } from '../../utils/request'; | ||
| import { getHttpSpanDetailsFromUrlObject, parseStringToURLObject } from '../../utils/url'; | ||
| import { getHttpSpanDetailsFromUrlObject, isURLObjectRelative, parseStringToURLObject } from '../../utils/url'; | ||
| import type { HttpClientRequest, HttpIncomingMessage } from './types'; | ||
| import { getRequestUrlFromClientRequest } from './get-request-url'; | ||
| import type { StartSpanOptions } from '../../types/startSpanOptions'; | ||
|
|
@@ -30,17 +33,23 @@ import { HTTP_CLIENT } from '@sentry/conventions/op'; | |
| */ | ||
| export function getOutgoingRequestSpanData(request: HttpClientRequest): StartSpanOptions { | ||
| const url = getRequestUrlFromClientRequest(request); | ||
| const [name, attributes] = getHttpSpanDetailsFromUrlObject( | ||
| parseStringToURLObject(url), | ||
| 'client', | ||
| 'auto.http.client', | ||
| request, | ||
| ); | ||
| const urlObject = parseStringToURLObject(url); | ||
| const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'client', 'auto.http.client', request); | ||
|
|
||
| const userAgent = request.getHeader('user-agent'); | ||
|
|
||
| // With span streaming, span names have to be low cardinality, so only the domain is kept. Outgoing | ||
| // requests have no route to fall back on, and a URL stays relative only when the request carried no | ||
| // host to build one from — server runtimes have no page origin to resolve that against, unlike | ||
| // browsers — so such a request is named after the method alone. | ||
| const client = getClient(); | ||
| const method = request.method?.toUpperCase(); | ||
| const domain = urlObject && !isURLObjectRelative(urlObject) ? urlObject.hostname : undefined; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to #23682 (comment), I guess server-side, we can't really get a doman/hostname for relative URLs 🤔 So omitting it for relative URLs is probably fine... wdyt? logaf-lower-than-in-browser tbh 😅
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, added a comment! |
||
| const streamedName = method ? (domain ? `${method} ${domain}` : method) : HTTP_SPAN_NAME_FALLBACK; | ||
| const spanName = !!client && hasSpanStreamingEnabled(client) ? streamedName : name; | ||
|
|
||
| return { | ||
| name, | ||
| name: spanName, | ||
| attributes: { | ||
| [SENTRY_OP]: HTTP_CLIENT, | ||
| [SENTRY_KIND]: 'client', | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,14 @@ | ||
| import type { ClientRequest, RequestOptions } from 'node:http'; | ||
| import type { Span } from '@sentry/core'; | ||
| import { URL_FULL } from '@sentry/conventions/attributes'; | ||
| import { defineIntegration, getRequestUrlFromClientRequest, hasSpansEnabled, stripDataUrlContent } from '@sentry/core'; | ||
| import { | ||
| defineIntegration, | ||
| getClient, | ||
| getRequestUrlFromClientRequest, | ||
| hasSpansEnabled, | ||
| hasSpanStreamingEnabled, | ||
| stripDataUrlContent, | ||
| } from '@sentry/core'; | ||
| import type { NodeClient } from '../../sdk/client'; | ||
| import type { HttpServerIntegrationOptions } from './httpServerIntegration'; | ||
| import { httpServerIntegration } from './httpServerIntegration'; | ||
|
|
@@ -109,7 +116,12 @@ export const httpIntegration = defineIntegration((options: HttpOptions = {}) => | |
| const url = getRequestUrlFromClientRequest(request); | ||
| if (url.startsWith('data:')) { | ||
| const sanitizedUrl = stripDataUrlContent(url); | ||
| span.updateName(`${request.method || 'GET'} ${sanitizedUrl}`); | ||
| // With span streaming the span already carries a low-cardinality name, so it must not be | ||
| // renamed back to something containing the URL. | ||
| const client = getClient(); | ||
| if (!client || !hasSpanStreamingEnabled(client)) { | ||
| span.updateName(`${request.method || 'GET'} ${sanitizedUrl}`); | ||
| } | ||
|
Comment on lines
+119
to
+124
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. q: should we also just set the request method in a new else block when a URL does not start with
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already handled in |
||
| span.setAttributes({ | ||
| [URL_FULL]: sanitizedUrl, | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
l: unless I'm missing something, can we still assert on the span name here?