Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Fallback to distinct-id as user.id logging attribute when user is not set ([#4847](https://github.com/getsentry/sentry-java/pull/4847))
- Report Timber.tag() as `timber.tag` log attribute ([#4845](https://github.com/getsentry/sentry-java/pull/4845))
- Session Replay: Add screenshot strategy serialization to RRWeb events ([#4851](https://github.com/getsentry/sentry-java/pull/4851))
- Android: Flush log when app enters background ([#4873](https://github.com/getsentry/sentry-java/pull/4873))

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
this.options.isEnableAppLifecycleBreadcrumbs());

if (this.options.isEnableAutoSessionTracking()
|| this.options.isEnableAppLifecycleBreadcrumbs()) {
|| this.options.isEnableAppLifecycleBreadcrumbs()
|| this.options.getLogs().isEnabled()) {
try (final ISentryLifecycleToken ignored = lock.acquire()) {
if (watcher != null) {
return;
Expand All @@ -56,7 +57,8 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
scopes,
this.options.getSessionTrackingIntervalMillis(),
this.options.isEnableAutoSessionTracking(),
this.options.isEnableAppLifecycleBreadcrumbs());
this.options.isEnableAppLifecycleBreadcrumbs(),
this.options.getLogs().isEnabled());

AppState.getInstance().addAppStateListener(watcher);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.sentry.ISentryLifecycleToken;
import io.sentry.SentryLevel;
import io.sentry.Session;
import io.sentry.logger.LoggerBatchProcessor;
import io.sentry.transport.CurrentDateProvider;
import io.sentry.transport.ICurrentDateProvider;
import io.sentry.util.AutoClosableReentrantLock;
Expand All @@ -29,18 +30,22 @@ final class LifecycleWatcher implements AppState.AppStateListener {
private final boolean enableSessionTracking;
private final boolean enableAppLifecycleBreadcrumbs;

private final boolean enableLogFlushing;

private final @NotNull ICurrentDateProvider currentDateProvider;

LifecycleWatcher(
final @NotNull IScopes scopes,
final long sessionIntervalMillis,
final boolean enableSessionTracking,
final boolean enableAppLifecycleBreadcrumbs) {
final boolean enableAppLifecycleBreadcrumbs,
final boolean enableLogFlushing) {
this(
scopes,
sessionIntervalMillis,
enableSessionTracking,
enableAppLifecycleBreadcrumbs,
enableLogFlushing,
CurrentDateProvider.getInstance());
}

Expand All @@ -49,10 +54,12 @@ final class LifecycleWatcher implements AppState.AppStateListener {
final long sessionIntervalMillis,
final boolean enableSessionTracking,
final boolean enableAppLifecycleBreadcrumbs,
final boolean enableLogFlushing,
final @NotNull ICurrentDateProvider currentDateProvider) {
this.sessionIntervalMillis = sessionIntervalMillis;
this.enableSessionTracking = enableSessionTracking;
this.enableAppLifecycleBreadcrumbs = enableAppLifecycleBreadcrumbs;
this.enableLogFlushing = enableLogFlushing;
this.scopes = scopes;
this.currentDateProvider = currentDateProvider;
}
Expand Down Expand Up @@ -101,6 +108,29 @@ public void onBackground() {
scheduleEndSession();

addAppBreadcrumb("background");

if (enableLogFlushing) {
try {
scopes
.getOptions()
.getExecutorService()
.submit(
new Runnable() {
@Override
public void run() {
scopes
.getGlobalScope()
.getClient()
.flushLogs(LoggerBatchProcessor.FLUSH_AFTER_MS);
}
});
} catch (Throwable t) {
scopes
.getOptions()
.getLogger()
.log(SentryLevel.ERROR, t, "Failed to submit log flush runnable");
}
}
}

private void scheduleEndSession() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ class AppLifecycleIntegrationTest {
}

@Test
fun `When SessionTracking and AppLifecycle breadcrumbs are disabled, lifecycle watcher should not be started`() {
fun `When SessionTracking and AppLifecycle breadcrumbs and Logs are disabled, lifecycle watcher should not be started`() {
val sut = fixture.getSut()
fixture.options.apply {
isEnableAppLifecycleBreadcrumbs = false
isEnableAutoSessionTracking = false
logs.isEnabled = false
}

sut.register(fixture.scopes, fixture.options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import io.sentry.DateUtils
import io.sentry.IContinuousProfiler
import io.sentry.IScope
import io.sentry.IScopes
import io.sentry.ISentryClient
import io.sentry.ReplayController
import io.sentry.ScopeCallback
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import io.sentry.Session
import io.sentry.Session.State
import io.sentry.test.ImmediateExecutorService
import io.sentry.transport.ICurrentDateProvider
import kotlin.test.BeforeTest
import kotlin.test.Test
Expand All @@ -36,10 +38,13 @@ class LifecycleWatcherTest {
val replayController = mock<ReplayController>()
val continuousProfiler = mock<IContinuousProfiler>()

val client = mock<ISentryClient>()

fun getSUT(
sessionIntervalMillis: Long = 0L,
enableAutoSessionTracking: Boolean = true,
enableAppLifecycleBreadcrumbs: Boolean = true,
enableLogFlushing: Boolean = true,
session: Session? = null,
): LifecycleWatcher {
val argumentCaptor: ArgumentCaptor<ScopeCallback> =
Expand All @@ -49,15 +54,20 @@ class LifecycleWatcherTest {
whenever(scopes.configureScope(argumentCaptor.capture())).thenAnswer {
argumentCaptor.value.run(scope)
}
whenever(scope.client).thenReturn(client)

options.setReplayController(replayController)
options.setContinuousProfiler(continuousProfiler)
options.executorService = ImmediateExecutorService()
whenever(scopes.options).thenReturn(options)
whenever(scopes.globalScope).thenReturn(scope)

return LifecycleWatcher(
scopes,
sessionIntervalMillis,
enableAutoSessionTracking,
enableAppLifecycleBreadcrumbs,
enableLogFlushing,
dateProvider,
)
}
Expand Down Expand Up @@ -295,4 +305,27 @@ class LifecycleWatcherTest {
watcher.onBackground()
verify(fixture.replayController, timeout(10000)).stop()
}

@Test
fun `flush logs when going in background`() {
val watcher = fixture.getSUT(enableLogFlushing = true)

watcher.onForeground()
watcher.onBackground()

watcher.onForeground()
watcher.onBackground()

verify(fixture.client, times(2)).flushLogs(any())
}

@Test
fun `do not flush logs when going in background when logging is disabled`() {
val watcher = fixture.getSUT(enableLogFlushing = false)

watcher.onForeground()
watcher.onBackground()

verify(fixture.client, never()).flushLogs(any())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ class SessionTrackingIntegrationTest {
TODO("Not yet implemented")
}

override fun flushLogs(timeoutMillis: Long) {
TODO("Not yet implemented")
}

override fun captureFeedback(feedback: Feedback, hint: Hint?, scope: IScope): SentryId {
TODO("Not yet implemented")
}
Expand Down
Loading
Loading