Skip to content
Open
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 @@ -7,6 +7,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!

- 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(browser): The pageload span now carries `browser.navigation.type`, the navigation type web-vitals reported TTFB and FCP for. Those vitals, and FP, are attributes of the pageload span rather than spans of their own, so until now there was no navigation type to read them against.
- 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.
- Integration options now follow the client. Previously a second `Sentry.init()` in the same process silently reused the options of the first one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_SDK_INTEGRATIONS,
} from '@sentry/core';
import {
BROWSER_NAVIGATION_TYPE,
SENTRY_SEGMENT_NAME_SOURCE,
SENTRY_SEGMENT_ID,
SENTRY_SEGMENT_NAME,
Expand Down Expand Up @@ -125,6 +126,10 @@ sentryTest(
type: expect.stringMatching(/^(integer)|(double)$/),
value: expect.any(Number),
},
[BROWSER_NAVIGATION_TYPE]: {
type: 'string',
value: 'navigate',
},
}),
'sentry.idle_span_finish_reason': {
type: 'string',
Expand Down
14 changes: 13 additions & 1 deletion packages/browser-utils/src/web-vitals/tracking.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { Client, Measurements, Span } from '@sentry/core';
import { browserPerformanceTimeOrigin, debug, setMeasurement, spanToJSON } from '@sentry/core';
import { SENTRY_OP } from '@sentry/conventions/attributes';
import { BROWSER_NAVIGATION_TYPE, SENTRY_OP } from '@sentry/conventions/attributes';
import { DEBUG_BUILD } from '../debug-build';
import { htmlTreeAsString } from '../htmlTreeAsString';
import type { MetricNavigationType } from '../instrumentation/performanceObserver';
import {
addClsInstrumentationHandler,
addFcpInstrumentationHandler,
Expand All @@ -17,6 +18,7 @@ import { getActivationStart, getNavigationEntry, getVisibilityWatcher } from './
let _measurements: Measurements = {};
let _lcpEntry: LargestContentfulPaint | undefined;
let _clsEntry: LayoutShift | undefined;
let _navigationType: MetricNavigationType | undefined;

interface StartTrackingWebVitalsOptions {
trackCls: boolean;
Expand Down Expand Up @@ -83,6 +85,8 @@ function _trackLCP(): () => void {

function _trackTtfb(): () => void {
return addTtfbInstrumentationHandler(({ metric }) => {
_navigationType = metric.navigationType;

const entry = metric.entries[metric.entries.length - 1];
if (!entry) {
return;
Expand All @@ -95,6 +99,7 @@ function _trackTtfb(): () => void {
/** Starts tracking the First Contentful Paint on the current page. */
function _trackFcp(): () => void {
return addFcpInstrumentationHandler(({ metric }) => {
_navigationType = metric.navigationType;
_measurements['fcp'] = { value: metric.value, unit: 'millisecond' };
});
}
Expand Down Expand Up @@ -201,6 +206,12 @@ export function addWebVitalsToSpan(span: Span, options: AddWebVitalsToSpanOption
_setWebVitalAttributes(span, options);
}

// TTFB, FP and FCP are attributes of this span rather than spans of their own, so the navigation
// type they were measured on is reported here for them to be read against.
if (_navigationType) {
span.setAttribute(BROWSER_NAVIGATION_TYPE, _navigationType);
}

// Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on
span.setAttribute(spanStreamingEnabled ? 'browser.performance.time_origin' : 'performance.timeOrigin', timeOrigin);

Expand All @@ -222,6 +233,7 @@ export function addWebVitalsToSpan(span: Span, options: AddWebVitalsToSpanOption
function resetWebVitalState(): void {
_lcpEntry = undefined;
_clsEntry = undefined;
_navigationType = undefined;
_measurements = {};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,6 @@ describe('startTrackingWebVitals', () => {

expect(spanToJSON(pageloadSpan).attributes['browser.web_vital.fp.value']).toBe(12);
expect(spanToJSON(pageloadSpan).attributes['browser.web_vital.fcp.value']).toBe(18);
expect(spanToJSON(pageloadSpan).attributes['browser.navigation.type']).toBe('prerender');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,6 @@ describe('startTrackingWebVitals', () => {

expect(spanToJSON(pageloadSpan).attributes['browser.web_vital.fp.value']).toBe(12);
expect(spanToJSON(pageloadSpan).attributes['browser.web_vital.fcp.value']).toBe(18);
expect(spanToJSON(pageloadSpan).attributes['browser.navigation.type']).toBe('navigate');
});
});
Loading