Skip to content

Commit 98f55ae

Browse files
authored
fix(replay): Do not capture replay for cached events (#4474)
* fix(replay): Do not capture replay for cached events * Changelog * Formatting * Wording * Still caputre replay for outbox events
1 parent 14a37e5 commit 98f55ae

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Send UI Profiling app start chunk when it finishes ([#4423](https://github.com/getsentry/sentry-java/pull/4423))
88
- Republish Javadoc [#4457](https://github.com/getsentry/sentry-java/pull/4457)
99
- Finalize `OkHttpEvent` even if no active span in `SentryOkHttpInterceptor` [#4469](https://github.com/getsentry/sentry-java/pull/4469)
10+
- Session Replay: Do not capture current replay for cached events from the past ([#4474](https://github.com/getsentry/sentry-java/pull/4474))
1011
- Session Replay: Correctly capture Dialogs and non full-sized windows ([#4354](https://github.com/getsentry/sentry-java/pull/4354))
1112
- Session Replay: Fix inconsistent `segment_id` ([#4471](https://github.com/getsentry/sentry-java/pull/4471))
1213

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import io.sentry.clientreport.DiscardReason;
44
import io.sentry.exception.SentryEnvelopeException;
55
import io.sentry.hints.AbnormalExit;
6+
import io.sentry.hints.ApplyScopeData;
67
import io.sentry.hints.Backfillable;
8+
import io.sentry.hints.Cached;
79
import io.sentry.hints.DiskFlushNotification;
810
import io.sentry.hints.TransactionEnd;
911
import io.sentry.logger.ILoggerBatchProcessor;
@@ -210,9 +212,12 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
210212
}
211213

212214
final boolean isBackfillable = HintUtils.hasType(hint, Backfillable.class);
213-
// if event is backfillable we don't wanna trigger capture replay, because it's an event from
214-
// the past
215-
if (event != null && !isBackfillable && (event.isErrored() || event.isCrashed())) {
215+
final boolean isCached =
216+
HintUtils.hasType(hint, Cached.class) && !HintUtils.hasType(hint, ApplyScopeData.class);
217+
// if event is backfillable or cached we don't wanna trigger capture replay, because it's
218+
// an event from the past. If it's cached, but with ApplyScopeData, it comes from the outbox
219+
// folder and we still want to capture replay (e.g. a native captureException error)
220+
if (event != null && !isBackfillable && !isCached && (event.isErrored() || event.isCrashed())) {
216221
options.getReplayController().captureReplay(event.isCrashed());
217222
}
218223

sentry/src/test/java/io/sentry/SentryClientTest.kt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2991,6 +2991,52 @@ class SentryClientTest {
29912991
assertFalse(called)
29922992
}
29932993

2994+
@Test
2995+
fun `does not captureReplay for cached events`() {
2996+
var called = false
2997+
fixture.sentryOptions.setReplayController(object : ReplayController by NoOpReplayController.getInstance() {
2998+
override fun captureReplay(isTerminating: Boolean?) {
2999+
called = true
3000+
}
3001+
})
3002+
val sut = fixture.getSut()
3003+
3004+
sut.captureEvent(
3005+
SentryEvent().apply {
3006+
exceptions = listOf(
3007+
SentryException().apply {
3008+
mechanism = Mechanism().apply { isHandled = false }
3009+
}
3010+
)
3011+
},
3012+
HintUtils.createWithTypeCheckHint(CachedHint())
3013+
)
3014+
assertFalse(called)
3015+
}
3016+
3017+
@Test
3018+
fun `captures replay for cached events with apply scope`() {
3019+
var called = false
3020+
fixture.sentryOptions.setReplayController(object : ReplayController by NoOpReplayController.getInstance() {
3021+
override fun captureReplay(isTerminating: Boolean?) {
3022+
called = true
3023+
}
3024+
})
3025+
val sut = fixture.getSut()
3026+
3027+
sut.captureEvent(
3028+
SentryEvent().apply {
3029+
exceptions = listOf(
3030+
SentryException().apply {
3031+
mechanism = Mechanism().apply { isHandled = false }
3032+
}
3033+
)
3034+
},
3035+
HintUtils.createWithTypeCheckHint(CachedWithApplyScopeHint())
3036+
)
3037+
assertTrue(called)
3038+
}
3039+
29943040
@Test
29953041
fun `when beforeSendReplay is set, callback is invoked`() {
29963042
var invoked = false
@@ -3502,6 +3548,10 @@ class SentryClientTest {
35023548
private class BackfillableHint : Backfillable {
35033549
override fun shouldEnrich(): Boolean = false
35043550
}
3551+
3552+
private class CachedHint : Cached
3553+
3554+
private class CachedWithApplyScopeHint : Cached, ApplyScopeData
35053555
}
35063556

35073557
class DropEverythingEventProcessor : EventProcessor {

0 commit comments

Comments
 (0)