Skip to content

Commit e1592e9

Browse files
committed
ref: Extract instrument into dedicated methods
1 parent 8a2fdc5 commit e1592e9

File tree

5 files changed

+103
-76
lines changed

5 files changed

+103
-76
lines changed

packages/replay/src/coreHandlers/performanceObserver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addPerformanceInstrumentationHandler } from '@sentry-internal/tracing';
1+
import { addLcpInstrumentationHandler, addPerformanceInstrumentationHandler } from '@sentry-internal/tracing';
22

33
import type { ReplayContainer } from '../types';
44
import { getLargestContentfulPaint } from '../util/createPerformanceEntries';
@@ -26,7 +26,7 @@ export function setupPerformanceObserver(replay: ReplayContainer): () => void {
2626
});
2727

2828
clearCallbacks.push(
29-
addPerformanceInstrumentationHandler('lcp', ({ metric }) => {
29+
addLcpInstrumentationHandler(({ metric }) => {
3030
replay.replayPerformanceEntries.push(getLargestContentfulPaint(metric));
3131
}),
3232
);

packages/tracing-internal/src/browser/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@ export {
99
addTracingHeadersToFetchRequest,
1010
} from './request';
1111

12-
export { addPerformanceInstrumentationHandler } from './instrument';
12+
export {
13+
addPerformanceInstrumentationHandler,
14+
addClsInstrumentationHandler,
15+
addFidInstrumentationHandler,
16+
addLcpInstrumentationHandler,
17+
} from './instrument';

packages/tracing-internal/src/browser/instrument.ts

Lines changed: 83 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { observe } from './web-vitals/lib/observe';
77

88
type InstrumentHandlerTypePerformanceObserver = 'longtask' | 'event' | 'navigation' | 'paint' | 'resource';
99

10+
type InstrumentHandlerTypeMetric = 'cls' | 'lcp' | 'fid';
11+
1012
// We provide this here manually instead of relying on a global, as this is not available in non-browser environements
1113
// And we do not want to expose such types
1214
interface PerformanceEntry {
@@ -68,45 +70,42 @@ interface Metric {
6870
navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender';
6971
}
7072

71-
export type InstrumentHandlerType = 'cls' | 'lcp' | 'fid' | InstrumentHandlerTypePerformanceObserver;
73+
type InstrumentHandlerType = InstrumentHandlerTypeMetric | InstrumentHandlerTypePerformanceObserver;
7274

7375
// eslint-disable-next-line @typescript-eslint/no-explicit-any
74-
export type InstrumentHandlerCallback = (data: any) => void;
76+
type InstrumentHandlerCallback = (data: any) => void;
7577

7678
type CleanupHandlerCallback = () => void;
7779

7880
const handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};
7981
const instrumented: { [key in InstrumentHandlerType]?: boolean } = {};
8082

81-
/** Instruments given API */
82-
function instrument(type: InstrumentHandlerType): void {
83-
if (instrumented[type]) {
84-
return;
85-
}
83+
let _previousCls: Metric | undefined;
84+
let _previousFid: Metric | undefined;
85+
let _previousLcp: Metric | undefined;
8686

87-
instrumented[type] = true;
88-
89-
switch (type) {
90-
case 'cls':
91-
instrumentCls();
92-
break;
93-
case 'fid':
94-
instrumentFid();
95-
break;
96-
case 'lcp':
97-
instrumentLcp();
98-
break;
99-
case 'longtask':
100-
case 'event':
101-
case 'navigation':
102-
case 'paint':
103-
case 'resource':
104-
instrumentPerformanceObserver(type);
105-
break;
106-
default:
107-
__DEBUG_BUILD__ && logger.warn('unknown instrumentation type:', type);
108-
return;
109-
}
87+
/**
88+
* Add a callback that will be triggered when a CLS metric is available.
89+
* Returns a cleanup callback which can be called to remove the instrumentation handler.
90+
*/
91+
export function addClsInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {
92+
return addMetricObserver('cls', callback, instrumentCls, _previousCls);
93+
}
94+
95+
/**
96+
* Add a callback that will be triggered when a LCP metric is available.
97+
* Returns a cleanup callback which can be called to remove the instrumentation handler.
98+
*/
99+
export function addLcpInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {
100+
return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp);
101+
}
102+
103+
/**
104+
* Add a callback that will be triggered when a FID metric is available.
105+
* Returns a cleanup callback which can be called to remove the instrumentation handler.
106+
*/
107+
export function addFidInstrumentationHandler(callback: (data: { metric: Metric }) => void): CleanupHandlerCallback {
108+
return addMetricObserver('fid', callback, instrumentFid, _previousFid);
110109
}
111110

112111
export function addPerformanceInstrumentationHandler(
@@ -117,48 +116,24 @@ export function addPerformanceInstrumentationHandler(
117116
type: InstrumentHandlerTypePerformanceObserver,
118117
callback: (data: { entries: PerformanceEntry[] }) => void,
119118
): CleanupHandlerCallback;
120-
export function addPerformanceInstrumentationHandler(
121-
type: 'lcp' | 'cls' | 'fid',
122-
callback: (data: { metric: Metric }) => void,
123-
): CleanupHandlerCallback;
124119

125120
/**
126-
* Add handler that will be called when given type of instrumentation triggers.
127-
* Use at your own risk, this might break without changelog notice, only used internally.
128-
* @hidden
121+
* Add a callback that will be triggered when a performance observer is triggered,
122+
* and receives the entries of the observer.
123+
* Returns a cleanup callback which can be called to remove the instrumentation handler.
129124
*/
130125
export function addPerformanceInstrumentationHandler(
131-
type: InstrumentHandlerType,
132-
callback: InstrumentHandlerCallback,
126+
type: InstrumentHandlerTypePerformanceObserver,
127+
callback: (data: { entries: PerformanceEntry[] }) => void,
133128
): CleanupHandlerCallback {
134-
handlers[type] = handlers[type] || [];
135-
(handlers[type] as InstrumentHandlerCallback[]).push(callback);
136-
instrument(type);
129+
addHandler(type, callback);
137130

138-
// Metrics may have been sent before, in which case we still want to trigger callbacks
139-
if (type === 'cls' && _previousCls) {
140-
callback({ metric: _previousCls });
141-
}
142-
if (type === 'fid' && _previousFid) {
143-
callback({ metric: _previousFid });
144-
}
145-
if (type === 'lcp' && _previousLcp) {
146-
callback({ metric: _previousLcp });
131+
if (!instrumented[type]) {
132+
instrumentPerformanceObserver(type);
133+
instrumented[type] = true;
147134
}
148135

149-
// Return a function to remove the handler
150-
return () => {
151-
const typeHandlers = handlers[type];
152-
153-
if (!typeHandlers) {
154-
return;
155-
}
156-
157-
const index = typeHandlers.indexOf(callback);
158-
if (index !== -1) {
159-
typeHandlers.splice(index, 1);
160-
}
161-
};
136+
return getCleanupCallback(type, callback);
162137
}
163138

164139
/** Trigger all handlers of a given type. */
@@ -182,13 +157,11 @@ function triggerHandlers(type: InstrumentHandlerType, data: unknown): void {
182157
}
183158
}
184159

185-
let _previousCls: Metric | undefined;
186-
let _previousFid: Metric | undefined;
187-
let _previousLcp: Metric | undefined;
188-
189160
function instrumentCls(): void {
190161
onCLS(metric => {
191-
triggerHandlers('cls', { metric });
162+
triggerHandlers('cls', {
163+
metric,
164+
});
192165
_previousCls = metric;
193166
});
194167
}
@@ -211,6 +184,26 @@ function instrumentLcp(): void {
211184
});
212185
}
213186

187+
function addMetricObserver(
188+
type: InstrumentHandlerTypeMetric,
189+
callback: InstrumentHandlerCallback,
190+
instrumentFn: () => void,
191+
previousValue: Metric | undefined,
192+
): CleanupHandlerCallback {
193+
addHandler(type, callback);
194+
195+
if (!instrumented[type]) {
196+
instrumentFn();
197+
instrumented[type] = true;
198+
}
199+
200+
if (previousValue) {
201+
callback({ metric: previousValue });
202+
}
203+
204+
return getCleanupCallback(type, callback);
205+
}
206+
214207
function instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObserver): void {
215208
const options: PerformanceObserverInit = {};
216209

@@ -227,3 +220,24 @@ function instrumentPerformanceObserver(type: InstrumentHandlerTypePerformanceObs
227220
options,
228221
);
229222
}
223+
224+
function addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {
225+
handlers[type] = handlers[type] || [];
226+
(handlers[type] as InstrumentHandlerCallback[]).push(handler);
227+
}
228+
229+
// Get a callback which can be called to remove the instrumentation handler
230+
function getCleanupCallback(type: InstrumentHandlerType, callback: InstrumentHandlerCallback): CleanupHandlerCallback {
231+
return () => {
232+
const typeHandlers = handlers[type];
233+
234+
if (!typeHandlers) {
235+
return;
236+
}
237+
238+
const index = typeHandlers.indexOf(callback);
239+
if (index !== -1) {
240+
typeHandlers.splice(index, 1);
241+
}
242+
};
243+
}

packages/tracing-internal/src/browser/metrics/index.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { getActiveTransaction } from '@sentry/core';
44
import type { Measurements } from '@sentry/types';
55
import { browserPerformanceTimeOrigin, htmlTreeAsString, logger } from '@sentry/utils';
66

7-
import { addPerformanceInstrumentationHandler } from '../instrument';
7+
import {
8+
addClsInstrumentationHandler,
9+
addFidInstrumentationHandler,
10+
addLcpInstrumentationHandler,
11+
addPerformanceInstrumentationHandler,
12+
} from '../instrument';
813
import { WINDOW } from '../types';
914
import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher';
1015
import type { NavigatorDeviceMemory, NavigatorNetworkInformation } from '../web-vitals/types';
@@ -108,7 +113,7 @@ export function startTrackingInteractions(): void {
108113

109114
/** Starts tracking the Cumulative Layout Shift on the current page. */
110115
function _trackCLS(): () => void {
111-
return addPerformanceInstrumentationHandler('cls', ({ metric }) => {
116+
return addClsInstrumentationHandler(({ metric }) => {
112117
const entry = metric.entries.pop();
113118
if (!entry) {
114119
return;
@@ -122,7 +127,7 @@ function _trackCLS(): () => void {
122127

123128
/** Starts tracking the Largest Contentful Paint on the current page. */
124129
function _trackLCP(): () => void {
125-
return addPerformanceInstrumentationHandler('lcp', ({ metric }) => {
130+
return addLcpInstrumentationHandler(({ metric }) => {
126131
const entry = metric.entries.pop();
127132
if (!entry) {
128133
return;
@@ -136,7 +141,7 @@ function _trackLCP(): () => void {
136141

137142
/** Starts tracking the First Input Delay on the current page. */
138143
function _trackFID(): () => void {
139-
return addPerformanceInstrumentationHandler('fid', ({ metric }) => {
144+
return addFidInstrumentationHandler(({ metric }) => {
140145
const entry = metric.entries.pop();
141146
if (!entry) {
142147
return;

packages/tracing-internal/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export {
1919
defaultRequestInstrumentationOptions,
2020
addTracingHeadersToFetchRequest,
2121
addPerformanceInstrumentationHandler,
22+
addClsInstrumentationHandler,
23+
addFidInstrumentationHandler,
24+
addLcpInstrumentationHandler,
2225
} from './browser';
2326

2427
export type { RequestInstrumentationOptions } from './browser';

0 commit comments

Comments
 (0)