Skip to content
2 changes: 1 addition & 1 deletion sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ dependencies {
testImplementation(projects.sentrySpotlight)
testImplementation(projects.sentryAndroidFragment)
testImplementation(projects.sentryAndroidTimber)
testImplementation(libs.timber)
testImplementation(projects.sentryAndroidReplay)
testImplementation(projects.sentryCompose)
testImplementation(projects.sentryAndroidNdk)
Expand All @@ -136,5 +137,4 @@ dependencies {
testImplementation(libs.androidx.compose.foundation.layout)
testImplementation(libs.androidx.compose.material3)
testRuntimeOnly(libs.androidx.fragment.ktx)
testRuntimeOnly(libs.timber)
}
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ static void installDefaultIntegrations(
}

if (isTimberAvailable) {
options.addIntegration(new SentryTimberIntegration(options.isEnableTimberLogs()));
options.addIntegration(new SentryTimberIntegration(() -> options.isEnableTimberLogs()));
}
options.addIntegration(new AppComponentsBreadcrumbsIntegration(context));
options.addIntegration(new SystemEventsBreadcrumbsIntegration(context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.sentry.SentryEnvelope
import io.sentry.SentryLevel
import io.sentry.SentryLevel.DEBUG
import io.sentry.SentryLevel.FATAL
import io.sentry.SentryLogEvent
import io.sentry.SentryOptions
import io.sentry.SentryOptions.BeforeSendCallback
import io.sentry.Session
Expand Down Expand Up @@ -84,6 +85,7 @@ import org.robolectric.annotation.Config
import org.robolectric.shadow.api.Shadow
import org.robolectric.shadows.ShadowActivityManager
import org.robolectric.shadows.ShadowActivityManager.ApplicationExitInfoBuilder
import timber.log.Timber

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

@Test
fun `auto-installed Timber integration uses Logs option set in configuration callback`() {
val logs = mutableListOf<SentryLogEvent>()
fixture.initSut { options ->
options.isEnableTimberLogs = true
options.logs.beforeSend =
SentryOptions.Logs.BeforeSendLogCallback { log ->
logs.add(log)
log
}
}

Timber.i("message")

assertEquals(1, logs.size)
}

@Test
fun `auto-installed Timber integration uses configuration callback override of manifest option`() {
val metadata =
Bundle().apply {
putString(ManifestMetadataReader.DSN, "https://key@sentry.io/123")
putBoolean(ManifestMetadataReader.ENABLE_TIMBER_LOGS, true)
}
val mockContext = ContextUtilsTestHelper.mockMetaData(metaData = metadata)
val logs = mutableListOf<SentryLogEvent>()

initForTest(mockContext) { options ->
options.isEnableTimberLogs = false
options.logs.beforeSend =
SentryOptions.Logs.BeforeSendLogCallback { log ->
logs.add(log)
log
}
}
Timber.i("message")

assertTrue(logs.isEmpty())
}

@Test
fun `deduplicates fragment, timber and system events integrations`() {
var refOptions: SentryAndroidOptions? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.sentry.SentryLogLevel
import io.sentry.SentryOptions
import io.sentry.android.timber.BuildConfig.VERSION_NAME
import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
import io.sentry.util.LazyEvaluator.Evaluator
import java.io.Closeable
import timber.log.Timber

Expand All @@ -18,11 +19,13 @@ public class SentryTimberIntegration(
public val minBreadcrumbLevel: SentryLevel = SentryLevel.INFO,
public val minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
) : Integration, Closeable {
public var enableLogs: Boolean = false
private set
public val enableLogs: Boolean
get() = enableLogsProvider.evaluate()

private var enableLogsProvider: Evaluator<Boolean> = Evaluator { false }

public constructor(enableLogs: Boolean) : this() {
this.enableLogs = enableLogs
enableLogsProvider = Evaluator { enableLogs }
}

public constructor(
Expand All @@ -31,7 +34,11 @@ public class SentryTimberIntegration(
minLogsLevel: SentryLogLevel,
enableLogs: Boolean,
) : this(minEventLevel, minBreadcrumbLevel, minLogsLevel) {
this.enableLogs = enableLogs
enableLogsProvider = Evaluator { enableLogs }
}

internal constructor(enableLogsProvider: Evaluator<Boolean>) : this() {
this.enableLogsProvider = enableLogsProvider
Comment thread
cursor[bot] marked this conversation as resolved.
}

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

tree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel, minLogsLevel, enableLogs)
tree =
SentryTimberTree(
scopes,
minEventLevel,
minBreadcrumbLevel,
minLogsLevel,
enableLogsProvider.evaluate(),
)
Timber.plant(tree)

logger.log(SentryLevel.DEBUG, "SentryTimberIntegration installed.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import io.sentry.logger.ILoggerApi
import io.sentry.logger.SentryLogParameters
import io.sentry.protocol.SdkVersion
import io.sentry.transport.ITransport
import io.sentry.util.LazyEvaluator.Evaluator
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -108,6 +109,18 @@ class SentryTimberIntegrationTest {
verify(fixture.logs).log(any(), any<SentryLogParameters>(), any<String>())
}

@Test
fun `Integration evaluates Logs provider when registered`() {
var enableLogs = false
val sut = SentryTimberIntegration(Evaluator { enableLogs })
enableLogs = true

sut.register(fixture.scopes, fixture.options)
Timber.i("message")

verify(fixture.logs).log(any(), any<SentryLogParameters>(), any<String>())
}

@Test
fun `Integrations removes a tree from Timber on close integration`() {
val sut = fixture.getSut()
Expand Down
Loading