Skip to content

Commit fb9f13e

Browse files
committed
ref(replay): Improve status logging
1 parent d3abf45 commit fb9f13e

File tree

12 files changed

+112
-62
lines changed

12 files changed

+112
-62
lines changed

packages/replay/jest.setup.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,24 @@ function checkCallForSentReplay(
129129
}
130130

131131
/**
132-
* Only want calls that send replay events, i.e. ignore error events
133-
*/
132+
* Only want calls that send replay events, i.e. ignore error events
133+
*/
134+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
134135
function getReplayCalls(calls: any[][][]): any[][][] {
135-
return calls.map(call => {
136-
const arg = call[0];
136+
return calls
137+
.map(call => {
138+
const arg = call[0];
137139
if (arg.length !== 2) {
138140
return [];
139141
}
140142

141-
if (!arg[1][0].find(({type}: {type: string}) => ['replay_event', 'replay_recording'].includes(type))) {
143+
if (!arg[1][0].find(({ type }: { type: string }) => ['replay_event', 'replay_recording'].includes(type))) {
142144
return [];
143145
}
144146

145-
return [ arg ];
146-
}).filter(Boolean);
147+
return [arg];
148+
})
149+
.filter(Boolean);
147150
}
148151

149152
/**
@@ -159,9 +162,11 @@ const toHaveSentReplay = function (
159162

160163
let result: CheckCallForSentReplayResult;
161164

162-
const expectedKeysLength = expected ? ('sample' in expected ? Object.keys(expected.sample) : Object.keys(expected)).length : 0;
165+
const expectedKeysLength = expected
166+
? ('sample' in expected ? Object.keys(expected.sample) : Object.keys(expected)).length
167+
: 0;
163168

164-
const replayCalls = getReplayCalls(calls)
169+
const replayCalls = getReplayCalls(calls);
165170

166171
for (const currentCall of replayCalls) {
167172
result = checkCallForSentReplay.call(this, currentCall[0], expected);
@@ -213,7 +218,7 @@ const toHaveLastSentReplay = function (
213218
expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean },
214219
) {
215220
const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock;
216-
const replayCalls = getReplayCalls(calls)
221+
const replayCalls = getReplayCalls(calls);
217222

218223
const lastCall = replayCalls[calls.length - 1]?.[0];
219224

packages/replay/src/eventBuffer/EventBufferProxy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { ReplayRecordingData } from '@sentry/types';
22
import { logger } from '@sentry/utils';
33

44
import type { AddEventResult, EventBuffer, EventBufferType, RecordingEvent } from '../types';
5+
import { logInfo } from '../util/log';
56
import { EventBufferArray } from './EventBufferArray';
67
import { EventBufferCompressionWorker } from './EventBufferCompressionWorker';
78

@@ -79,7 +80,7 @@ export class EventBufferProxy implements EventBuffer {
7980
} catch (error) {
8081
// If the worker fails to load, we fall back to the simple buffer.
8182
// Nothing more to do from our side here
82-
__DEBUG_BUILD__ && logger.log('[Replay] Failed to load the compression worker, falling back to simple buffer');
83+
logInfo('[Replay] Failed to load the compression worker, falling back to simple buffer');
8384
return;
8485
}
8586

packages/replay/src/eventBuffer/WorkerHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { logger } from '@sentry/utils';
22

33
import type { WorkerRequest, WorkerResponse } from '../types';
4+
import { logInfo } from '../util/log';
45

56
/**
67
* Event buffer that uses a web worker to compress events.
@@ -55,7 +56,7 @@ export class WorkerHandler {
5556
* Destroy the worker.
5657
*/
5758
public destroy(): void {
58-
__DEBUG_BUILD__ && logger.log('[Replay] Destroying compression worker');
59+
logInfo('[Replay] Destroying compression worker');
5960
this._worker.terminate();
6061
}
6162

packages/replay/src/eventBuffer/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getWorkerURL } from '@sentry-internal/replay-worker';
2-
import { logger } from '@sentry/utils';
32

43
import type { EventBuffer } from '../types';
4+
import { logInfo } from '../util/log';
55
import { EventBufferArray } from './EventBufferArray';
66
import { EventBufferProxy } from './EventBufferProxy';
77

@@ -18,15 +18,15 @@ export function createEventBuffer({ useCompression }: CreateEventBufferParams):
1818
try {
1919
const workerUrl = getWorkerURL();
2020

21-
__DEBUG_BUILD__ && logger.log('[Replay] Using compression worker');
21+
logInfo('[Replay] Using compression worker');
2222
const worker = new Worker(workerUrl);
2323
return new EventBufferProxy(worker);
2424
} catch (error) {
25-
__DEBUG_BUILD__ && logger.log('[Replay] Failed to create compression worker');
25+
logInfo('[Replay] Failed to create compression worker');
2626
// Fall back to use simple event buffer array
2727
}
2828
}
2929

30-
__DEBUG_BUILD__ && logger.log('[Replay] Using simple buffer');
30+
logInfo('[Replay] Using simple buffer');
3131
return new EventBufferArray();
3232
}

packages/replay/src/replay.ts

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { debounce } from './util/debounce';
4747
import { getHandleRecordingEmit } from './util/handleRecordingEmit';
4848
import { isExpired } from './util/isExpired';
4949
import { isSessionExpired } from './util/isSessionExpired';
50+
import { logInfo } from './util/log';
5051
import { sendReplay } from './util/sendReplay';
5152
import type { SKIPPED } from './util/throttle';
5253
import { throttle, THROTTLED } from './util/throttle';
@@ -239,6 +240,8 @@ export class ReplayContainer implements ReplayContainerInterface {
239240
this.recordingMode = 'buffer';
240241
}
241242

243+
logInfo(`[Replay] Starting replay in ${this.recordingMode} mode`, this._options._experiments.traceInternals);
244+
242245
this._initializeRecording();
243246
}
244247

@@ -258,6 +261,8 @@ export class ReplayContainer implements ReplayContainerInterface {
258261
throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
259262
}
260263

264+
logInfo('[Replay] Starting replay in session mode', this._options._experiments.traceInternals);
265+
261266
const previousSessionId = this.session && this.session.id;
262267

263268
const { session } = getSession({
@@ -267,6 +272,7 @@ export class ReplayContainer implements ReplayContainerInterface {
267272
// This is intentional: create a new session-based replay when calling `start()`
268273
sessionSampleRate: 1,
269274
allowBuffering: false,
275+
traceInternals: this._options._experiments.traceInternals,
270276
});
271277

272278
session.previousSessionId = previousSessionId;
@@ -284,6 +290,8 @@ export class ReplayContainer implements ReplayContainerInterface {
284290
throw new Error('Replay recording is already in progress');
285291
}
286292

293+
logInfo('[Replay] Starting replay in buffer mode', this._options._experiments.traceInternals);
294+
287295
const previousSessionId = this.session && this.session.id;
288296

289297
const { session } = getSession({
@@ -292,6 +300,7 @@ export class ReplayContainer implements ReplayContainerInterface {
292300
currentSession: this.session,
293301
sessionSampleRate: 0,
294302
allowBuffering: true,
303+
traceInternals: this._options._experiments.traceInternals,
295304
});
296305

297306
session.previousSessionId = previousSessionId;
@@ -352,15 +361,10 @@ export class ReplayContainer implements ReplayContainerInterface {
352361
}
353362

354363
try {
355-
if (__DEBUG_BUILD__) {
356-
const msg = `[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''}`;
357-
358-
// When `traceInternals` is enabled, we want to log this to the console
359-
// Else, use the regular debug output
360-
// eslint-disable-next-line
361-
const log = this.getOptions()._experiments.traceInternals ? console.warn : logger.log;
362-
log(msg);
363-
}
364+
logInfo(
365+
`[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''}`,
366+
this._options._experiments.traceInternals,
367+
);
364368

365369
// We can't move `_isEnabled` after awaiting a flush, otherwise we can
366370
// enter into an infinite loop when `stop()` is called while flushing.
@@ -393,8 +397,14 @@ export class ReplayContainer implements ReplayContainerInterface {
393397
* not as thorough of a shutdown as `stop()`.
394398
*/
395399
public pause(): void {
400+
if (this._isPaused) {
401+
return;
402+
}
403+
396404
this._isPaused = true;
397405
this.stopRecording();
406+
407+
logInfo('[Replay] Pausing replay', this._options._experiments.traceInternals);
398408
}
399409

400410
/**
@@ -404,12 +414,14 @@ export class ReplayContainer implements ReplayContainerInterface {
404414
* new DOM checkout.`
405415
*/
406416
public resume(): void {
407-
if (!this._loadAndCheckSession()) {
417+
if (!this._isPaused || !this._loadAndCheckSession()) {
408418
return;
409419
}
410420

411421
this._isPaused = false;
412422
this.startRecording();
423+
424+
logInfo('[Replay] Resuming replay', this._options._experiments.traceInternals);
413425
}
414426

415427
/**
@@ -426,9 +438,12 @@ export class ReplayContainer implements ReplayContainerInterface {
426438

427439
const activityTime = Date.now();
428440

429-
// eslint-disable-next-line no-console
430-
const log = this.getOptions()._experiments.traceInternals ? console.info : logger.info;
431-
__DEBUG_BUILD__ && log(`[Replay] Converting buffer to session, starting at ${activityTime}`);
441+
logInfo('[Replay] Converting buffer to session', this._options._experiments.traceInternals);
442+
443+
// Change to 'session' recording mode
444+
// We do this before `flushImmediate` so that if this is called again while flushing is in progress,
445+
// we do not repeat these steps
446+
this.recordingMode = 'session';
432447

433448
// Allow flush to complete before resuming as a session recording, otherwise
434449
// the checkout from `startRecording` may be included in the payload.
@@ -442,11 +457,7 @@ export class ReplayContainer implements ReplayContainerInterface {
442457
return;
443458
}
444459

445-
// Re-start recording, but in "session" recording mode
446-
447-
// Reset all "capture on error" configuration before
448-
// starting a new recording
449-
this.recordingMode = 'session';
460+
// Re-start recording in session-mode
450461

451462
// Once this session ends, we do not want to refresh it
452463
if (this.session) {
@@ -736,6 +747,7 @@ export class ReplayContainer implements ReplayContainerInterface {
736747
currentSession: this.session,
737748
sessionSampleRate: this._options.sessionSampleRate,
738749
allowBuffering: this._options.errorSampleRate > 0 || this.recordingMode === 'buffer',
750+
traceInternals: this._options._experiments.traceInternals,
739751
});
740752

741753
// If session was newly created (i.e. was not loaded from storage), then
@@ -752,7 +764,7 @@ export class ReplayContainer implements ReplayContainerInterface {
752764
this.session = session;
753765

754766
if (!this.session.sampled) {
755-
void this.stop('session unsampled');
767+
void this.stop('session not refreshed');
756768
return false;
757769
}
758770

@@ -894,7 +906,7 @@ export class ReplayContainer implements ReplayContainerInterface {
894906
// If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION
895907
// ms, we will re-use the existing session, otherwise create a new
896908
// session
897-
__DEBUG_BUILD__ && logger.log('[Replay] Document has become active, but session has expired');
909+
logInfo('[Replay] Document has become active, but session has expired');
898910
return;
899911
}
900912

@@ -909,7 +921,7 @@ export class ReplayContainer implements ReplayContainerInterface {
909921
*/
910922
private _triggerFullSnapshot(checkout = true): void {
911923
try {
912-
__DEBUG_BUILD__ && logger.log('[Replay] Taking full rrweb snapshot');
924+
logInfo('[Replay] Taking full rrweb snapshot');
913925
record.takeFullSnapshot(checkout);
914926
} catch (err) {
915927
this._handleException(err);
@@ -1111,13 +1123,10 @@ export class ReplayContainer implements ReplayContainerInterface {
11111123
// If session is too short, or too long (allow some wiggle room over maxSessionLife), do not send it
11121124
// This _should_ not happen, but it may happen if flush is triggered due to a page activity change or similar
11131125
if (duration < this._options.minReplayDuration || duration > this.timeouts.maxSessionLife + 5_000) {
1114-
// eslint-disable-next-line no-console
1115-
const log = this.getOptions()._experiments.traceInternals ? console.warn : logger.warn;
1116-
__DEBUG_BUILD__ &&
1117-
log(
1118-
`[Replay] Session duration (${Math.floor(duration / 1000)}s) is too short or too long, not sending replay.`,
1119-
);
1120-
1126+
logInfo(
1127+
`[Replay] Session duration (${Math.floor(duration / 1000)}s) is too short or too long, not sending replay.`,
1128+
this._options._experiments.traceInternals,
1129+
);
11211130
return;
11221131
}
11231132

packages/replay/src/session/createSession.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { logger } from '@sentry/utils';
2-
31
import type { Sampled, Session, SessionOptions } from '../types';
42
import { isSampled } from '../util/isSampled';
53
import { saveSession } from './saveSession';
@@ -23,8 +21,6 @@ export function createSession({ sessionSampleRate, allowBuffering, stickySession
2321
sampled,
2422
});
2523

26-
__DEBUG_BUILD__ && logger.log(`[Replay] Creating new session: ${session.id}`);
27-
2824
if (stickySession) {
2925
saveSession(session);
3026
}

packages/replay/src/session/fetchSession.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { REPLAY_SESSION_KEY, WINDOW } from '../constants';
22
import type { Session } from '../types';
33
import { hasSessionStorage } from '../util/hasSessionStorage';
4+
import { logInfo } from '../util/log';
45
import { makeSession } from './Session';
56

67
/**
78
* Fetches a session from storage
89
*/
9-
export function fetchSession(): Session | null {
10+
export function fetchSession(traceInternals?: boolean): Session | null {
1011
if (!hasSessionStorage()) {
1112
return null;
1213
}
@@ -21,6 +22,8 @@ export function fetchSession(): Session | null {
2122

2223
const sessionObj = JSON.parse(sessionStringFromStorage) as Session;
2324

25+
logInfo('[Replay] Loading existing session', traceInternals);
26+
2427
return makeSession(sessionObj);
2528
} catch {
2629
return null;

packages/replay/src/session/getSession.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { logger } from '@sentry/utils';
2-
31
import type { Session, SessionOptions, Timeouts } from '../types';
42
import { isSessionExpired } from '../util/isSessionExpired';
3+
import { logInfo } from '../util/log';
54
import { createSession } from './createSession';
65
import { fetchSession } from './fetchSession';
76
import { makeSession } from './Session';
@@ -13,6 +12,8 @@ interface GetSessionParams extends SessionOptions {
1312
* The current session (e.g. if stickySession is off)
1413
*/
1514
currentSession?: Session;
15+
16+
traceInternals?: boolean;
1617
}
1718

1819
/**
@@ -24,9 +25,10 @@ export function getSession({
2425
stickySession,
2526
sessionSampleRate,
2627
allowBuffering,
28+
traceInternals,
2729
}: GetSessionParams): { type: 'new' | 'saved'; session: Session } {
2830
// If session exists and is passed, use it instead of always hitting session storage
29-
const session = currentSession || (stickySession && fetchSession());
31+
const session = currentSession || (stickySession && fetchSession(traceInternals));
3032

3133
if (session) {
3234
// If there is a session, check if it is valid (e.g. "last activity" time
@@ -42,9 +44,10 @@ export function getSession({
4244
// and when this session is expired, it will not be renewed until user
4345
// reloads.
4446
const discardedSession = makeSession({ sampled: false });
47+
logInfo('[Replay] Session should not be refreshed', traceInternals);
4548
return { type: 'new', session: discardedSession };
4649
} else {
47-
__DEBUG_BUILD__ && logger.log('[Replay] Session has expired');
50+
logInfo('[Replay] Session has expired', traceInternals);
4851
}
4952
// Otherwise continue to create a new session
5053
}
@@ -54,6 +57,7 @@ export function getSession({
5457
sessionSampleRate,
5558
allowBuffering,
5659
});
60+
logInfo('[Replay] Created new session', traceInternals);
5761

5862
return { type: 'new', session: newSession };
5963
}

0 commit comments

Comments
 (0)