Skip to content

feat(replay): Add responseStatus, decodedBodySize to perf entries #7613

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 9 commits into from
Mar 27, 2023
Merged
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
18 changes: 18 additions & 0 deletions packages/browser-integration-tests/utils/replayEventTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,16 @@ export const expectedNavigationPerformanceSpan = {
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
decodedBodySize: expect.any(Number),
encodedBodySize: expect.any(Number),
duration: expect.any(Number),
domInteractive: expect.any(Number),
domContentLoadedEventEnd: expect.any(Number),
domContentLoadedEventStart: expect.any(Number),
loadEventStart: expect.any(Number),
loadEventEnd: expect.any(Number),
domComplete: expect.any(Number),
redirectCount: expect.any(Number),
size: expect.any(Number),
},
};
Expand All @@ -85,7 +94,16 @@ export const expectedReloadPerformanceSpan = {
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: {
decodedBodySize: expect.any(Number),
encodedBodySize: expect.any(Number),
duration: expect.any(Number),
domInteractive: expect.any(Number),
domContentLoadedEventEnd: expect.any(Number),
domContentLoadedEventStart: expect.any(Number),
loadEventStart: expect.any(Number),
loadEventEnd: expect.any(Number),
domComplete: expect.any(Number),
redirectCount: expect.any(Number),
size: expect.any(Number),
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,19 @@ export const ReplayRecordingData = [
description: 'http://localhost:3000/',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: { size: expect.any(Number), duration: expect.any(Number) },
data: {
decodedBodySize: expect.any(Number),
encodedBodySize: expect.any(Number),
duration: expect.any(Number),
domInteractive: expect.any(Number),
domContentLoadedEventEnd: expect.any(Number),
domContentLoadedEventStart: expect.any(Number),
loadEventStart: expect.any(Number),
loadEventEnd: expect.any(Number),
domComplete: expect.any(Number),
redirectCount: expect.any(Number),
size: expect.any(Number),
},
},
},
},
Expand All @@ -157,7 +169,11 @@ export const ReplayRecordingData = [
description: expect.stringMatching(/http:\/\/localhost:3000\/static\/js\/main.(\w+).js/),
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: { size: expect.any(Number), encodedBodySize: expect.any(Number) },
data: {
decodedBodySize: expect.any(Number),
encodedBodySize: expect.any(Number),
size: expect.any(Number),
},
},
},
},
Expand Down
7 changes: 5 additions & 2 deletions packages/replay/src/coreHandlers/addNetworkBreadcrumb.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { NetworkRequestData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { createPerformanceSpans } from '../util/createPerformanceSpans';
import { shouldFilterRequest } from '../util/shouldFilterRequest';

/** Add a performance entry breadcrumb */
export function addNetworkBreadcrumb(replay: ReplayContainer, result: ReplayPerformanceEntry | null): void {
export function addNetworkBreadcrumb(
replay: ReplayContainer,
result: ReplayPerformanceEntry<NetworkRequestData> | null,
): void {
if (!replay.isEnabled()) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/replay/src/coreHandlers/handleFetch.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { HandlerDataFetch } from '@sentry/types';

import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { NetworkRequestData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { addNetworkBreadcrumb } from './addNetworkBreadcrumb';

/** only exported for tests */
export function handleFetch(handlerData: HandlerDataFetch): null | ReplayPerformanceEntry {
export function handleFetch(handlerData: HandlerDataFetch): null | ReplayPerformanceEntry<NetworkRequestData> {
const { startTimestamp, endTimestamp, fetchData, response } = handlerData;

if (!endTimestamp) {
Expand Down
4 changes: 2 additions & 2 deletions packages/replay/src/coreHandlers/handleHistory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { HistoryData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { createPerformanceSpans } from '../util/createPerformanceSpans';

interface HistoryHandlerData {
from: string;
to: string;
}

function handleHistory(handlerData: HistoryHandlerData): ReplayPerformanceEntry {
function handleHistory(handlerData: HistoryHandlerData): ReplayPerformanceEntry<HistoryData> {
const { from, to } = handlerData;

const now = Date.now() / 1000;
Expand Down
6 changes: 3 additions & 3 deletions packages/replay/src/coreHandlers/handleNetworkBreadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
} from '@sentry/types';
import { addInstrumentationHandler, logger } from '@sentry/utils';

import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { NetworkRequestData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { addNetworkBreadcrumb } from './addNetworkBreadcrumb';
import { handleFetchSpanListener } from './handleFetch';
import { handleXhrSpanListener } from './handleXhr';
Expand Down Expand Up @@ -148,7 +148,7 @@ function _makeNetworkReplayBreadcrumb(
type: string,
breadcrumb: Breadcrumb & { data: FetchBreadcrumbData | XhrBreadcrumbData },
hint: FetchBreadcrumbHint | XhrBreadcrumbHint,
): ReplayPerformanceEntry | null {
): ReplayPerformanceEntry<NetworkRequestData> | null {
const { startTimestamp, endTimestamp } = hint;

if (!endTimestamp) {
Expand All @@ -167,7 +167,7 @@ function _makeNetworkReplayBreadcrumb(
return null;
}

const result: ReplayPerformanceEntry & { data: object } = {
const result: ReplayPerformanceEntry<NetworkRequestData> = {
type,
start: startTimestamp / 1000,
end: endTimestamp / 1000,
Expand Down
4 changes: 2 additions & 2 deletions packages/replay/src/coreHandlers/handleXhr.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { HandlerDataXhr } from '@sentry/types';

import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { NetworkRequestData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { addNetworkBreadcrumb } from './addNetworkBreadcrumb';

/** only exported for tests */
export function handleXhr(handlerData: HandlerDataXhr): ReplayPerformanceEntry | null {
export function handleXhr(handlerData: HandlerDataXhr): ReplayPerformanceEntry<NetworkRequestData> | null {
const { startTimestamp, endTimestamp, xhr } = handlerData;

if (!startTimestamp || !endTimestamp || !xhr.__sentry_xhr__) {
Expand Down
136 changes: 130 additions & 6 deletions packages/replay/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,135 @@ export interface WorkerRequest {
// PerformancePaintTiming and PerformanceNavigationTiming are only available with TS 4.4 and newer
// Therefore, we're exporting them here to make them available in older TS versions
export type PerformancePaintTiming = PerformanceEntry;
export type PerformanceNavigationTiming = PerformanceEntry & {
type: string;
transferSize: number;
domComplete: number;
export type PerformanceNavigationTiming = PerformanceEntry &
PerformanceResourceTiming & {
type: string;
transferSize: number;

/**
* A DOMHighResTimeStamp representing the time immediately before the user agent
* sets the document's readyState to "interactive".
*/
domInteractive: number;

/**
* A DOMHighResTimeStamp representing the time immediately before the current
* document's DOMContentLoaded event handler starts.
*/
domContentLoadedEventStart: number;
/**
* A DOMHighResTimeStamp representing the time immediately after the current
* document's DOMContentLoaded event handler completes.
*/
domContentLoadedEventEnd: number;

/**
* A DOMHighResTimeStamp representing the time immediately before the current
* document's load event handler starts.
*/
loadEventStart: number;

/**
* A DOMHighResTimeStamp representing the time immediately after the current
* document's load event handler completes.
*/
loadEventEnd: number;

/**
* A DOMHighResTimeStamp representing the time immediately before the user agent
* sets the document's readyState to "complete".
*/
domComplete: number;

/**
* A number representing the number of redirects since the last non-redirect
* navigation in the current browsing context.
*/
redirectCount: number;
};
export type ExperimentalPerformanceResourceTiming = PerformanceResourceTiming & {
// Experimental, see: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus
// Requires Chrome 109
responseStatus?: number;
};

export type PaintData = undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems a bit weird? Should this be undefined?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it is a bit weird but we don't attach data for paint, so those breadcrumbs will not have a data attribute at all


/**
* See https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
*
* Note `navigation.push` will not have any data
*/
export type NavigationData = Partial<
Pick<
PerformanceNavigationTiming,
| 'decodedBodySize'
| 'encodedBodySize'
| 'duration'
| 'domInteractive'
| 'domContentLoadedEventEnd'
| 'domContentLoadedEventStart'
| 'loadEventStart'
| 'loadEventEnd'
| 'domComplete'
| 'redirectCount'
>
> & {
/**
* Transfer size of resource
*/
size?: number;
};

export type ResourceData = Pick<PerformanceResourceTiming, 'decodedBodySize' | 'encodedBodySize'> & {
/**
* Transfer size of resource
*/
size: number;
/**
* HTTP status code. Note this is experimental and not available on all browsers.
*/
statusCode?: number;
};

export interface LargestContentfulPaintData {
/**
* Render time (in ms) of the LCP
*/
value: number;
size: number;
/**
* The recording id of the LCP node. -1 if not found
*/
nodeId?: number;
}

/**
* Entries that come from window.performance
*/
export type AllPerformanceEntryData = PaintData | NavigationData | ResourceData | LargestContentfulPaintData;

export interface MemoryData {
memory: {
jsHeapSizeLimit: number;
totalJSHeapSize: number;
usedJSHeapSize: number;
};
}

export interface NetworkRequestData {
method?: string;
statusCode?: number;
requestBodySize?: number;
responseBodySize?: number;
}

export interface HistoryData {
previous: string;
}

export type AllEntryData = AllPerformanceEntryData | MemoryData | NetworkRequestData | HistoryData;

/**
* The response from the worker
*/
Expand Down Expand Up @@ -319,7 +443,7 @@ export interface ReplayContainer {
setInitialState(): void;
}

export interface ReplayPerformanceEntry {
export interface ReplayPerformanceEntry<T> {
/**
* One of these types https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/entryType
*/
Expand All @@ -343,5 +467,5 @@ export interface ReplayPerformanceEntry {
/**
* Additional unstructured data to be included
*/
data?: Record<string, unknown>;
data: T;
}
4 changes: 2 additions & 2 deletions packages/replay/src/util/addMemoryEntry.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { WINDOW } from '../constants';
import type { AddEventResult, ReplayContainer, ReplayPerformanceEntry } from '../types';
import type { AddEventResult, MemoryData, ReplayContainer, ReplayPerformanceEntry } from '../types';
import { createPerformanceSpans } from './createPerformanceSpans';

type ReplayMemoryEntry = ReplayPerformanceEntry & { data: { memory: MemoryInfo } };
type ReplayMemoryEntry = ReplayPerformanceEntry<MemoryData> & { data: { memory: MemoryInfo } };

interface MemoryInfo {
jsHeapSizeLimit: number;
Expand Down
Loading