Skip to content

Fix tag extraction logic, bump to Timber 5.0.1 #4489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Fix tag extraction logic for Timber ([#4489](https://github.com/getsentry/sentry-java/pull/4489))

## 8.14.0

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ springboot3-starter-aop = { module = "org.springframework.boot:spring-boot-start
springboot3-starter-security = { module = "org.springframework.boot:spring-boot-starter-security", version.ref = "springboot3" }
springboot3-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-jdbc", version.ref = "springboot3" }
springboot3-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "springboot3" }
timber = { module = "com.jakewharton.timber:timber", version = "4.7.1" }
timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }

# test libraries
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version = "1.6.8" }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")

package io.sentry.android.timber

import android.util.Log
Expand All @@ -17,23 +19,15 @@ public class SentryTimberTree(
private val minEventLevel: SentryLevel,
private val minBreadcrumbLevel: SentryLevel
) : Timber.Tree() {
private val pendingTag = ThreadLocal<String?>()

private fun retrieveTag(): String? {
val tag = pendingTag.get()
if (tag != null) {
this.pendingTag.remove()
}
return tag
}

/** Log a verbose message with optional format args. */
override fun v(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, but am I missing something or this ain't gonna work for Timber < 5? Because we only define it as compileOnly so if the hosting app is using a lower version it will crash?

super.v(message, *args)
logWithSentry(Log.VERBOSE, null, message, *args)
logWithSentry(Log.VERBOSE, null, message, tag, *args)
}

/** Log a verbose exception and a message with optional format args. */
Expand All @@ -42,23 +36,26 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.v(t, message, *args)
logWithSentry(Log.VERBOSE, t, message, *args)
logWithSentry(Log.VERBOSE, t, message, tag, *args)
}

/** Log a verbose exception. */
override fun v(t: Throwable?) {
val tag = explicitTag.get()
super.v(t)
logWithSentry(Log.VERBOSE, t, null)
logWithSentry(Log.VERBOSE, t, null, tag, null)
}

/** Log a debug message with optional format args. */
override fun d(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.d(message, *args)
logWithSentry(Log.DEBUG, null, message, *args)
logWithSentry(Log.DEBUG, null, message, tag, *args)
}

/** Log a debug exception and a message with optional format args. */
Expand All @@ -67,23 +64,26 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.d(t, message, *args)
logWithSentry(Log.DEBUG, t, message, *args)
logWithSentry(Log.DEBUG, t, message, tag, *args)
}

/** Log a debug exception. */
override fun d(t: Throwable?) {
val tag = explicitTag.get()
super.d(t)
logWithSentry(Log.DEBUG, t, null)
logWithSentry(Log.DEBUG, t, null, tag, null)
}

/** Log an info message with optional format args. */
override fun i(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.d(message, *args)
logWithSentry(Log.INFO, null, message, *args)
logWithSentry(Log.INFO, null, message, tag, *args)
}

/** Log an info exception and a message with optional format args. */
Expand All @@ -92,23 +92,26 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.i(t, message, *args)
logWithSentry(Log.INFO, t, message, *args)
logWithSentry(Log.INFO, t, message, tag, *args)
}

/** Log an info exception. */
override fun i(t: Throwable?) {
val tag = explicitTag.get()
super.i(t)
logWithSentry(Log.INFO, t, null)
logWithSentry(Log.INFO, t, null, tag, null)
}

/** Log a warning message with optional format args. */
override fun w(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.w(message, *args)
logWithSentry(Log.WARN, null, message, *args)
logWithSentry(Log.WARN, null, message, tag, *args)
}

/** Log a warning exception and a message with optional format args. */
Expand All @@ -117,23 +120,26 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.w(t, message, *args)
logWithSentry(Log.WARN, t, message, *args)
logWithSentry(Log.WARN, t, message, tag, *args)
}

/** Log a warning exception. */
override fun w(t: Throwable?) {
val tag = explicitTag.get()
super.w(t)
logWithSentry(Log.WARN, t, null)
logWithSentry(Log.WARN, t, null, tag, null)
}

/** Log an error message with optional format args. */
override fun e(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.e(message, *args)
logWithSentry(Log.ERROR, null, message, *args)
logWithSentry(Log.ERROR, null, message, tag, *args)
}

/** Log an error exception and a message with optional format args. */
Expand All @@ -142,23 +148,26 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.e(t, message, *args)
logWithSentry(Log.ERROR, t, message, *args)
logWithSentry(Log.ERROR, t, message, tag, *args)
}

/** Log an error exception. */
override fun e(t: Throwable?) {
val tag = explicitTag.get()
super.e(t)
logWithSentry(Log.ERROR, t, null)
logWithSentry(Log.ERROR, t, null, tag, null)
}

/** Log an assert message with optional format args. */
override fun wtf(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.wtf(message, *args)
logWithSentry(Log.ASSERT, null, message, *args)
logWithSentry(Log.ASSERT, null, message, tag, *args)
}

/** Log an assert exception and a message with optional format args. */
Expand All @@ -167,14 +176,16 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.wtf(t, message, *args)
logWithSentry(Log.ASSERT, t, message, *args)
logWithSentry(Log.ASSERT, t, message, tag, *args)
}

/** Log an assert exception. */
override fun wtf(t: Throwable?) {
val tag = explicitTag.get()
super.wtf(t)
logWithSentry(Log.ASSERT, t, null)
logWithSentry(Log.ASSERT, t, null, tag, null)
}

/** Log at `priority` a message with optional format args. */
Expand All @@ -183,8 +194,9 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.log(priority, message, *args)
logWithSentry(priority, null, message, *args)
logWithSentry(priority, null, message, tag, *args)
}

/** Log at `priority` an exception and a message with optional format args. */
Expand All @@ -194,8 +206,9 @@ public class SentryTimberTree(
message: String?,
vararg args: Any?
) {
val tag = explicitTag.get()
super.log(priority, t, message, *args)
logWithSentry(priority, t, message, *args)
logWithSentry(priority, t, message, tag, *args)
}

/** Log at `priority` an exception. */
Expand All @@ -204,26 +217,16 @@ public class SentryTimberTree(
t: Throwable?
) {
super.log(priority, t)
logWithSentry(priority, t, null)
}

override fun log(
priority: Int,
tag: String?,
message: String,
t: Throwable?
) {
pendingTag.set(tag)
logWithSentry(priority, t, null, tag, null)
}

private fun logWithSentry(
priority: Int,
throwable: Throwable?,
message: String?,
tag: String?,
vararg args: Any?
) {
val tag = retrieveTag()

if (message.isNullOrEmpty() && throwable == null) {
return // Swallow message if it's null and there's no throwable
}
Expand All @@ -238,7 +241,7 @@ public class SentryTimberTree(
}

captureEvent(level, tag, sentryMessage, throwable)
addBreadcrumb(level, sentryMessage, throwable)
addBreadcrumb(level, sentryMessage, tag, throwable)
}

/**
Expand Down Expand Up @@ -279,12 +282,13 @@ public class SentryTimberTree(
private fun addBreadcrumb(
sentryLevel: SentryLevel,
msg: Message,
tag: String?,
throwable: Throwable?
) {
// checks the breadcrumb level
if (isLoggable(sentryLevel, minBreadcrumbLevel)) {
val throwableMsg = throwable?.message
val breadCrumb = when {
val breadcrumb = when {
msg.message != null -> Breadcrumb().apply {
level = sentryLevel
category = "Timber"
Expand All @@ -295,11 +299,24 @@ public class SentryTimberTree(
}
else -> null
}

breadCrumb?.let { scopes.addBreadcrumb(it) }
if (breadcrumb != null) {
if (tag != null) {
breadcrumb.setData("tag", tag)
}
scopes.addBreadcrumb(breadcrumb)
}
}
}

override fun log(
priority: Int,
tag: String?,
message: String,
t: Throwable?
) {
// no-op
}

/**
* Converts from Timber priority to SentryLevel.
* Fallback to SentryLevel.DEBUG.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class SentryTimberIntegrationTest {
val sut = fixture.getSut()
sut.register(fixture.scopes, fixture.options)

assertEquals(1, Timber.treeCount())
assertEquals(1, Timber.treeCount)

val trees = Timber.forest()
val first = trees.first()
Expand All @@ -64,18 +64,18 @@ class SentryTimberIntegrationTest {
val sut = fixture.getSut()
sut.register(fixture.scopes, fixture.options)

assertEquals(1, Timber.treeCount())
assertEquals(1, Timber.treeCount)

sut.close()
assertEquals(0, Timber.treeCount())
assertEquals(0, Timber.treeCount)
}

@Test
fun `Integrations do not throw if close is called before register`() {
val sut = fixture.getSut()
sut.close()

assertEquals(0, Timber.treeCount())
assertEquals(0, Timber.treeCount)
}

@Test
Expand Down
Loading
Loading