Skip to content
Draft
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Unreleased

- **feat(browser)!: Extract Web Vitals into a dedicated `webVitalsIntegration` (v11)**

Web vital tracking (LCP, CLS, INP) has been extracted out of `browserTracingIntegration` into a new standalone `webVitalsIntegration`. `browserTracingIntegration` auto-registers it by default, so no migration is required for the common case.

Breaking changes:
- `enableInp` option on `browserTracingIntegration` has been removed. To disable INP, register `webVitalsIntegration({ disable: ['inp'] })` alongside `browserTracingIntegration`.
- `_experiments.enableStandaloneClsSpans` and `_experiments.enableStandaloneLcpSpans` have been removed; the v1 standalone web vital span path no longer exists.
- The internal standalone span envelope path (`SpanContext.isStandalone`, `experimental.standalone` on `StartSpanOptions`, `createSpanEnvelope`, `SentrySpan#isStandaloneSpan`) has been removed. Web vitals now flow through the v2 streamed span pipeline exclusively.

- **feat(nitro): Add `@sentry/nitro` SDK**

A new `@sentry/nitro` package provides first-class Sentry support for [Nitro](https://nitro.build/) applications, with HTTP handler and error instrumentation, middleware tracing, request isolation, and build-time source map uploading via `withSentryConfig`.
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Sentry.init({
Sentry.browserTracingIntegration({
linkPreviousTrace: 'in-memory',
consistentTraceSampling: true,
enableInp: false,
}),
Sentry.spanStreamingIntegration(),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Sentry.init({
Sentry.browserTracingIntegration({
linkPreviousTrace: 'in-memory',
consistentTraceSampling: true,
enableInp: false,
}),
],
tracePropagationTargets: ['sentry-test-external.io'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Sentry.init({
enableLongTask: false,
enableLongAnimationFrame: true,
instrumentPageLoad: false,
enableInp: false,
}),
Sentry.spanStreamingIntegration(),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Sentry.init({
enableLongTask: false,
enableLongAnimationFrame: true,
instrumentPageLoad: false,
enableInp: false,
}),
],
tracesSampleRate: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Sentry.init({
enableLongAnimationFrame: false,
instrumentPageLoad: false,
instrumentNavigation: true,
enableInp: false,
enableLongTask: true,
}),
Sentry.spanStreamingIntegration(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Sentry.init({
enableLongAnimationFrame: false,
instrumentPageLoad: false,
instrumentNavigation: true,
enableInp: false,
enableLongTask: true,
}),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ sentryTest('should capture a `connection.rtt` metric. xxx', async ({ getLocalTes
const url = await getLocalTestUrl({ testDir: __dirname });
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.['connection.rtt']?.value).toBe(0);
expect(eventData.contexts?.trace?.data?.['network.connection.rtt']).toBe(0);
});

sentryTest(
Expand All @@ -40,8 +39,7 @@ sentryTest(

await session.detach();

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.['connection.rtt']?.value).toBe(200);
expect(eventData.contexts?.trace?.data?.['network.connection.rtt']).toBe(200);
},
);

Expand All @@ -55,8 +53,7 @@ sentryTest(

await session.detach();

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.['connection.rtt']?.value).toBe(100);
expect(eventData.contexts?.trace?.data?.['network.connection.rtt']).toBe(100);
},
);

Expand All @@ -70,7 +67,6 @@ sentryTest(

await session.detach();

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.['connection.rtt']?.value).toBe(50);
expect(eventData.contexts?.trace?.data?.['network.connection.rtt']).toBe(50);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../.

const bundle = process.env.PW_BUNDLE || '';

sentryTest(
// TODO(v11): re-enable once span streaming is the default — see web-vitals-lcp/test.ts.
sentryTest.skip(
'should capture metrics for LCP instrumentation handlers',
async ({ browserName, getLocalTestUrl, page }) => {
// This uses a utility that is not exported in CDN bundles
Expand All @@ -26,17 +27,19 @@ sentryTest(
page.locator('button').click(),
]);

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.lcp?.value).toBeDefined();
const lcpSpan = eventData.spans?.find(({ op }) => op === 'ui.webvital.lcp');
expect(lcpSpan).toBeDefined();
const lcpAttrs = lcpSpan?.data ?? {};
expect(lcpAttrs['browser.web_vital.lcp.value']).toBeGreaterThan(0);

// This should be body > img, but it can be flakey as sometimes it will report
// the button as LCP.
expect(eventData.contexts?.trace?.data?.['lcp.element'].startsWith('body >')).toBe(true);
expect(String(lcpAttrs['browser.web_vital.lcp.element']).startsWith('body >')).toBe(true);

// Working around flakiness
// Only testing this when the LCP element is an image, not a button
if (eventData.contexts?.trace?.data?.['lcp.element'] === 'body > img') {
expect(eventData.contexts?.trace?.data?.['lcp.size']).toBe(107400);
if (lcpAttrs['browser.web_vital.lcp.element'] === 'body > img') {
expect(lcpAttrs['browser.web_vital.lcp.size']).toBe(107400);

const lcp = await (await page.waitForFunction('window._LCP')).jsonValue();
const lcp2 = await (await page.waitForFunction('window._LCP2')).jsonValue();
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading