Skip to content

feat(replay): Keep min. 30 seconds of data in error mode #7025

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

Closed
wants to merge 1 commit into from

Conversation

mydea
Copy link
Member

@mydea mydea commented Feb 1, 2023

Supersedes #6924

This PR adjusts the event buffer to keep 30-60s of recording data (instead of 0-60s) in error mode.

This is accomplished by keeping the events in a queue that tracks when the last checkout happens, and allows to delete everything up until this event.

In compression mode, this means that we do not stream the events to the compressor, but compress them all at once. That's necessary because it is not really possible to remove parts of the compression stream.

In session mode, we continue to use the streaming compression as we do right now.

@mydea mydea added the Package: replay Issues related to the Sentry Replay SDK label Feb 1, 2023
@mydea mydea requested review from billyvg and Lms24 February 1, 2023 12:58
@mydea mydea self-assigned this Feb 1, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Feb 1, 2023

size-limit report 📦

Path Size
@sentry/browser - ES5 CDN Bundle (gzipped + minified) 20.06 KB (0%)
@sentry/browser - ES5 CDN Bundle (minified) 62.19 KB (0%)
@sentry/browser - ES6 CDN Bundle (gzipped + minified) 18.69 KB (0%)
@sentry/browser - ES6 CDN Bundle (minified) 55.33 KB (0%)
@sentry/browser - Webpack (gzipped + minified) 20.42 KB (0%)
@sentry/browser - Webpack (minified) 66.77 KB (0%)
@sentry/react - Webpack (gzipped + minified) 20.45 KB (0%)
@sentry/nextjs Client - Webpack (gzipped + minified) 47.85 KB (0%)
@sentry/browser + @sentry/tracing - ES5 CDN Bundle (gzipped + minified) 26.97 KB (+0.01% 🔺)
@sentry/browser + @sentry/tracing - ES6 CDN Bundle (gzipped + minified) 25.23 KB (0%)
@sentry/replay ES6 CDN Bundle (gzipped + minified) 42.57 KB (+0.7% 🔺)
@sentry/replay - Webpack (gzipped + minified) 37 KB (+0.83% 🔺)
@sentry/browser + @sentry/tracing + @sentry/replay - ES6 CDN Bundle (gzipped + minified) 60.22 KB (+0.48% 🔺)
@sentry/browser + @sentry/replay - ES6 CDN Bundle (gzipped + minified) 53.77 KB (+0.54% 🔺)


const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 };

describe('Unit | eventBuffer | EventBufferArray', () => {
it('adds events to normal event buffer', async function () {
const buffer = createEventBuffer({ useCompression: false });
for (let recordingMode of ['session', 'error'] as ReplayRecordingMode[]) {
Copy link
Member Author

Choose a reason for hiding this comment

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

We just make sure here that this works the same in both error & session mode.

@@ -29,4 +34,97 @@ describe('Unit | util | addEvent', () => {

expect(replay.isEnabled()).toEqual(false);
});

it.each([
Copy link
Member Author

Choose a reason for hiding this comment

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

These are the most relevant tests here, making sure it works the same with & without compression for both error & session mode.

@mydea mydea force-pushed the fn/replay-errors-30s branch from 7146b49 to 07d63b6 Compare February 1, 2023 14:43
@mydea mydea marked this pull request as ready for review February 1, 2023 15:07
@mydea mydea force-pushed the fn/replay-errors-30s branch from 07d63b6 to 47bdb74 Compare February 1, 2023 15:29
@@ -182,6 +182,7 @@ export class ReplayContainer implements ReplayContainerInterface {

this.eventBuffer = createEventBuffer({
useCompression: this._options.useCompression,
recordingMode: this.recordingMode,
Copy link
Member

Choose a reason for hiding this comment

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

Is there gonna be an issue when we switch from error -> session recording mode?

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't, it only means that (for now) we will continue in partitioned mode for compression - meaning even after the error was sent, we'll still not be using the streaming compression but the "all at once" compression. We may adjust this in the future, but this'll mean to swap out the event buffer at runtime, which I wanted to avoid for this first step.

Maybe it is clearer to rename this, e.g. instead of recordingMode make it rememberLastCheckout: boolean? Then it's a bit clearer what it does and that it is not really directly related to the recording mode?

Copy link
Member Author

Choose a reason for hiding this comment

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

changed this to keepLastCheckout: boolean, which should hopefully be clearer!

Comment on lines +48 to +57
if (replay.recordingMode === 'error') {
// Do not wait on it, just do it
// We know in this mode this is actually "sync"
void eventBuffer.clear(true);

// Ensure we have the correct first checkout timestamp when an error occurs
if (!session.segmentId) {
replay.getContext().earliestEvent = eventBuffer.getEarliestTimestamp();
}
Copy link
Member

Choose a reason for hiding this comment

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

Just to clarify for myself, we examine the buffer for the earliest event because we want the replay "start time" to be when the 1st checkout in the buffer happens.

So if session has been running for 2.5 minutes, we would want the replay to "start" at ~2 minutes. And replay.context.earliestEvent (before this block of code), would represent the earliest event of the entire "session".

So an issue I can think of is with the performance observer. I believe we only add them when we flush, so those events will end up becoming the earliest events anyway (which might be fine).

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, to be honest all of this is a bit brittle to me 😅 but this was the best I could come up with to handle this in a somewhat reasonable way. I wonder if it makes sense to maybe compute this on the server? Or generally change how we keep this a bit, not sure...

Copy link
Member

Choose a reason for hiding this comment

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

semi-related to this PR but I was also wondering about that - do we discard events with timestamps before the initial full checkout on the server? Or would sending such events cause problems?

Copy link
Member

@billyvg billyvg Feb 2, 2023

Choose a reason for hiding this comment

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

We discard events that are older than SESSION_IDLE_TIMEOUT minutes ago. Because we get buffered data from performance observer, those occur before initial checkout.

I wonder if we need to change/move this logic as well

// See note above re: session start needs to reflect the most recent
// checkout.
if (this.recordingMode === 'error' && this.session && this._context.earliestEvent) {
this.session.started = this._context.earliestEvent;
this._maybeSaveSession();
}

I think this is to meant to update session start time so we know when to correctly timeout a session.

@mydea mydea force-pushed the fn/replay-errors-30s branch from 47bdb74 to 3602fc4 Compare February 2, 2023 09:44
Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

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

This makes sense to me and I think it's going in a good direction.

@mydea
Copy link
Member Author

mydea commented Feb 9, 2023

FYI since main focus right now is on stability, let's probably wait for until GA to merge this in. WDYT @billyvg ?

@billyvg
Copy link
Member

billyvg commented Feb 9, 2023

@mydea agreed!

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2023

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@mydea
Copy link
Member Author

mydea commented May 2, 2023

Closing in favor of #7992

@mydea mydea closed this May 2, 2023
@AbhiPrasad AbhiPrasad deleted the fn/replay-errors-30s branch March 27, 2025 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Package: replay Issues related to the Sentry Replay SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants