Skip to content

feat(replay): Replay Web Vital Breadcrumbs #12296

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

Merged
merged 45 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
59a985f
replay web vital breadcrumbs
c298lee May 30, 2024
6e29bcc
placeholder tests
c298lee May 31, 2024
32a774b
update tests and refactor
c298lee Jun 3, 2024
35c1db0
chore: Document e2e test env vars (#12303)
lforst May 31, 2024
2719b02
fix(browser): Fix idle span ending (#12306)
mydea May 31, 2024
da25922
fix(browser): Fix types export path for CJS (#12305)
mydea May 31, 2024
ba9acbe
feat(vercel-edge): Export core integrations from Vercel edge SDK (#12…
lforst May 31, 2024
b4505d8
test: Refactor utils into `@sentry-internal/test-utils` (#12277)
mydea May 31, 2024
4772147
test: Refactor webpack E2E tests to avoid sending to Sentry (#12312)
mydea May 31, 2024
2cb5215
fix(replay): Avoid infinite loop of logs (#12309)
mydea May 31, 2024
66a8cf9
test(e2e): Streamline react-router-6-use-routes test (#12315)
mydea May 31, 2024
1880316
test(e2e): Update `react-router-6` test to avoid sending to Sentry (#…
mydea May 31, 2024
0ec8f82
test(aws-lambda): Add basic lambda layer e2e test (#12279)
Lms24 May 31, 2024
9ce85f7
fix(feedback): Override TriggerLabel Option (#12316)
c298lee May 31, 2024
84886c7
fix(nextjs): Fix version detection and option insertion logic for `cl…
ykzts Jun 3, 2024
119a923
ci(deps): bump pnpm/action-setup from 2 to 4 (#12320)
dependabot[bot] Jun 3, 2024
5494cb5
ref(browser): Ensure idle span ending is consistent (#12310)
mydea Jun 3, 2024
10833b0
feat(deps): Bump @sentry/cli from 2.31.2 to 2.32.1 (#12332)
dependabot[bot] Jun 3, 2024
761b9d2
ci: Fix sveltekit flakes (#12327)
lforst Jun 3, 2024
48b228c
feat(deps): Bump @opentelemetry/propagator-aws-xray from 1.3.1 to 1.2…
dependabot[bot] Jun 3, 2024
03f68d0
placeholder tests
c298lee May 31, 2024
0e110b1
Merge branch 'develop' into replay-web-vitals
c298lee Jun 4, 2024
087b0b3
linting
c298lee Jun 4, 2024
2436558
Merge branch 'develop' into replay-web-vitals
c298lee Jun 4, 2024
753c99b
fix inp import
c298lee Jun 4, 2024
7c34d01
format + update test
c298lee Jun 4, 2024
0cc8090
lint
c298lee Jun 4, 2024
f695f68
fix test
c298lee Jun 4, 2024
7772427
some PR comment refactor
c298lee Jun 6, 2024
aa04cf8
PR comments
c298lee Jun 6, 2024
f81ca6f
add inp to test
c298lee Jun 7, 2024
bdc7bca
typos & tests
c298lee Jun 7, 2024
27c53ee
lint & fix performance entry test
c298lee Jun 7, 2024
f523075
hopefully actually fixed some tests??
c298lee Jun 7, 2024
f21a812
remove inp from e2e test
c298lee Jun 7, 2024
3eaf3f9
try copying web-vitals-inp test?
c298lee Jun 7, 2024
a27fa22
Merge branch 'develop' into replay-web-vitals
c298lee Jun 7, 2024
39e20b2
add promise all to test
c298lee Jun 7, 2024
e7d7db0
rm await inside all
c298lee Jun 7, 2024
44590d1
remove inp from tests
c298lee Jun 7, 2024
4849a8f
get element from right place for other web vitals
c298lee Jun 7, 2024
98f29b5
Merge branch 'develop' into replay-web-vitals
c298lee Jun 7, 2024
f2a287b
forgot to update e2e test
c298lee Jun 7, 2024
738508a
add cls node
c298lee Jun 7, 2024
853ed14
lint
c298lee Jun 7, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { expect } from '@playwright/test';

import { sentryTest } from '../../../utils/fixtures';
import {
expectedCLSPerformanceSpan,
expectedClickBreadcrumb,
expectedFCPPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedLCPPerformanceSpan,
expectedMemoryPerformanceSpan,
Expand Down Expand Up @@ -62,6 +64,8 @@ sentryTest(
expect.arrayContaining([
expectedNavigationPerformanceSpan,
expectedLCPPerformanceSpan,
expectedCLSPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedFCPPerformanceSpan,
expectedMemoryPerformanceSpan, // two memory spans - once per flush
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { expect } from '@playwright/test';

import { sentryTest } from '../../../utils/fixtures';
import {
expectedCLSPerformanceSpan,
expectedClickBreadcrumb,
expectedFCPPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedLCPPerformanceSpan,
expectedMemoryPerformanceSpan,
Expand Down Expand Up @@ -78,11 +80,13 @@ sentryTest(
const collectedPerformanceSpans = [...recording0.performanceSpans, ...recording1.performanceSpans];
const collectedBreadcrumbs = [...recording0.breadcrumbs, ...recording1.breadcrumbs];

expect(collectedPerformanceSpans.length).toEqual(6);
expect(collectedPerformanceSpans.length).toEqual(8);
expect(collectedPerformanceSpans).toEqual(
expect.arrayContaining([
expectedNavigationPerformanceSpan,
expectedLCPPerformanceSpan,
expectedCLSPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedFCPPerformanceSpan,
expectedMemoryPerformanceSpan, // two memory spans - once per flush
Expand Down Expand Up @@ -116,11 +120,13 @@ sentryTest(
const collectedPerformanceSpansAfterReload = [...recording2.performanceSpans, ...recording3.performanceSpans];
const collectedBreadcrumbsAdterReload = [...recording2.breadcrumbs, ...recording3.breadcrumbs];

expect(collectedPerformanceSpansAfterReload.length).toEqual(6);
expect(collectedPerformanceSpansAfterReload.length).toEqual(8);
expect(collectedPerformanceSpansAfterReload).toEqual(
expect.arrayContaining([
expectedReloadPerformanceSpan,
expectedLCPPerformanceSpan,
expectedCLSPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedFCPPerformanceSpan,
expectedMemoryPerformanceSpan,
Expand Down Expand Up @@ -188,6 +194,8 @@ sentryTest(
expect.arrayContaining([
expectedNavigationPerformanceSpan,
expectedLCPPerformanceSpan,
expectedCLSPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedFCPPerformanceSpan,
expectedMemoryPerformanceSpan,
Expand Down Expand Up @@ -304,11 +312,13 @@ sentryTest(
];
const collectedBreadcrumbsAfterIndexNavigation = [...recording8.breadcrumbs, ...recording9.breadcrumbs];

expect(collectedPerformanceSpansAfterIndexNavigation.length).toEqual(6);
expect(collectedPerformanceSpansAfterIndexNavigation.length).toEqual(8);
expect(collectedPerformanceSpansAfterIndexNavigation).toEqual(
expect.arrayContaining([
expectedNavigationPerformanceSpan,
expectedLCPPerformanceSpan,
expectedCLSPerformanceSpan,
expectedFIDPerformanceSpan,
expectedFPPerformanceSpan,
expectedFCPPerformanceSpan,
expectedMemoryPerformanceSpan,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,56 @@ export const expectedMemoryPerformanceSpan = {
};

export const expectedLCPPerformanceSpan = {
op: 'largest-contentful-paint',
op: 'web-vital',
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
nodeId: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
},
};

export const expectedCLSPerformanceSpan = {
op: 'web-vital',
description: 'cumulative-layout-shift',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
},
};

export const expectedFIDPerformanceSpan = {
op: 'web-vital',
description: 'first-input-delay',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
nodeId: expect.any(Number),
},
};

export const expectedINPPerformanceSpan = {
op: 'web-vital',
description: 'interaction-to-next-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
nodeId: expect.any(Number),
},
};

export const expectedFCPPerformanceSpan = {
op: 'paint',
description: 'first-contentful-paint',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export const ReplayRecordingData = [
data: {
tag: 'performanceSpan',
payload: {
op: 'largest-contentful-paint',
op: 'web-vital',
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,56 @@ export const ReplayRecordingData = [
data: {
tag: 'performanceSpan',
payload: {
op: 'largest-contentful-paint',
op: 'web-vital',
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
nodeId: 16,
},
},
},
},
{
type: 5,
timestamp: expect.any(Number),
data: {
tag: 'performanceSpan',
payload: {
op: 'web-vital',
description: 'cumulative-layout-shift',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
},
},
},
},
{
type: 5,
timestamp: expect.any(Number),
data: {
tag: 'performanceSpan',
payload: {
op: 'web-vital',
description: 'first-input-delay',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
nodeId: 10,
},
},
},
},
{
type: 5,
timestamp: expect.any(Number),
Expand Down
1 change: 1 addition & 0 deletions packages/browser-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export {
addFidInstrumentationHandler,
addTtfbInstrumentationHandler,
addLcpInstrumentationHandler,
addInpInstrumentationHandler,
} from './metrics/instrument';

export {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { addLcpInstrumentationHandler, addPerformanceInstrumentationHandler } from '@sentry-internal/browser-utils';

import {
addClsInstrumentationHandler,
addFidInstrumentationHandler,
addInpInstrumentationHandler,
addLcpInstrumentationHandler,
addPerformanceInstrumentationHandler,
} from '@sentry-internal/browser-utils';
import type { ReplayContainer } from '../types';
import { getLargestContentfulPaint } from '../util/createPerformanceEntries';
import {
getCumulativeLayoutShift,
getFirstInputDelay,
getInteractionToNextPaint,
getLargestContentfulPaint,
webVitalHandler,
} from '../util/createPerformanceEntries';

/**
* Sets up a PerformanceObserver to listen to all performance entry types.
Expand All @@ -26,9 +37,10 @@ export function setupPerformanceObserver(replay: ReplayContainer): () => void {
});

clearCallbacks.push(
addLcpInstrumentationHandler(({ metric }) => {
replay.replayPerformanceEntries.push(getLargestContentfulPaint(metric));
}),
addLcpInstrumentationHandler(webVitalHandler(getLargestContentfulPaint, replay)),
addClsInstrumentationHandler(webVitalHandler(getCumulativeLayoutShift, replay)),
addFidInstrumentationHandler(webVitalHandler(getFirstInputDelay, replay)),
addInpInstrumentationHandler(webVitalHandler(getInteractionToNextPaint, replay)),
);

// A callback to cleanup all handlers
Expand Down
9 changes: 7 additions & 2 deletions packages/replay-internal/src/types/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,17 @@ export type ResourceData = Pick<PerformanceResourceTiming, 'decodedBodySize' | '
statusCode?: number;
};

export interface LargestContentfulPaintData {
export interface WebVitalData {
/**
* Render time (in ms) of the LCP
*/
value: number;
size: number;
/**
* The rating as to whether the metric value is within the "good",
* "needs improvement", or "poor" thresholds of the metric.
*/
rating: 'good' | 'needs-improvement' | 'poor';
/**
* The recording id of the LCP node. -1 if not found
*/
Expand All @@ -111,7 +116,7 @@ export interface LargestContentfulPaintData {
/**
* Entries that come from window.performance
*/
export type AllPerformanceEntryData = PaintData | NavigationData | ResourceData | LargestContentfulPaintData;
export type AllPerformanceEntryData = PaintData | NavigationData | ResourceData | WebVitalData;

export interface MemoryData {
memory: {
Expand Down
10 changes: 5 additions & 5 deletions packages/replay-internal/src/types/replayFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import type { Breadcrumb } from '@sentry/types';

import type {
HistoryData,
LargestContentfulPaintData,
MemoryData,
NavigationData,
NetworkRequestData,
PaintData,
ResourceData,
WebVitalData,
} from './performance';
import type { ReplayEventTypeCustom } from './rrweb';

Expand Down Expand Up @@ -162,9 +162,9 @@ interface ReplayHistoryFrame extends ReplayBaseSpanFrame {
op: 'navigation.push';
}

interface ReplayLargestContentfulPaintFrame extends ReplayBaseSpanFrame {
data: LargestContentfulPaintData;
op: 'largest-contentful-paint';
interface ReplayWebVitalFrame extends ReplayBaseSpanFrame {
data: WebVitalData;
op: 'largest-contentful-paint' | 'cumulative-layout-shift' | 'first-input-delay' | 'interaction-to-next-paint';
}

interface ReplayMemoryFrame extends ReplayBaseSpanFrame {
Expand Down Expand Up @@ -196,7 +196,7 @@ export type ReplaySpanFrame =
| ReplayBaseSpanFrame
| ReplayHistoryFrame
| ReplayRequestFrame
| ReplayLargestContentfulPaintFrame
| ReplayWebVitalFrame
| ReplayMemoryFrame
| ReplayNavigationFrame
| ReplayPaintFrame
Expand Down
Loading
Loading