Skip to content
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

Missing replay screenshots cause segments to not include latest data #3677

Open
vaind opened this issue Sep 3, 2024 · 0 comments
Open

Missing replay screenshots cause segments to not include latest data #3677

vaind opened this issue Sep 3, 2024 · 0 comments

Comments

@vaind
Copy link
Collaborator

vaind commented Sep 3, 2024

Description

Consider the following code that creates segments in response to a screenshot being captured

override fun onScreenshotRecorded(bitmap: Bitmap?, store: ReplayCache.(frameTimestamp: Long) -> Unit) {
if (options.connectionStatusProvider.connectionStatus == DISCONNECTED) {
options.logger.log(DEBUG, "Skipping screenshot recording, no internet connection")
bitmap?.recycle()
return
}
// have to do it before submitting, otherwise if the queue is busy, the timestamp won't be
// reflecting the exact time of when it was captured
val frameTimestamp = dateProvider.currentTimeMillis
val height = recorderConfig.recordingHeight
val width = recorderConfig.recordingWidth
replayExecutor.submitSafely(options, "$TAG.add_frame") {
cache?.store(frameTimestamp)
val currentSegmentTimestamp = segmentTimestamp
currentSegmentTimestamp ?: run {
options.logger.log(DEBUG, "Segment timestamp is not set, not recording frame")
return@submitSafely
}
if (isTerminating.get()) {
options.logger.log(DEBUG, "Not capturing segment, because the app is terminating, will be captured on next launch")
return@submitSafely
}
val now = dateProvider.currentTimeMillis
if ((now - currentSegmentTimestamp.time >= options.experimental.sessionReplay.sessionSegmentDuration)) {
val segment =
createSegmentInternal(
options.experimental.sessionReplay.sessionSegmentDuration,
currentSegmentTimestamp,
currentReplayId,
currentSegment,
height,
width
)
if (segment is ReplaySegment.Created) {
segment.capture(hub)
currentSegment++
// set next segment timestamp as close to the previous one as possible to avoid gaps
segmentTimestamp = segment.replay.timestamp
}
}
if ((now - replayStartTimestamp.get() >= options.experimental.sessionReplay.sessionDuration)) {
options.replayController.stop()
options.logger.log(INFO, "Session replay deadline exceeded (1h), stopping recording")
}
}
}

Specifically,

createSegmentInternal(
options.experimental.sessionReplay.sessionSegmentDuration,
currentSegmentTimestamp,

If there is a gap between frames of more than sessionSegmentDuration, a segment would be created only for the duration prior to this frame.
I've noticed this while investigating why breadcrumbs are sometimes not send on Flutter - it's because if there are no changes on the UI, there is no frame created but when next there are some changes (and breadcrumbs created for UI taps), these were not sent because:

  • the current segment start timestamp was the end timestamp of the previous segment
  • the duration of the segment was capped at the sessionSegmentDuration (5 seconds at the moment)
    thus when the current screenshot timestamp was, for example, a minute after the previous one (because the app sat idle), it would take additional 60/5 = 12 frames (12 seconds when the user actively did something on the UI) to catch up; or actually 12 + at least additional 3 for those 12 seconds

I've tried a minor change of passing the actual duration between the last segment end-timestamp and the current frame timestamp, although I'm not sure that is the way to go:

            val now = dateProvider.currentTimeMillis
            val duration = now - currentSegmentTimestamp.time
            if ((duration >= options.experimental.sessionReplay.sessionSegmentDuration)) {
                val segment =
                    createSegmentInternal(
                        duration,
                        currentSegmentTimestamp,

Instead, I think it may be necessary to either loop here or add more job instances: replayExecutor.submitSafely(options, "$TAG.add_frame") {

@vaind vaind changed the title Missing replay screenshots cause segments not include latest data Missing replay screenshots cause segments to not include latest data Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

4 participants