Skip to content

Commit

Permalink
update cls and add ttfb
Browse files Browse the repository at this point in the history
  • Loading branch information
c298lee committed Jul 19, 2024
1 parent eb23dc4 commit a83dcfd
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ export const expectedINPPerformanceSpan = {
},
};

export const expectedTTFB = {
op: 'web-vital',
description: 'time-to-first-byte',
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 @@ -4,13 +4,15 @@ import {
addInpInstrumentationHandler,
addLcpInstrumentationHandler,
addPerformanceInstrumentationHandler,
addTtfbInstrumentationHandler,
} from '@sentry-internal/browser-utils';
import type { ReplayContainer } from '../types';
import {
getCumulativeLayoutShift,
getFirstInputDelay,
getInteractionToNextPaint,
getLargestContentfulPaint,
getTimeToFirstByte,
webVitalHandler,
} from '../util/createPerformanceEntries';

Expand Down Expand Up @@ -41,6 +43,7 @@ export function setupPerformanceObserver(replay: ReplayContainer): () => void {
addClsInstrumentationHandler(webVitalHandler(getCumulativeLayoutShift, replay)),
addFidInstrumentationHandler(webVitalHandler(getFirstInputDelay, replay)),
addInpInstrumentationHandler(webVitalHandler(getInteractionToNextPaint, replay)),
addTtfbInstrumentationHandler(webVitalHandler(getTimeToFirstByte, replay)),
);

// A callback to cleanup all handlers
Expand Down
2 changes: 1 addition & 1 deletion packages/replay-internal/src/types/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export interface WebVitalData {
/**
* The recording id of the LCP node. -1 if not found
*/
nodeId?: number;
nodeId?: number | number[];
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/replay-internal/src/types/replayFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ interface ReplayHistoryFrame extends ReplayBaseSpanFrame {

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

interface ReplayMemoryFrame extends ReplayBaseSpanFrame {
Expand Down
43 changes: 33 additions & 10 deletions packages/replay-internal/src/util/createPerformanceEntries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,17 @@ export function getLargestContentfulPaint(metric: Metric): ReplayPerformanceEntr
* Add a CLS event to the replay based on a CLS metric.
*/
export function getCumulativeLayoutShift(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
// get first node that shifts
const firstEntry = metric.entries[0] as (PerformanceEntry & { sources?: LayoutShiftAttribution[] }) | undefined;
const node = firstEntry
? firstEntry.sources && firstEntry.sources[0]
? firstEntry.sources[0].node
: undefined
: undefined;
return getWebVital(metric, 'cumulative-layout-shift', node);
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { sources?: LayoutShiftAttribution[] }) | undefined;
const nodes: Node[] = [];
if (lastEntry && lastEntry.sources) {
for (const source of lastEntry.sources) {
if (source.node) {
nodes.push(source.node)
}

}
}
return getWebVital(metric, 'cumulative-layout-shift', nodes);
}

/**
Expand All @@ -219,19 +222,39 @@ export function getInteractionToNextPaint(metric: Metric): ReplayPerformanceEntr
return getWebVital(metric, 'interaction-to-next-paint', node);
}

/**
* Add a TTFB event to the replay based on an INP metric.
*/
export function getTimeToFirstByte(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { target?: Node }) | undefined;
const node = lastEntry ? lastEntry.target : undefined;
return getWebVital(metric, 'time-to-first-byte', node);
}

/**
* Add an web vital event to the replay based on the web vital metric.
*/
export function getWebVital(
metric: Metric,
name: string,
node: Node | undefined,
node: Node | Node[] | undefined,
): ReplayPerformanceEntry<WebVitalData> {
const value = metric.value;
const rating = metric.rating;

const end = getAbsoluteTime(value);

const nodeIds: number[] = [];
if (Array.isArray(node)) {
for (const n of node) {
nodeIds.push(record.mirror.getId(n));
}
} else {
if (node) {
nodeIds.push(record.mirror.getId(node))
}
}

const data: ReplayPerformanceEntry<WebVitalData> = {
type: 'web-vital',
name,
Expand All @@ -241,7 +264,7 @@ export function getWebVital(
value,
size: value,
rating,
nodeId: node ? record.mirror.getId(node) : undefined,
nodeId: nodeIds ? nodeIds : undefined,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getFirstInputDelay,
getInteractionToNextPaint,
getLargestContentfulPaint,
getTimeToFirstByte,
} from '../../../src/util/createPerformanceEntries';
import { PerformanceEntryNavigation } from '../../fixtures/performanceEntry/navigation';

Expand Down Expand Up @@ -147,4 +148,24 @@ describe('Unit | util | createPerformanceEntries', () => {
});
});
});

describe('getTimeToFirstByte', () => {
it('works with an TTFB metric', async () => {
const metric = {
value: 5108.299,
rating: 'good' as const,
entries: [],
};

const event = getTimeToFirstByte(metric);

expect(event).toEqual({
type: 'web-vital',
name: 'time-to-first-byte',
start: 1672531205.108299,
end: 1672531205.108299,
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
});
});
});
});

0 comments on commit a83dcfd

Please sign in to comment.