Skip to content

Commit d7c56cc

Browse files
adinauerclaude
andcommitted
fix(android): Read Timber Logs option after configuration
Resolve the auto-installed Timber integration's Logs opt-in lazily when the integration registers. This honors programmatic configuration and manifest overrides applied after default integrations are constructed. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3b52f01 commit d7c56cc

6 files changed

Lines changed: 77 additions & 7 deletions

File tree

‎sentry-android-core/build.gradle.kts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ dependencies {
122122
testImplementation(projects.sentrySpotlight)
123123
testImplementation(projects.sentryAndroidFragment)
124124
testImplementation(projects.sentryAndroidTimber)
125+
testImplementation(libs.timber)
125126
testImplementation(projects.sentryAndroidReplay)
126127
testImplementation(projects.sentryCompose)
127128
testImplementation(projects.sentryAndroidNdk)
@@ -132,5 +133,4 @@ dependencies {
132133
testImplementation(libs.androidx.compose.foundation.layout)
133134
testImplementation(libs.androidx.compose.material3)
134135
testRuntimeOnly(libs.androidx.fragment.ktx)
135-
testRuntimeOnly(libs.timber)
136136
}

‎sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ static void installDefaultIntegrations(
473473
}
474474

475475
if (isTimberAvailable) {
476-
options.addIntegration(new SentryTimberIntegration(options.isEnableTimberLogs()));
476+
options.addIntegration(new SentryTimberIntegration(options::isEnableTimberLogs));
477477
}
478478
options.addIntegration(new AppComponentsBreadcrumbsIntegration(context));
479479
options.addIntegration(new SystemEventsBreadcrumbsIntegration(context));

‎sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import io.sentry.SentryEnvelope
2323
import io.sentry.SentryLevel
2424
import io.sentry.SentryLevel.DEBUG
2525
import io.sentry.SentryLevel.FATAL
26+
import io.sentry.SentryLogEvent
2627
import io.sentry.SentryOptions
2728
import io.sentry.SentryOptions.BeforeSendCallback
2829
import io.sentry.Session
@@ -84,6 +85,7 @@ import org.robolectric.annotation.Config
8485
import org.robolectric.shadow.api.Shadow
8586
import org.robolectric.shadows.ShadowActivityManager
8687
import org.robolectric.shadows.ShadowActivityManager.ApplicationExitInfoBuilder
88+
import timber.log.Timber
8789

8890
@RunWith(AndroidJUnit4::class)
8991
@Config(sdk = [Build.VERSION_CODES.N], shadows = [SentryShadowProcess::class])
@@ -238,6 +240,46 @@ class SentryAndroidTest {
238240
assertNotEquals(0, AppStartMetrics.getInstance().appStartTimeSpan.durationMs)
239241
}
240242

243+
@Test
244+
fun `auto-installed Timber integration uses Logs option set in configuration callback`() {
245+
val logs = mutableListOf<SentryLogEvent>()
246+
fixture.initSut { options ->
247+
options.isEnableTimberLogs = true
248+
options.logs.beforeSend =
249+
SentryOptions.Logs.BeforeSendLogCallback { log ->
250+
logs.add(log)
251+
log
252+
}
253+
}
254+
255+
Timber.i("message")
256+
257+
assertEquals(1, logs.size)
258+
}
259+
260+
@Test
261+
fun `auto-installed Timber integration uses configuration callback override of manifest option`() {
262+
val metadata =
263+
Bundle().apply {
264+
putString(ManifestMetadataReader.DSN, "https://key@sentry.io/123")
265+
putBoolean(ManifestMetadataReader.ENABLE_TIMBER_LOGS, true)
266+
}
267+
val mockContext = ContextUtilsTestHelper.mockMetaData(metaData = metadata)
268+
val logs = mutableListOf<SentryLogEvent>()
269+
270+
initForTest(mockContext) { options ->
271+
options.isEnableTimberLogs = false
272+
options.logs.beforeSend =
273+
SentryOptions.Logs.BeforeSendLogCallback { log ->
274+
logs.add(log)
275+
log
276+
}
277+
}
278+
Timber.i("message")
279+
280+
assertTrue(logs.isEmpty())
281+
}
282+
241283
@Test
242284
fun `deduplicates fragment, timber and system events integrations`() {
243285
var refOptions: SentryAndroidOptions? = null

‎sentry-android-timber/api/sentry-android-timber.api‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public final class io/sentry/android/timber/SentryTimberIntegration : io/sentry/
1212
public fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;)V
1313
public synthetic fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
1414
public fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;Z)V
15+
public fun <init> (Ljava/util/function/BooleanSupplier;)V
1516
public fun <init> (Z)V
1617
public fun close ()V
1718
public final fun getEnableLogs ()Z

‎sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.sentry.SentryOptions
1010
import io.sentry.android.timber.BuildConfig.VERSION_NAME
1111
import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
1212
import java.io.Closeable
13+
import java.util.function.BooleanSupplier
1314
import timber.log.Timber
1415

1516
/** Sentry integration for Timber. */
@@ -18,11 +19,13 @@ public class SentryTimberIntegration(
1819
public val minBreadcrumbLevel: SentryLevel = SentryLevel.INFO,
1920
public val minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
2021
) : Integration, Closeable {
21-
public var enableLogs: Boolean = false
22-
private set
22+
public val enableLogs: Boolean
23+
get() = enableLogsProvider.asBoolean
24+
25+
private var enableLogsProvider: BooleanSupplier = BooleanSupplier { false }
2326

2427
public constructor(enableLogs: Boolean) : this() {
25-
this.enableLogs = enableLogs
28+
enableLogsProvider = BooleanSupplier { enableLogs }
2629
}
2730

2831
public constructor(
@@ -31,7 +34,11 @@ public class SentryTimberIntegration(
3134
minLogsLevel: SentryLogLevel,
3235
enableLogs: Boolean,
3336
) : this(minEventLevel, minBreadcrumbLevel, minLogsLevel) {
34-
this.enableLogs = enableLogs
37+
enableLogsProvider = BooleanSupplier { enableLogs }
38+
}
39+
40+
public constructor(enableLogsProvider: BooleanSupplier) : this() {
41+
this.enableLogsProvider = enableLogsProvider
3542
}
3643

3744
private lateinit var tree: SentryTimberTree
@@ -47,7 +54,14 @@ public class SentryTimberIntegration(
4754
override fun register(scopes: IScopes, options: SentryOptions) {
4855
logger = options.logger
4956

50-
tree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel, minLogsLevel, enableLogs)
57+
tree =
58+
SentryTimberTree(
59+
scopes,
60+
minEventLevel,
61+
minBreadcrumbLevel,
62+
minLogsLevel,
63+
enableLogsProvider.asBoolean,
64+
)
5165
Timber.plant(tree)
5266

5367
logger.log(SentryLevel.DEBUG, "SentryTimberIntegration installed.")

‎sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.sentry.logger.ILoggerApi
1212
import io.sentry.logger.SentryLogParameters
1313
import io.sentry.protocol.SdkVersion
1414
import io.sentry.transport.ITransport
15+
import java.util.function.BooleanSupplier
1516
import kotlin.test.BeforeTest
1617
import kotlin.test.Test
1718
import kotlin.test.assertEquals
@@ -108,6 +109,18 @@ class SentryTimberIntegrationTest {
108109
verify(fixture.logs).log(any(), any<SentryLogParameters>(), any<String>())
109110
}
110111

112+
@Test
113+
fun `Integration evaluates Logs provider when registered`() {
114+
var enableLogs = false
115+
val sut = SentryTimberIntegration(BooleanSupplier { enableLogs })
116+
enableLogs = true
117+
118+
sut.register(fixture.scopes, fixture.options)
119+
Timber.i("message")
120+
121+
verify(fixture.logs).log(any(), any<SentryLogParameters>(), any<String>())
122+
}
123+
111124
@Test
112125
fun `Integrations removes a tree from Timber on close integration`() {
113126
val sut = fixture.getSut()

0 commit comments

Comments
 (0)