Skip to content

Commit 553b49c

Browse files
committed
fix(replay): Ensure dropped errors are removed from replay reference
1 parent f19949c commit 553b49c

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

packages/replay/src/index.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable max-lines */ // TODO: We might want to split this file up
22
import { addGlobalEventProcessor, getCurrentHub, Scope, setContext } from '@sentry/core';
3-
import { Breadcrumb, Client, Event, Integration } from '@sentry/types';
3+
import { Breadcrumb, Client, DataCategory, Event, EventDropReason, Integration } from '@sentry/types';
44
import { addInstrumentationHandler, createEnvelope, logger } from '@sentry/utils';
55
import debounce from 'lodash.debounce';
66
import { PerformanceObserverEntryList } from 'perf_hooks';
@@ -125,6 +125,11 @@ export class Replay implements Integration {
125125
*/
126126
private stopRecording: ReturnType<typeof record> | null = null;
127127

128+
/**
129+
* We overwrite `client.recordDroppedEvent`, but store the original method here so we can restore it.
130+
*/
131+
private _originalRecordDroppedEvent?: Client['recordDroppedEvent'];
132+
128133
private context: InternalEventContext = {
129134
errorIds: new Set(),
130135
traceIds: new Set(),
@@ -400,6 +405,9 @@ export class Replay implements Integration {
400405
WINDOW.addEventListener('blur', this.handleWindowBlur);
401406
WINDOW.addEventListener('focus', this.handleWindowFocus);
402407

408+
// We need to filter out dropped events captured by `addGlobalEventProcessor(this.handleGlobalEvent)` below
409+
this._overwriteRecordDroppedEvent();
410+
403411
// There is no way to remove these listeners, so ensure they are only added once
404412
if (!this.hasInitializedCoreListeners) {
405413
// Listeners from core SDK //
@@ -462,6 +470,8 @@ export class Replay implements Integration {
462470
WINDOW.removeEventListener('blur', this.handleWindowBlur);
463471
WINDOW.removeEventListener('focus', this.handleWindowFocus);
464472

473+
this._restoreRecordDroppedEvent();
474+
465475
if (this.performanceObserver) {
466476
this.performanceObserver.disconnect();
467477
this.performanceObserver = null;
@@ -1333,4 +1343,39 @@ export class Replay implements Integration {
13331343
saveSession(this.session);
13341344
}
13351345
}
1346+
1347+
private _overwriteRecordDroppedEvent(): void {
1348+
const client = getCurrentHub().getClient();
1349+
1350+
if (!client) {
1351+
return;
1352+
}
1353+
1354+
const _originalCallback = client.recordDroppedEvent.bind(client);
1355+
1356+
const recordDroppedEvent: Client['recordDroppedEvent'] = (
1357+
reason: EventDropReason,
1358+
category: DataCategory,
1359+
event?: Event,
1360+
): void => {
1361+
if (event && event.event_id) {
1362+
this.context.errorIds.delete(event.event_id);
1363+
}
1364+
1365+
return _originalCallback(reason, category, event);
1366+
};
1367+
1368+
client.recordDroppedEvent = recordDroppedEvent;
1369+
this._originalRecordDroppedEvent = _originalCallback;
1370+
}
1371+
1372+
private _restoreRecordDroppedEvent(): void {
1373+
const client = getCurrentHub().getClient();
1374+
1375+
if (!client || !this._originalRecordDroppedEvent) {
1376+
return;
1377+
}
1378+
1379+
client.recordDroppedEvent = this._originalRecordDroppedEvent;
1380+
}
13361381
}

packages/replay/test/unit/index-handleGlobalEvent.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentHub } from '@sentry/core';
12
import { Error } from '@test/fixtures/error';
23
import { Transaction } from '@test/fixtures/transaction';
34
import { resetSdkMock } from '@test/mocks';
@@ -83,6 +84,27 @@ it('only tags errors with replay id, adds trace and error id to context for erro
8384
expect(replay.waitForError).toBe(false);
8485
});
8586

87+
it('strips out dropped events from errorIds', async () => {
88+
const error1 = Error({ event_id: 'err1' });
89+
const error2 = Error({ event_id: 'err2' });
90+
const error3 = Error({ event_id: 'err3' });
91+
92+
replay['_overwriteRecordDroppedEvent']();
93+
94+
const client = getCurrentHub().getClient()!;
95+
96+
replay.handleGlobalEvent(error1);
97+
replay.handleGlobalEvent(error2);
98+
replay.handleGlobalEvent(error3);
99+
100+
client.recordDroppedEvent('before_send', 'error', { event_id: 'err2' });
101+
102+
// @ts-ignore private
103+
expect(Array.from(replay.context.errorIds)).toEqual(['err1', 'err3']);
104+
105+
replay['_restoreRecordDroppedEvent']();
106+
});
107+
86108
it('tags errors and transactions with replay id for session samples', async () => {
87109
({ replay } = await resetSdkMock({
88110
sessionSampleRate: 1.0,

0 commit comments

Comments
 (0)