Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
- Replace `UUIDGenerator` implementation with Apache licensed code ([#4662](https://github.com/getsentry/sentry-java/pull/4662))
- Replace `Random` implementation with MIT licensed code ([#4664](https://github.com/getsentry/sentry-java/pull/4664))

### Fixes

- Flush logs on crash ([#4684](https://github.com/getsentry/sentry-java/pull/4684))

## 8.20.0

### Fixes
Expand Down
26 changes: 16 additions & 10 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
public final class SentryClient implements ISentryClient {
static final String SENTRY_PROTOCOL_VERSION = "7";

private static final int LOG_FLUSH_ON_CRASH_TIMEOUT_MILLIS = 500;

private boolean enabled;

private final @NotNull SentryOptions options;
Expand Down Expand Up @@ -211,16 +213,6 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
sentryId = event.getEventId();
}

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

try {
final @Nullable TraceContext traceContext = getTraceContext(scope, hint, event);
final boolean shouldSendAttachments = event != null;
Expand All @@ -245,6 +237,20 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
finalizeTransaction(scope, hint);
}

final boolean isBackfillable = HintUtils.hasType(hint, Backfillable.class);
final boolean isCached =
HintUtils.hasType(hint, Cached.class) && !HintUtils.hasType(hint, ApplyScopeData.class);
// if event is backfillable or cached we don't wanna trigger capture replay, because it's
// an event from the past. If it's cached, but with ApplyScopeData, it comes from the outbox
// folder and we still want to capture replay (e.g. a native captureException error)
if (event != null && !isBackfillable && !isCached && (event.isErrored() || event.isCrashed())) {
options.getReplayController().captureReplay(event.isCrashed());
// We need to flush the logs to ensure they are sent on crash
if (event.isCrashed()) {
loggerBatchProcessor.flush(LOG_FLUSH_ON_CRASH_TIMEOUT_MILLIS);
}
}

return sentryId;
}

Expand Down
19 changes: 19 additions & 0 deletions sentry/src/test/java/io/sentry/SentryClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3023,6 +3023,25 @@ class SentryClientTest {
assertTrue(terminated == true)
}

@Test
fun `flush logs for crash events`() {
val sut = fixture.getSut()
val batchProcessor = mock<ILoggerBatchProcessor>()
sut.injectForField("loggerBatchProcessor", batchProcessor)
sut.captureLog(
SentryLogEvent(SentryId(), SentryNanotimeDate(), "message", SentryLogLevel.WARN),
fixture.scopes.scope,
)

sut.captureEvent(
SentryEvent().apply {
exceptions =
listOf(SentryException().apply { mechanism = Mechanism().apply { isHandled = false } })
}
)
verify(batchProcessor).flush(eq(500))
}

@Test
fun `cleans up replay folder for Backfillable replay events`() {
val dir = File(tmpDir.newFolder().absolutePath)
Expand Down
Loading