Skip to content

feat(core)!: Update all spans to use url.full, url.fragment and url.query - #22547

Merged
mydea merged 17 commits into
developfrom
fn/url-attributes
Jul 28, 2026
Merged

feat(core)!: Update all spans to use url.full, url.fragment and url.query#22547
mydea merged 17 commits into
developfrom
fn/url-attributes

Conversation

@mydea

@mydea mydea commented Jul 23, 2026

Copy link
Copy Markdown
Member

This updates all spans we emit to:

  1. Ensure we directly set url related attributes instead of relying on inferral
  2. Update to the new semantic attribtues:
    a. http.url and url become url.full
    b. http.fragment becomes url.fragment (with unified semantic omitting the #)
    c. http.search becomes url.search (with unified semantic omitting the ?)

For this we introduce new utility helpers to ensure consistent formatting of search/fragment.

@mydea mydea changed the title feat(core): Ensure url, http.query and http.fragment are directly added feat(core): Ensure url, http.query and http.fragment are directly added Jul 23, 2026
Comment thread packages/core/src/fetch.ts Outdated
Comment thread packages/core/src/utils/url.ts Outdated
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.02 kB - -
@sentry/browser - with treeshaking flags 26.46 kB - -
@sentry/browser (incl. Tracing) 46.58 kB +0.1% +42 B 🔺
@sentry/browser (incl. Tracing + Span Streaming) 47.48 kB +0.05% +19 B 🔺
@sentry/browser (incl. Tracing, Profiling) 51.3 kB +0.02% +6 B 🔺
@sentry/browser (incl. Tracing, Replay) 85.9 kB +0.04% +33 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 75.53 kB +0.02% +14 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 90.6 kB +0.03% +26 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 103.24 kB +0.03% +22 B 🔺
@sentry/browser (incl. Feedback) 45.2 kB - -
@sentry/browser (incl. sendFeedback) 32.82 kB - -
@sentry/browser (incl. FeedbackAsync) 37.86 kB - -
@sentry/browser (incl. Metrics) 29.12 kB - -
@sentry/browser (incl. Logs) 29.34 kB - -
@sentry/browser (incl. Metrics & Logs) 30.05 kB - -
@sentry/react 29.8 kB - -
@sentry/react (incl. Tracing) 48.89 kB +0.09% +40 B 🔺
@sentry/vue 33.97 kB - -
@sentry/vue (incl. Tracing) 48.55 kB +0.05% +20 B 🔺
@sentry/svelte 28.04 kB - -
CDN Bundle 30.32 kB - -
CDN Bundle (incl. Tracing) 47.72 kB +0.03% +14 B 🔺
CDN Bundle (incl. Logs, Metrics) 31.9 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 49.1 kB +0.04% +16 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 71.17 kB - -
CDN Bundle (incl. Tracing, Replay) 85.36 kB +0.06% +47 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 86.64 kB +0.04% +31 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 91.13 kB +0.02% +15 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 92.42 kB +0.04% +30 B 🔺
CDN Bundle - uncompressed 90.26 kB - -
CDN Bundle (incl. Tracing) - uncompressed 143.21 kB -0.01% -11 B 🔽
CDN Bundle (incl. Logs, Metrics) - uncompressed 94.97 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 147.19 kB -0.01% -11 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 219.73 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 262.46 kB -0.01% -11 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 266.43 kB -0.01% -11 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 276.17 kB -0.01% -11 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 280.12 kB -0.01% -11 B 🔽
@sentry/nextjs (client) 51.44 kB +0.07% +32 B 🔺
@sentry/sveltekit (client) 47.03 kB +0.05% +23 B 🔺
@sentry/core/server 79.66 kB +0.11% +84 B 🔺
@sentry/core/browser 51.6 kB +0.12% +59 B 🔺
@sentry/node 112.45 kB -0.03% -28 B 🔽
@sentry/node (incl. diagnostics channel injection) 156.6 kB -0.03% -39 B 🔽
@sentry/node/import (ESM hook with diagnostics-channel injection) 166 B - -
@sentry/node - without tracing 61.99 kB -0.04% -22 B 🔽
@sentry/aws-serverless 72.32 kB +0.04% +23 B 🔺
@sentry/cloudflare (withSentry) - minified 196.03 kB +0.05% +87 B 🔺
@sentry/cloudflare (withSentry) 482.73 kB +0.05% +229 B 🔺

View base workflow run

@mydea
mydea force-pushed the fn/url-attributes branch from 4345066 to 6c67654 Compare July 23, 2026 12:56
@mydea
mydea marked this pull request as ready for review July 23, 2026 13:28
@mydea
mydea requested review from a team as code owners July 23, 2026 13:28
@mydea
mydea requested review from andreiborza, isaacs, logaretm and msonnb and removed request for a team July 23, 2026 13:28

@isaacs isaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some suggestions for cleanup and I think the clanker comment is likely valid.

It might be good to add a helper utility that can strip fragment/search strings, since we have url.search?.strip(1) || undefined in a bunch of places now? Something like:

function stripUrlPart(part: string || undefined || null, prefix: '?' : '#') {
  return (part && part.charAt(0) === prefix) ? part.strip(1) : undefined;
}

Comment on lines +27 to +28
...(parsedUrl.search ? { 'http.query': parsedUrl.search.slice(1) || undefined } : {}),
...(parsedUrl.hash ? { 'http.fragment': parsedUrl.hash.slice(1) || undefined } : {}),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These get serialized with JSON.stringify, so undefined values are safe. Not a blocker, but worth cleaning up where we encounter it, imo. Also, these can probably pull in the costs to cut down on bundle size ever so slightly:

Suggested change
...(parsedUrl.search ? { 'http.query': parsedUrl.search.slice(1) || undefined } : {}),
...(parsedUrl.hash ? { 'http.fragment': parsedUrl.hash.slice(1) || undefined } : {}),
[HTTP_FRAGMENT]: parsedUrl.hash?.slice(1) || undefined,
[HTTP_QUERY]: parsedUrl?.search?.slice(1) || undefined,

Comment on lines +173 to +174
const query = urlObj?.search ? urlObj.search.slice(1) || undefined : undefined;
const fragment = urlObj?.hash ? urlObj.hash.slice(1) || undefined : undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here

Suggested change
const query = urlObj?.search ? urlObj.search.slice(1) || undefined : undefined;
const fragment = urlObj?.hash ? urlObj.hash.slice(1) || undefined : undefined;
const query = urlObj?.search?.slice(1) || undefined;
const fragment = urlObj?.hash?.slice(1) || undefined;

Comment thread packages/core/src/fetch.ts Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be requestUrl.search?.strip(1) || undefined?

@mydea
mydea force-pushed the fn/url-attributes branch from 6c67654 to c78788f Compare July 27, 2026 11:06
@mydea
mydea requested a review from a team as a code owner July 27, 2026 11:06
@mydea
mydea requested review from nicohrubec and s1gr1d and removed request for a team July 27, 2026 11:06
@mydea mydea changed the title feat(core): Ensure url, http.query and http.fragment are directly added feat(core): Update all spans to use url.full, url.fragment and url.query Jul 27, 2026
Comment thread packages/browser/src/tracing/request.ts
@mydea
mydea force-pushed the fn/url-attributes branch from c78788f to 8567eb6 Compare July 27, 2026 11:54
Comment thread packages/opentelemetry/src/utils/parseSpanDescription.ts
Comment thread packages/angular/src/tracing.ts

@Lms24 Lms24 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice cleanup, thanks!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same q for this test: shouldn't url no longer be sent?

Comment thread packages/core/src/utils/url.ts Outdated
* unconditionally — setting an attribute to `undefined` is a no-op.
*/
export function getUrlQuery(query: string | undefined): string | undefined {
return stripUrlPartPrefix(query, '?');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

l: instead of the helper function, could we simply inline this?

Suggested change
return stripUrlPartPrefix(query, '?');
return query?.replace(/^\?/, '')

might save a couple of bytes. Same for the fragment below

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good call!

}
if (parsedUrl.hash) {
attributes['http.fragment'] = parsedUrl.hash;
attributes[SERVER_ADDRESS] = parsedUrl.host;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The code incorrectly assigns parsedUrl.host to the SERVER_ADDRESS attribute, which includes the port number for non-standard ports, violating OpenTelemetry semantic conventions.
Severity: MEDIUM

Suggested Fix

To conform to OpenTelemetry standards, change the assignment for SERVER_ADDRESS from parsedUrl.host to parsedUrl.hostname. This will correctly exclude the port number from the server.address attribute.

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/core/src/fetch.ts#L401

Potential issue: The code sets the `SERVER_ADDRESS` attribute using `parsedUrl.host`.
According to the JavaScript URL API, `URL.host` includes the port number if it's
non-standard (e.g., `example.com:8080`). This violates the OpenTelemetry semantic
convention for `server.address`, which should only contain the domain name or IP
address, with the port stored in a separate `server.port` attribute. This bug is
triggered for any HTTP request made to a non-standard port, resulting in semantically
incorrect telemetry data that can confuse downstream monitoring and analysis tools.

Also affects:

  • packages/browser/src/tracing/request.ts:394~394

@mydea mydea changed the title feat(core): Update all spans to use url.full, url.fragment and url.query feat(core)!: Update all spans to use url.full, url.fragment and url.query Jul 27, 2026
Comment thread packages/core/src/fetch.ts
Comment thread packages/core/src/types/request.ts Outdated
Comment on lines +31 to +32
'url.fragment'?: string;
'url.query'?: string;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it possible to use a template literal type here? Then we could import from sentry conventions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah should be, there are some leftovers I suppose that should be updated!

@mydea
mydea force-pushed the fn/url-attributes branch from 9914791 to 5431c5a Compare July 27, 2026 13:53
Comment thread dev-packages/e2e-tests/test-applications/astro-5/tests/tracing.dynamic.test.ts Outdated
@mydea
mydea enabled auto-merge (squash) July 27, 2026 14:35
@mydea
mydea force-pushed the fn/url-attributes branch from e8e4377 to 2aefe20 Compare July 27, 2026 14:50
@mydea
mydea disabled auto-merge July 27, 2026 14:53

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2aefe20. Configure here.

Comment on lines +211 to +213
attributes[URL_FULL] = isURLObjectRelative(urlObject)
? getSanitizedUrlStringFromUrlObject(urlObject)
: urlObject.href;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The url.full attribute is set to a relative pathname for relative URLs, which violates the OpenTelemetry semantic convention requiring an absolute URL.
Severity: MEDIUM

Suggested Fix

To comply with the OpenTelemetry specification, the url.full attribute should only be set when an absolute URL is available. For relative URLs, this attribute should be omitted entirely instead of being set to a relative path.

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/core/src/utils/url.ts#L211-L213

Potential issue: The code sets the OpenTelemetry attribute `url.full` to a relative path
(e.g., `/api/users`) when processing relative URLs. This violates the OpenTelemetry
semantic convention, which mandates that `url.full` must be an absolute URL. While this
may not cause an immediate crash, it produces non-compliant span data. Downstream
consumers and backend systems that expect a full, parseable URL may fail to process
these spans correctly, leading to issues like incorrect span grouping or data processing
errors.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is true, but I think the best we can do in this case.

@mydea
mydea merged commit 7a6a6a6 into develop Jul 28, 2026
278 checks passed
@mydea
mydea deleted the fn/url-attributes branch July 28, 2026 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants