Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

Work in this release was contributed by @psh4607, @thijsw, @trinitiwowka, @nehaprasad-dev, @JealousGx, @Jxxunnn, @eddie333016, @davidmurdoch, @yashschandra, @atharv-sys32, @AG0708, @birkskyum, @mkly, @mcbbugu, @suhailopensource, @zkasuran, @mohd-akram, @RealBhupesh, @halillusion, @psang39, @hafzism, @JosephDoUrden, @Tyagiquamar, @Andarist, @msnelling, and @oesnuj. Thank you for your contributions!

- ref(browser)!: LCP and CLS spans no longer set `browser.web_vital.lcp.report_event` and `browser.web_vital.cls.report_event`. With per-navigation web vitals (the default) the attribute was already never set; it is now also gone when `softNavigations` and `bfcacheNavigations` are turned off. When the values are finalized is unchanged.
- feat(browser)!: `browser.navigation.type` on web vital and bfcache navigation spans now carries the navigation type exactly as web-vitals reports it. `bfcache` is now `back-forward-cache`, and a back/forward navigation that missed the bfcache (`back-forward`) or a discarded-tab restore (`restore`) is no longer folded into `navigate`. Update any dashboards or alerts filtering on `bfcache`.
- feat(core): Add `createFetchIntegration`, the shared implementation behind the global-`fetch` integrations in `@sentry/bun`, `@sentry/cloudflare`, `@sentry/deno` and `@sentry/vercel-edge`. Those four packages carried four copies of it; they now share one. Two changes come out of that:
- All four gain a `tracePropagation` option (default `true`). Turn it off to stop injecting `sentry-trace` and `baggage` without also turning off spans. To scope propagation to specific URLs, keep using `tracePropagationTargets` in the client options.
Expand Down
8 changes: 8 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,14 @@ Sentry.init({
});
```

### Web vital spans no longer carry a report event

Affected SDKs: All SDKs running in the browser.

LCP and CLS spans no longer set `browser.web_vital.lcp.report_event` and `browser.web_vital.cls.report_event`. The attribute recorded whether the SDK finalized the page load's value on `pagehide` or at the first `navigation`. With per-navigation reporting (the default, see above) `web-vitals` decides when a value is final and the attribute was already never set, so it only remained for setups that turn per-navigation reporting off.

When the values are finalized is unchanged. If you have searches or dashboards keyed on the attribute, remove the filter.

### `DOMException.code` is no longer set as a tag

Affected SDKs: All SDKs running in the browser.
Expand Down
7 changes: 0 additions & 7 deletions packages/browser-utils/src/web-vitals/emitSpan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
} from '@sentry/conventions/attributes';
import { WINDOW } from '../types';
import type { MetricNavigationType } from '../instrumentation/performanceObserver';
import type { WebVitalReportEvent } from './reportEvents';

// Locally-defined interfaces to avoid leaking bare global type references into the
// generated .d.ts. The `declare global` augmentations in web-vitals/types.ts make these
Expand Down Expand Up @@ -48,7 +47,6 @@ interface WebVitalSpanOptions {
value: number;
attributes?: SpanAttributes;
parentSpan?: Span;
reportEvent?: WebVitalReportEvent;
startTime: number;
endTime?: number;
/** Set when the vital was reported for a soft navigation rather than the initial page load. */
Expand Down Expand Up @@ -78,7 +76,6 @@ export function _emitWebVitalSpan(options: WebVitalSpanOptions): void {
value,
attributes: passedAttributes,
parentSpan,
reportEvent,
startTime,
endTime,
standalone,
Expand Down Expand Up @@ -111,10 +108,6 @@ export function _emitWebVitalSpan(options: WebVitalSpanOptions): void {
attributes['sentry.pageload.span_id'] = parentSpan.spanContext().spanId;
}

if (reportEvent) {
attributes[`browser.web_vital.${metricName}.report_event`] = reportEvent;
}

if (softNavigationId != null) {
attributes[BROWSER_NAVIGATION_ID] = softNavigationId;
}
Expand Down
23 changes: 8 additions & 15 deletions packages/browser-utils/src/web-vitals/reportEvents.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
import type { Client, Span } from '@sentry/core';
import { onHidden } from './utils';

export type WebVitalReportEvent = 'pagehide' | 'navigation';

/**
* Listens for events on which we want to collect a previously accumulated web vital value.
* Currently, this includes:
*
* - pagehide (i.e. user minimizes browser window, hides tab, etc)
* - soft navigation (we only care about the vital of the initially loaded route)
*
* As a "side-effect", this function will also collect the span id of the pageload span.
* As a "side-effect", this function will also collect the pageload span.
*
* @param collectorCallback the callback to be called when the first of these events is triggered. Parameters:
* - event: the event that triggered the reporting of the web vital value.
* - pageloadSpanId: the span id of the pageload span. This is used to link the web vital span to the pageload span.
* - pageloadSpan: the pageload span instance. This is used for full access to the pageload span for span streaming.
* @param collectorCallback the callback to be called when the first of these events is triggered. It is passed the
* pageload span, which the web vital span is parented to.
*/
export function listenForWebVitalReportEvents(
client: Client,
collectorCallback: (event: WebVitalReportEvent, pageloadSpanId: string, pageloadSpan?: Span) => void,
) {
export function listenForWebVitalReportEvents(client: Client, collectorCallback: (pageloadSpan: Span) => void) {
let pageloadSpan: Span | undefined;

let collected = false;
function _runCollectorCallbackOnce(event: WebVitalReportEvent) {
function _runCollectorCallbackOnce() {
if (!collected && pageloadSpan) {
collectorCallback(event, pageloadSpan.spanContext().spanId, pageloadSpan);
collectorCallback(pageloadSpan);
}
collected = true;
}

onHidden(() => {
_runCollectorCallbackOnce('pagehide');
_runCollectorCallbackOnce();
});

const unsubscribeStartNavigation = client.on('beforeStartNavigationSpan', (_, options) => {
// we only want to collect LCP if we actually navigate. Redirects should be ignored.
if (!options?.isRedirect) {
_runCollectorCallbackOnce('navigation');
_runCollectorCallbackOnce();
unsubscribeStartNavigation();
unsubscribeAfterStartPageLoadSpan();
}
Expand Down
15 changes: 4 additions & 11 deletions packages/browser-utils/src/web-vitals/spans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import type { LargestContentfulPaint, LayoutShift } from './emitSpan';
import { BROWSER_NAVIGATION_TYPE } from '@sentry/conventions/attributes';
import { _emitWebVitalSpan } from './emitSpan';
import { isValidLcpMetric } from './lcp';
import type { WebVitalReportEvent } from './reportEvents';
import { listenForWebVitalReportEvents } from './reportEvents';
import { getNavigationSpanForMetric } from './softNavs';
import { getBrowserPerformanceAPI, msToSec, supportsWebVital } from '../performance/utils';
Expand Down Expand Up @@ -125,7 +124,6 @@ export function trackLcpAsSpan(client: Client, perNavigation = false): void {
metric.value,
entry,
parentSpan,
undefined,
softNavigationId,
metric.navigationType,
metric.navigationStartTime,
Expand All @@ -151,8 +149,8 @@ export function trackLcpAsSpan(client: Client, perNavigation = false): void {
lcpEntry = entry;
}, true);

listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {
_sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, reportEvent, undefined, lcpNavigationType);
listenForWebVitalReportEvents(client, pageloadSpan => {
_sendLcpSpan(lcpValue, lcpEntry, pageloadSpan, undefined, lcpNavigationType);
cleanupLcpHandler();
});
}
Expand All @@ -164,7 +162,6 @@ export function _sendLcpSpan(
lcpValue: number,
entry: LargestContentfulPaint | undefined,
pageloadSpan?: Span,
reportEvent?: WebVitalReportEvent,
softNavigationId?: number,
navigationType?: MetricNavigationType,
navigationStartTime?: number,
Expand Down Expand Up @@ -202,7 +199,6 @@ export function _sendLcpSpan(
value: lcpValue,
attributes,
parentSpan: pageloadSpan,
reportEvent,
startTime,
endTime,
softNavigationId,
Expand All @@ -225,7 +221,6 @@ export function trackClsAsSpan(client: Client, perNavigation = false): void {
metric.value,
entry,
parentSpan,
undefined,
softNavigationId,
metric.navigationType,
metric.navigationStartTime,
Expand All @@ -251,8 +246,8 @@ export function trackClsAsSpan(client: Client, perNavigation = false): void {
clsEntry = entry;
}, true);

listenForWebVitalReportEvents(client, (reportEvent, _, pageloadSpan) => {
_sendClsSpan(clsValue, clsEntry, pageloadSpan, reportEvent, undefined, clsNavigationType);
listenForWebVitalReportEvents(client, pageloadSpan => {
_sendClsSpan(clsValue, clsEntry, pageloadSpan, undefined, clsNavigationType);
cleanupClsHandler();
});
}
Expand All @@ -264,7 +259,6 @@ export function _sendClsSpan(
clsValue: number,
entry: LayoutShift | undefined,
pageloadSpan?: Span,
reportEvent?: WebVitalReportEvent,
softNavigationId?: number,
navigationType?: MetricNavigationType,
navigationStartTime?: number,
Expand Down Expand Up @@ -295,7 +289,6 @@ export function _sendClsSpan(
value: clsValue,
attributes,
parentSpan: pageloadSpan,
reportEvent,
startTime,
softNavigationId,
navigationType,
Expand Down
28 changes: 3 additions & 25 deletions packages/browser-utils/test/web-vitals/spans.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,26 +282,6 @@ describe('_emitWebVitalSpan', () => {
);
});

it('includes reportEvent when provided', () => {
_emitWebVitalSpan({
name: 'Test',
op: 'ui.webvital.cls',
origin: 'auto.http.browser.cls',
metricName: 'cls',
value: 0.1,
reportEvent: 'pagehide',
startTime: 1.0,
});

expect(SentryCoreBrowser.startInactiveSpan).toHaveBeenCalledWith(
expect.objectContaining({
attributes: expect.objectContaining({
'browser.web_vital.cls.report_event': 'pagehide',
}),
}),
);
});

it('merges additional attributes', () => {
_emitWebVitalSpan({
name: 'Test',
Expand Down Expand Up @@ -421,7 +401,7 @@ describe('_sendLcpSpan', () => {

const mockPageloadSpan = createMockPageloadSpan('pageload-123');

_sendLcpSpan(250, mockEntry, mockPageloadSpan as any, 'pagehide');
_sendLcpSpan(250, mockEntry, mockPageloadSpan as any);

expect(SentryCoreBrowser.startInactiveSpan).toHaveBeenCalledWith(
expect.objectContaining({
Expand All @@ -437,7 +417,6 @@ describe('_sendLcpSpan', () => {
'browser.web_vital.lcp.load_time': 100,
'browser.web_vital.lcp.render_time': 150,
'browser.web_vital.lcp.size': 50000,
'browser.web_vital.lcp.report_event': 'pagehide',
'sentry.transaction': 'test-route',
'sentry.segment.name': 'test-route',
}),
Expand All @@ -464,7 +443,7 @@ describe('_sendLcpSpan', () => {
it('lasts the reported value when there is no entry to end at', () => {
// A soft navigation 2000ms into the page. Ending at the time origin would put the end before
// the start.
_sendLcpSpan(250, undefined, undefined, undefined, 2, 'soft-navigation', 2000);
_sendLcpSpan(250, undefined, undefined, 2, 'soft-navigation', 2000);

expect(SentryCoreBrowser.startInactiveSpan).toHaveBeenCalledWith(expect.objectContaining({ startTime: 3 }));
expect(mockSpan.end).toHaveBeenCalledWith(3.25);
Expand Down Expand Up @@ -530,7 +509,7 @@ describe('_sendClsSpan', () => {

const mockPageloadSpan = createMockPageloadSpan('pageload-789');

_sendClsSpan(0.1, mockEntry, mockPageloadSpan as any, 'navigation');
_sendClsSpan(0.1, mockEntry, mockPageloadSpan as any);

expect(SentryCoreBrowser.startInactiveSpan).toHaveBeenCalledWith(
expect.objectContaining({
Expand All @@ -541,7 +520,6 @@ describe('_sendClsSpan', () => {
'sentry.pageload.span_id': 'pageload-789',
'browser.web_vital.cls.source.1': '<div>',
'browser.web_vital.cls.source.2': '<span>',
'browser.web_vital.cls.report_event': 'navigation',
'sentry.transaction': 'test-route',
'sentry.segment.name': 'test-route',
}),
Expand Down
Loading