Skip to content

Commit b4efa21

Browse files
authored
ref(replay): Hide internal replay tracing behind experiments flag (#6487)
1 parent 867c731 commit b4efa21

11 files changed

+100
-108
lines changed

packages/replay/src/coreHandlers/handleFetch.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ReplayPerformanceEntry } from '../createPerformanceEntry';
22
import type { ReplayContainer } from '../types';
33
import { createPerformanceSpans } from '../util/createPerformanceSpans';
4-
import { isIngestHost } from '../util/isIngestHost';
4+
import { shouldFilterRequest } from '../util/shouldFilterRequest';
55

66
interface FetchHandlerData {
77
args: Parameters<typeof fetch>;
@@ -28,11 +28,6 @@ export function handleFetch(handlerData: FetchHandlerData): null | ReplayPerform
2828

2929
const { startTimestamp, endTimestamp, fetchData, response } = handlerData;
3030

31-
// Do not capture fetches to Sentry ingestion endpoint
32-
if (isIngestHost(fetchData.url)) {
33-
return null;
34-
}
35-
3631
return {
3732
type: 'resource.fetch',
3833
start: startTimestamp / 1000,
@@ -60,6 +55,10 @@ export function handleFetchSpanListener(replay: ReplayContainer): (handlerData:
6055
return;
6156
}
6257

58+
if (shouldFilterRequest(replay, result.name)) {
59+
return;
60+
}
61+
6362
replay.addUpdate(() => {
6463
createPerformanceSpans(replay, [result]);
6564
// Returning true will cause `addUpdate` to not flush

packages/replay/src/coreHandlers/handleGlobalEvent.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import { addBreadcrumb } from '@sentry/core';
12
import { Event } from '@sentry/types';
23

34
import { REPLAY_EVENT_NAME, UNABLE_TO_SEND_REPLAY } from '../constants';
45
import type { ReplayContainer } from '../types';
5-
import { addInternalBreadcrumb } from '../util/addInternalBreadcrumb';
66

77
/**
88
* Returns a listener to be added to `addGlobalEventProcessor(listener)`.
@@ -39,11 +39,13 @@ export function handleGlobalEventListener(replay: ReplayContainer): (event: Even
3939
}
4040

4141
const exc = event.exception?.values?.[0];
42-
addInternalBreadcrumb({
43-
message: `Tagging event (${event.event_id}) - ${event.message} - ${exc?.type || 'Unknown'}: ${
44-
exc?.value || 'n/a'
45-
}`,
46-
});
42+
if (__DEBUG_BUILD__ && replay.getOptions()._experiments?.traceInternals) {
43+
addInternalBreadcrumb({
44+
message: `Tagging event (${event.event_id}) - ${event.message} - ${exc?.type || 'Unknown'}: ${
45+
exc?.value || 'n/a'
46+
}`,
47+
});
48+
}
4749

4850
// Need to be very careful that this does not cause an infinite loop
4951
if (
@@ -70,3 +72,14 @@ export function handleGlobalEventListener(replay: ReplayContainer): (event: Even
7072
return event;
7173
};
7274
}
75+
76+
function addInternalBreadcrumb(arg: Parameters<typeof addBreadcrumb>[0]): void {
77+
const { category, level, message, ...rest } = arg;
78+
79+
addBreadcrumb({
80+
category: category || 'console',
81+
level: level || 'debug',
82+
message: `[debug]: ${message}`,
83+
...rest,
84+
});
85+
}

packages/replay/src/coreHandlers/handleXhr.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ReplayPerformanceEntry } from '../createPerformanceEntry';
22
import type { ReplayContainer } from '../types';
33
import { createPerformanceSpans } from '../util/createPerformanceSpans';
4-
import { isIngestHost } from '../util/isIngestHost';
4+
import { shouldFilterRequest } from '../util/shouldFilterRequest';
55

66
// From sentry-javascript
77
// e.g. https://github.com/getsentry/sentry-javascript/blob/c7fc025bf9fa8c073fdb56351808ce53909fbe45/packages/utils/src/instrument.ts#L180
@@ -47,8 +47,7 @@ function handleXhr(handlerData: XhrHandlerData): ReplayPerformanceEntry | null {
4747

4848
const { method, url, status_code: statusCode } = handlerData.xhr.__sentry_xhr__ || {};
4949

50-
// Do not capture fetches to Sentry ingestion endpoint
51-
if (url === undefined || isIngestHost(url)) {
50+
if (url === undefined) {
5251
return null;
5352
}
5453

@@ -79,6 +78,10 @@ export function handleXhrSpanListener(replay: ReplayContainer): (handlerData: Xh
7978
return;
8079
}
8180

81+
if (shouldFilterRequest(replay, result.name)) {
82+
return;
83+
}
84+
8285
replay.addUpdate(() => {
8386
createPerformanceSpans(replay, [result]);
8487
// Returning true will cause `addUpdate` to not flush

packages/replay/src/createPerformanceEntry.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { record } from 'rrweb';
33

44
import { WINDOW } from './constants';
55
import type { AllPerformanceEntry, PerformanceNavigationTiming, PerformancePaintTiming } from './types';
6-
import { isIngestHost } from './util/isIngestHost';
76

87
export interface ReplayPerformanceEntry {
98
/**
@@ -110,11 +109,6 @@ function createNavigationEntry(entry: PerformanceNavigationTiming) {
110109
function createResourceEntry(entry: PerformanceResourceTiming) {
111110
const { entryType, initiatorType, name, responseEnd, startTime, encodedBodySize, transferSize } = entry;
112111

113-
// Do not capture fetches to Sentry ingestion endpoint
114-
if (isIngestHost(name)) {
115-
return null;
116-
}
117-
118112
// Core SDK handles these
119113
if (['fetch', 'xmlhttprequest'].includes(initiatorType)) {
120114
return null;

packages/replay/src/replay.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ export class ReplayContainer implements ReplayContainerInterface {
7575
/**
7676
* Options to pass to `rrweb.record()`
7777
*/
78-
readonly recordingOptions: RecordingOptions;
78+
private readonly _recordingOptions: RecordingOptions;
7979

80-
readonly options: ReplayPluginOptions;
80+
private readonly _options: ReplayPluginOptions;
8181

8282
private _performanceObserver: PerformanceObserver | null = null;
8383

@@ -125,11 +125,11 @@ export class ReplayContainer implements ReplayContainerInterface {
125125
};
126126

127127
constructor({ options, recordingOptions }: { options: ReplayPluginOptions; recordingOptions: RecordingOptions }) {
128-
this.recordingOptions = recordingOptions;
129-
this.options = options;
128+
this._recordingOptions = recordingOptions;
129+
this._options = options;
130130

131-
this._debouncedFlush = debounce(() => this.flush(), this.options.flushMinDelay, {
132-
maxWait: this.options.flushMaxDelay,
131+
this._debouncedFlush = debounce(() => this.flush(), this._options.flushMinDelay, {
132+
maxWait: this._options.flushMaxDelay,
133133
});
134134
}
135135

@@ -148,6 +148,11 @@ export class ReplayContainer implements ReplayContainerInterface {
148148
return this._isPaused;
149149
}
150150

151+
/** Get the replay integration options. */
152+
public getOptions(): ReplayPluginOptions {
153+
return this._options;
154+
}
155+
151156
/**
152157
* Initializes the plugin.
153158
*
@@ -183,7 +188,7 @@ export class ReplayContainer implements ReplayContainerInterface {
183188
this.updateSessionActivity();
184189

185190
this.eventBuffer = createEventBuffer({
186-
useCompression: Boolean(this.options.useCompression),
191+
useCompression: Boolean(this._options.useCompression),
187192
});
188193

189194
this.addListeners();
@@ -201,7 +206,7 @@ export class ReplayContainer implements ReplayContainerInterface {
201206
startRecording(): void {
202207
try {
203208
this._stopRecording = record({
204-
...this.recordingOptions,
209+
...this._recordingOptions,
205210
// When running in error sampling mode, we need to overwrite `checkoutEveryNth`
206211
// Without this, it would record forever, until an error happens, which we don't want
207212
// instead, we'll always keep the last 60 seconds of replay before an error happened
@@ -275,7 +280,7 @@ export class ReplayContainer implements ReplayContainerInterface {
275280
handleException(error: unknown): void {
276281
__DEBUG_BUILD__ && logger.error('[Replay]', error);
277282

278-
if (this.options._experiments && this.options._experiments.captureExceptions) {
283+
if (__DEBUG_BUILD__ && this._options._experiments && this._options._experiments.captureExceptions) {
279284
captureException(error);
280285
}
281286
}
@@ -297,10 +302,10 @@ export class ReplayContainer implements ReplayContainerInterface {
297302
loadSession({ expiry }: { expiry: number }): void {
298303
const { type, session } = getSession({
299304
expiry,
300-
stickySession: Boolean(this.options.stickySession),
305+
stickySession: Boolean(this._options.stickySession),
301306
currentSession: this.session,
302-
sessionSampleRate: this.options.sessionSampleRate,
303-
errorSampleRate: this.options.errorSampleRate,
307+
sessionSampleRate: this._options.sessionSampleRate,
308+
errorSampleRate: this._options.errorSampleRate,
304309
});
305310

306311
// If session was newly created (i.e. was not loaded from storage), then
@@ -482,7 +487,7 @@ export class ReplayContainer implements ReplayContainerInterface {
482487
// a previous session ID. In this case, we want to buffer events
483488
// for a set amount of time before flushing. This can help avoid
484489
// capturing replays of users that immediately close the window.
485-
setTimeout(() => this.conditionalFlush(), this.options.initialFlushDelay);
490+
setTimeout(() => this.conditionalFlush(), this._options.initialFlushDelay);
486491

487492
// Cancel any previously debounced flushes to ensure there are no [near]
488493
// simultaneous flushes happening. The latter request should be
@@ -955,8 +960,8 @@ export class ReplayContainer implements ReplayContainerInterface {
955960

956961
preparedEvent.tags = {
957962
...preparedEvent.tags,
958-
sessionSampleRate: this.options.sessionSampleRate,
959-
errorSampleRate: this.options.errorSampleRate,
963+
sessionSampleRate: this._options.sessionSampleRate,
964+
errorSampleRate: this._options.errorSampleRate,
960965
replayType: this.session?.sampled,
961966
};
962967

@@ -1061,7 +1066,7 @@ export class ReplayContainer implements ReplayContainerInterface {
10611066

10621067
/** Save the session, if it is sticky */
10631068
private _maybeSaveSession(): void {
1064-
if (this.session && this.options.stickySession) {
1069+
if (this.session && this._options.stickySession) {
10651070
saveSession(this.session);
10661071
}
10671072
}

packages/replay/src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ export interface ReplayPluginOptions extends SessionOptions {
115115
*
116116
* Default: undefined
117117
*/
118-
_experiments?: Partial<{ captureExceptions: boolean }>;
118+
_experiments?: Partial<{
119+
captureExceptions: boolean;
120+
traceInternals: boolean;
121+
}>;
119122
}
120123

121124
// These are optional for ReplayPluginOptions because the plugin sets default values
@@ -230,4 +233,5 @@ export interface ReplayContainer {
230233
flushImmediate(): void;
231234
triggerUserActivity(): void;
232235
addUpdate(cb: AddUpdateCallback): void;
236+
getOptions(): ReplayPluginOptions;
233237
}

packages/replay/src/util/addInternalBreadcrumb.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

packages/replay/src/util/isIngestHost.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

packages/replay/src/util/isInternal.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { getCurrentHub } from '@sentry/core';
2+
3+
import type { ReplayContainer } from '../types';
4+
5+
/**
6+
* Check whether a given request URL should be filtered out.
7+
*/
8+
export function shouldFilterRequest(replay: ReplayContainer, url: string): boolean {
9+
// If we enabled the `traceInternals` experiment, we want to trace everything
10+
if (__DEBUG_BUILD__ && replay.getOptions()._experiments?.traceInternals) {
11+
return false;
12+
}
13+
14+
return !_isSentryRequest(url);
15+
}
16+
17+
/**
18+
* Checks wether a given URL belongs to the configured Sentry DSN.
19+
*/
20+
function _isSentryRequest(url: string): boolean {
21+
const dsn = getCurrentHub().getClient()?.getDsn();
22+
return dsn ? url.includes(dsn.host) : false;
23+
}

0 commit comments

Comments
 (0)