Skip to content

Commit 3a939dd

Browse files
authored
Merge 2f205b3 into fc5ccaf
2 parents fc5ccaf + 2f205b3 commit 3a939dd

File tree

10 files changed

+88
-5
lines changed

10 files changed

+88
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ SentryAndroid.init(
4949
```
5050

5151
</details>
52+
- Android: Flush logs when app enters background ([#4873](https://github.com/getsentry/sentry-java/pull/4873))
5253

5354

5455
### Improvements

sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
4545
this.options.isEnableAppLifecycleBreadcrumbs());
4646

4747
if (this.options.isEnableAutoSessionTracking()
48-
|| this.options.isEnableAppLifecycleBreadcrumbs()) {
48+
|| this.options.isEnableAppLifecycleBreadcrumbs()
49+
|| this.options.getLogs().isEnabled()) {
4950
try (final ISentryLifecycleToken ignored = lock.acquire()) {
5051
if (watcher != null) {
5152
return;
@@ -56,7 +57,8 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
5657
scopes,
5758
this.options.getSessionTrackingIntervalMillis(),
5859
this.options.isEnableAutoSessionTracking(),
59-
this.options.isEnableAppLifecycleBreadcrumbs());
60+
this.options.isEnableAppLifecycleBreadcrumbs(),
61+
this.options.getLogs().isEnabled());
6062

6163
AppState.getInstance().addAppStateListener(watcher);
6264
}

sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.sentry.ISentryLifecycleToken;
66
import io.sentry.SentryLevel;
77
import io.sentry.Session;
8+
import io.sentry.logger.LoggerBatchProcessor;
89
import io.sentry.transport.CurrentDateProvider;
910
import io.sentry.transport.ICurrentDateProvider;
1011
import io.sentry.util.AutoClosableReentrantLock;
@@ -29,18 +30,22 @@ final class LifecycleWatcher implements AppState.AppStateListener {
2930
private final boolean enableSessionTracking;
3031
private final boolean enableAppLifecycleBreadcrumbs;
3132

33+
private final boolean enableLogFlushing;
34+
3235
private final @NotNull ICurrentDateProvider currentDateProvider;
3336

3437
LifecycleWatcher(
3538
final @NotNull IScopes scopes,
3639
final long sessionIntervalMillis,
3740
final boolean enableSessionTracking,
38-
final boolean enableAppLifecycleBreadcrumbs) {
41+
final boolean enableAppLifecycleBreadcrumbs,
42+
final boolean enableLogFlushing) {
3943
this(
4044
scopes,
4145
sessionIntervalMillis,
4246
enableSessionTracking,
4347
enableAppLifecycleBreadcrumbs,
48+
enableLogFlushing,
4449
CurrentDateProvider.getInstance());
4550
}
4651

@@ -49,10 +54,12 @@ final class LifecycleWatcher implements AppState.AppStateListener {
4954
final long sessionIntervalMillis,
5055
final boolean enableSessionTracking,
5156
final boolean enableAppLifecycleBreadcrumbs,
57+
final boolean enableLogFlushing,
5258
final @NotNull ICurrentDateProvider currentDateProvider) {
5359
this.sessionIntervalMillis = sessionIntervalMillis;
5460
this.enableSessionTracking = enableSessionTracking;
5561
this.enableAppLifecycleBreadcrumbs = enableAppLifecycleBreadcrumbs;
62+
this.enableLogFlushing = enableLogFlushing;
5663
this.scopes = scopes;
5764
this.currentDateProvider = currentDateProvider;
5865
}
@@ -101,6 +108,29 @@ public void onBackground() {
101108
scheduleEndSession();
102109

103110
addAppBreadcrumb("background");
111+
112+
if (enableLogFlushing) {
113+
try {
114+
scopes
115+
.getOptions()
116+
.getExecutorService()
117+
.submit(
118+
new Runnable() {
119+
@Override
120+
public void run() {
121+
scopes
122+
.getGlobalScope()
123+
.getClient()
124+
.flushLogs(LoggerBatchProcessor.FLUSH_AFTER_MS);
125+
}
126+
});
127+
} catch (Throwable t) {
128+
scopes
129+
.getOptions()
130+
.getLogger()
131+
.log(SentryLevel.ERROR, t, "Failed to submit log flush runnable");
132+
}
133+
}
104134
}
105135

106136
private void scheduleEndSession() {

sentry-android-core/src/test/java/io/sentry/android/core/AppLifecycleIntegrationTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ class AppLifecycleIntegrationTest {
3434
}
3535

3636
@Test
37-
fun `When SessionTracking and AppLifecycle breadcrumbs are disabled, lifecycle watcher should not be started`() {
37+
fun `When SessionTracking and AppLifecycle breadcrumbs and Logs are disabled, lifecycle watcher should not be started`() {
3838
val sut = fixture.getSut()
3939
fixture.options.apply {
4040
isEnableAppLifecycleBreadcrumbs = false
4141
isEnableAutoSessionTracking = false
42+
logs.isEnabled = false
4243
}
4344

4445
sut.register(fixture.scopes, fixture.options)

sentry-android-core/src/test/java/io/sentry/android/core/LifecycleWatcherTest.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import io.sentry.DateUtils
55
import io.sentry.IContinuousProfiler
66
import io.sentry.IScope
77
import io.sentry.IScopes
8+
import io.sentry.ISentryClient
89
import io.sentry.ReplayController
910
import io.sentry.ScopeCallback
1011
import io.sentry.SentryLevel
1112
import io.sentry.SentryOptions
1213
import io.sentry.Session
1314
import io.sentry.Session.State
15+
import io.sentry.test.ImmediateExecutorService
1416
import io.sentry.transport.ICurrentDateProvider
1517
import kotlin.test.BeforeTest
1618
import kotlin.test.Test
@@ -36,10 +38,13 @@ class LifecycleWatcherTest {
3638
val replayController = mock<ReplayController>()
3739
val continuousProfiler = mock<IContinuousProfiler>()
3840

41+
val client = mock<ISentryClient>()
42+
3943
fun getSUT(
4044
sessionIntervalMillis: Long = 0L,
4145
enableAutoSessionTracking: Boolean = true,
4246
enableAppLifecycleBreadcrumbs: Boolean = true,
47+
enableLogFlushing: Boolean = true,
4348
session: Session? = null,
4449
): LifecycleWatcher {
4550
val argumentCaptor: ArgumentCaptor<ScopeCallback> =
@@ -49,15 +54,20 @@ class LifecycleWatcherTest {
4954
whenever(scopes.configureScope(argumentCaptor.capture())).thenAnswer {
5055
argumentCaptor.value.run(scope)
5156
}
57+
whenever(scope.client).thenReturn(client)
58+
5259
options.setReplayController(replayController)
5360
options.setContinuousProfiler(continuousProfiler)
61+
options.executorService = ImmediateExecutorService()
5462
whenever(scopes.options).thenReturn(options)
63+
whenever(scopes.globalScope).thenReturn(scope)
5564

5665
return LifecycleWatcher(
5766
scopes,
5867
sessionIntervalMillis,
5968
enableAutoSessionTracking,
6069
enableAppLifecycleBreadcrumbs,
70+
enableLogFlushing,
6171
dateProvider,
6272
)
6373
}
@@ -295,4 +305,27 @@ class LifecycleWatcherTest {
295305
watcher.onBackground()
296306
verify(fixture.replayController, timeout(10000)).stop()
297307
}
308+
309+
@Test
310+
fun `flush logs when going in background`() {
311+
val watcher = fixture.getSUT(enableLogFlushing = true)
312+
313+
watcher.onForeground()
314+
watcher.onBackground()
315+
316+
watcher.onForeground()
317+
watcher.onBackground()
318+
319+
verify(fixture.client, times(2)).flushLogs(any())
320+
}
321+
322+
@Test
323+
fun `do not flush logs when going in background when logging is disabled`() {
324+
val watcher = fixture.getSUT(enableLogFlushing = false)
325+
326+
watcher.onForeground()
327+
watcher.onBackground()
328+
329+
verify(fixture.client, never()).flushLogs(any())
330+
}
298331
}

sentry-android-core/src/test/java/io/sentry/android/core/SessionTrackingIntegrationTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ class SessionTrackingIntegrationTest {
142142
TODO("Not yet implemented")
143143
}
144144

145+
override fun flushLogs(timeoutMillis: Long) {
146+
TODO("Not yet implemented")
147+
}
148+
145149
override fun captureFeedback(feedback: Feedback, hint: Hint?, scope: IScope): SentryId {
146150
TODO("Not yet implemented")
147151
}

sentry/api/sentry.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ public abstract interface class io/sentry/ISentryClient {
10531053
public abstract fun close ()V
10541054
public abstract fun close (Z)V
10551055
public abstract fun flush (J)V
1056+
public abstract fun flushLogs (J)V
10561057
public abstract fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
10571058
public abstract fun isEnabled ()Z
10581059
public fun isHealthy ()Z
@@ -2856,6 +2857,7 @@ public final class io/sentry/SentryClient : io/sentry/ISentryClient {
28562857
public fun close ()V
28572858
public fun close (Z)V
28582859
public fun flush (J)V
2860+
public fun flushLogs (J)V
28592861
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
28602862
public fun isEnabled ()Z
28612863
public fun isHealthy ()Z

sentry/src/main/java/io/sentry/ISentryClient.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public interface ISentryClient {
4747
*/
4848
void flush(long timeoutMillis);
4949

50+
void flushLogs(long timeoutMillis);
51+
5052
/**
5153
* Captures the event.
5254
*

sentry/src/main/java/io/sentry/NoOpSentryClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public void close() {}
3838
@Override
3939
public void flush(long timeoutMillis) {}
4040

41+
@Override
42+
public void flushLogs(long timeoutMillis) {}
43+
4144
@Override
4245
public @NotNull SentryId captureFeedback(
4346
@NotNull Feedback feedback, @Nullable Hint hint, @NotNull IScope scope) {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,10 +1563,15 @@ public void close(final boolean isRestarting) {
15631563

15641564
@Override
15651565
public void flush(final long timeoutMillis) {
1566-
loggerBatchProcessor.flush(timeoutMillis);
1566+
flushLogs(timeoutMillis);
15671567
transport.flush(timeoutMillis);
15681568
}
15691569

1570+
@Override
1571+
public void flushLogs(final long timeoutMillis) {
1572+
loggerBatchProcessor.flush(timeoutMillis);
1573+
}
1574+
15701575
@Override
15711576
public @Nullable RateLimiter getRateLimiter() {
15721577
return transport.getRateLimiter();

0 commit comments

Comments
 (0)