Skip to content

Commit

Permalink
feat(browser): Add navigation activationStart timestamp to pageload…
Browse files Browse the repository at this point in the history
… span (#13658)

Add the navigation performance entry `activationStart` property as a span attribute to the
pageload span. The attribute is called `performance.activationStart` and it is measured in ms
relative to performance.timeOrigin.
  • Loading branch information
Lms24 committed Sep 13, 2024
1 parent 5d0094a commit 2140083
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,30 @@ sentryTest('paint web vitals values are greater than TTFB', async ({ browserName
expect(fpValue).toBeGreaterThanOrEqual(ttfbValue!);
});

sentryTest('captures time origin as span attribute', async ({ getLocalTestPath, page }) => {
// Only run in chromium to ensure all vitals are present
if (shouldSkipTracingTest()) {
sentryTest.skip();
}
sentryTest(
'captures time origin and navigation activationStart as span attributes',
async ({ getLocalTestPath, page }) => {
// Only run in chromium to ensure all vitals are present
if (shouldSkipTracingTest()) {
sentryTest.skip();
}

const url = await getLocalTestPath({ testDir: __dirname });
const [eventData] = await Promise.all([getFirstSentryEnvelopeRequest<Event>(page), page.goto(url)]);
const url = await getLocalTestPath({ testDir: __dirname });
const [eventData] = await Promise.all([getFirstSentryEnvelopeRequest<Event>(page), page.goto(url)]);

const timeOriginAttribute = eventData.contexts?.trace?.data?.['performance.timeOrigin'];
const transactionStartTimestamp = eventData.start_timestamp;
const timeOriginAttribute = eventData.contexts?.trace?.data?.['performance.timeOrigin'];
const activationStart = eventData.contexts?.trace?.data?.['performance.activationStart'];

expect(timeOriginAttribute).toBeDefined();
expect(transactionStartTimestamp).toBeDefined();
const transactionStartTimestamp = eventData.start_timestamp;

const delta = Math.abs(transactionStartTimestamp! - timeOriginAttribute);
expect(timeOriginAttribute).toBeDefined();
expect(transactionStartTimestamp).toBeDefined();

// The delta should be less than 1ms if this flakes, we should increase the threshold
expect(delta).toBeLessThanOrEqual(1);
});
const delta = Math.abs(transactionStartTimestamp! - timeOriginAttribute);

// The delta should be less than 1ms if this flakes, we should increase the threshold
expect(delta).toBeLessThanOrEqual(1);

expect(activationStart).toBeGreaterThanOrEqual(0);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ test('Captures a pageload transaction', async ({ page }) => {
'sentry.sample_rate': 1,
'sentry.source': 'route',
'performance.timeOrigin': expect.any(Number),
'performance.activationStart': expect.any(Number),
},
op: 'pageload',
span_id: expect.any(String),
Expand Down
9 changes: 9 additions & 0 deletions packages/browser-utils/src/metrics/browserMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
addTtfbInstrumentationHandler,
} from './instrument';
import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';
import { getActivationStart } from './web-vitals/lib/getActivationStart';
import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';
import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';

Expand Down Expand Up @@ -383,6 +384,14 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
// Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on
span.setAttribute('performance.timeOrigin', timeOrigin);

// In prerendering scenarios, where a page might be prefetched and pre-rendered before the user clicks the link,
// the navigation starts earlier than when the user clicks it. Web Vitals should always be based on the
// user-perceived time, so they are not reported from the actual start of the navigation, but rather from the
// time where the user actively started the navigation, for example by clicking a link.
// This is user action is called "activation" and the time between navigation and activation is stored in
// the `activationStart` attribute of the "navigation" PerformanceEntry.
span.setAttribute('performance.activationStart', getActivationStart());

_setWebVitalAttributes(span);
}

Expand Down

0 comments on commit 2140083

Please sign in to comment.