Skip to content

Commit 6d73df9

Browse files
authored
Merge ca0024c into e16d062
2 parents e16d062 + ca0024c commit 6d73df9

File tree

5 files changed

+110
-50
lines changed

5 files changed

+110
-50
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Fix tag extraction logic for Timber ([#4489](https://github.com/getsentry/sentry-java/pull/4489))
6+
37
## 8.13.3
48

59
### Fixes

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ springboot3-starter-aop = { module = "org.springframework.boot:spring-boot-start
144144
springboot3-starter-security = { module = "org.springframework.boot:spring-boot-starter-security", version.ref = "springboot3" }
145145
springboot3-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-jdbc", version.ref = "springboot3" }
146146
springboot3-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "springboot3" }
147-
timber = { module = "com.jakewharton.timber:timber", version = "4.7.1" }
147+
timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }
148148

149149
# test libraries
150150
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version = "1.6.8" }

sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberTree.kt

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
2+
13
package io.sentry.android.timber
24

35
import android.util.Log
@@ -17,23 +19,15 @@ public class SentryTimberTree(
1719
private val minEventLevel: SentryLevel,
1820
private val minBreadcrumbLevel: SentryLevel
1921
) : Timber.Tree() {
20-
private val pendingTag = ThreadLocal<String?>()
21-
22-
private fun retrieveTag(): String? {
23-
val tag = pendingTag.get()
24-
if (tag != null) {
25-
this.pendingTag.remove()
26-
}
27-
return tag
28-
}
2922

3023
/** Log a verbose message with optional format args. */
3124
override fun v(
3225
message: String?,
3326
vararg args: Any?
3427
) {
28+
val tag = explicitTag.get()
3529
super.v(message, *args)
36-
logWithSentry(Log.VERBOSE, null, message, *args)
30+
logWithSentry(Log.VERBOSE, null, message, tag, *args)
3731
}
3832

3933
/** Log a verbose exception and a message with optional format args. */
@@ -42,23 +36,26 @@ public class SentryTimberTree(
4236
message: String?,
4337
vararg args: Any?
4438
) {
39+
val tag = explicitTag.get()
4540
super.v(t, message, *args)
46-
logWithSentry(Log.VERBOSE, t, message, *args)
41+
logWithSentry(Log.VERBOSE, t, message, tag, *args)
4742
}
4843

4944
/** Log a verbose exception. */
5045
override fun v(t: Throwable?) {
46+
val tag = explicitTag.get()
5147
super.v(t)
52-
logWithSentry(Log.VERBOSE, t, null)
48+
logWithSentry(Log.VERBOSE, t, null, tag, null)
5349
}
5450

5551
/** Log a debug message with optional format args. */
5652
override fun d(
5753
message: String?,
5854
vararg args: Any?
5955
) {
56+
val tag = explicitTag.get()
6057
super.d(message, *args)
61-
logWithSentry(Log.DEBUG, null, message, *args)
58+
logWithSentry(Log.DEBUG, null, message, tag, *args)
6259
}
6360

6461
/** Log a debug exception and a message with optional format args. */
@@ -67,23 +64,26 @@ public class SentryTimberTree(
6764
message: String?,
6865
vararg args: Any?
6966
) {
67+
val tag = explicitTag.get()
7068
super.d(t, message, *args)
71-
logWithSentry(Log.DEBUG, t, message, *args)
69+
logWithSentry(Log.DEBUG, t, message, tag, *args)
7270
}
7371

7472
/** Log a debug exception. */
7573
override fun d(t: Throwable?) {
74+
val tag = explicitTag.get()
7675
super.d(t)
77-
logWithSentry(Log.DEBUG, t, null)
76+
logWithSentry(Log.DEBUG, t, null, tag, null)
7877
}
7978

8079
/** Log an info message with optional format args. */
8180
override fun i(
8281
message: String?,
8382
vararg args: Any?
8483
) {
84+
val tag = explicitTag.get()
8585
super.d(message, *args)
86-
logWithSentry(Log.INFO, null, message, *args)
86+
logWithSentry(Log.INFO, null, message, tag, *args)
8787
}
8888

8989
/** Log an info exception and a message with optional format args. */
@@ -92,23 +92,26 @@ public class SentryTimberTree(
9292
message: String?,
9393
vararg args: Any?
9494
) {
95+
val tag = explicitTag.get()
9596
super.i(t, message, *args)
96-
logWithSentry(Log.INFO, t, message, *args)
97+
logWithSentry(Log.INFO, t, message, tag, *args)
9798
}
9899

99100
/** Log an info exception. */
100101
override fun i(t: Throwable?) {
102+
val tag = explicitTag.get()
101103
super.i(t)
102-
logWithSentry(Log.INFO, t, null)
104+
logWithSentry(Log.INFO, t, null, tag, null)
103105
}
104106

105107
/** Log a warning message with optional format args. */
106108
override fun w(
107109
message: String?,
108110
vararg args: Any?
109111
) {
112+
val tag = explicitTag.get()
110113
super.w(message, *args)
111-
logWithSentry(Log.WARN, null, message, *args)
114+
logWithSentry(Log.WARN, null, message, tag, *args)
112115
}
113116

114117
/** Log a warning exception and a message with optional format args. */
@@ -117,23 +120,26 @@ public class SentryTimberTree(
117120
message: String?,
118121
vararg args: Any?
119122
) {
123+
val tag = explicitTag.get()
120124
super.w(t, message, *args)
121-
logWithSentry(Log.WARN, t, message, *args)
125+
logWithSentry(Log.WARN, t, message, tag, *args)
122126
}
123127

124128
/** Log a warning exception. */
125129
override fun w(t: Throwable?) {
130+
val tag = explicitTag.get()
126131
super.w(t)
127-
logWithSentry(Log.WARN, t, null)
132+
logWithSentry(Log.WARN, t, null, tag, null)
128133
}
129134

130135
/** Log an error message with optional format args. */
131136
override fun e(
132137
message: String?,
133138
vararg args: Any?
134139
) {
140+
val tag = explicitTag.get()
135141
super.e(message, *args)
136-
logWithSentry(Log.ERROR, null, message, *args)
142+
logWithSentry(Log.ERROR, null, message, tag, *args)
137143
}
138144

139145
/** Log an error exception and a message with optional format args. */
@@ -142,23 +148,26 @@ public class SentryTimberTree(
142148
message: String?,
143149
vararg args: Any?
144150
) {
151+
val tag = explicitTag.get()
145152
super.e(t, message, *args)
146-
logWithSentry(Log.ERROR, t, message, *args)
153+
logWithSentry(Log.ERROR, t, message, tag, *args)
147154
}
148155

149156
/** Log an error exception. */
150157
override fun e(t: Throwable?) {
158+
val tag = explicitTag.get()
151159
super.e(t)
152-
logWithSentry(Log.ERROR, t, null)
160+
logWithSentry(Log.ERROR, t, null, tag, null)
153161
}
154162

155163
/** Log an assert message with optional format args. */
156164
override fun wtf(
157165
message: String?,
158166
vararg args: Any?
159167
) {
168+
val tag = explicitTag.get()
160169
super.wtf(message, *args)
161-
logWithSentry(Log.ASSERT, null, message, *args)
170+
logWithSentry(Log.ASSERT, null, message, tag, *args)
162171
}
163172

164173
/** Log an assert exception and a message with optional format args. */
@@ -167,14 +176,16 @@ public class SentryTimberTree(
167176
message: String?,
168177
vararg args: Any?
169178
) {
179+
val tag = explicitTag.get()
170180
super.wtf(t, message, *args)
171-
logWithSentry(Log.ASSERT, t, message, *args)
181+
logWithSentry(Log.ASSERT, t, message, tag, *args)
172182
}
173183

174184
/** Log an assert exception. */
175185
override fun wtf(t: Throwable?) {
186+
val tag = explicitTag.get()
176187
super.wtf(t)
177-
logWithSentry(Log.ASSERT, t, null)
188+
logWithSentry(Log.ASSERT, t, null, tag, null)
178189
}
179190

180191
/** Log at `priority` a message with optional format args. */
@@ -183,8 +194,9 @@ public class SentryTimberTree(
183194
message: String?,
184195
vararg args: Any?
185196
) {
197+
val tag = explicitTag.get()
186198
super.log(priority, message, *args)
187-
logWithSentry(priority, null, message, *args)
199+
logWithSentry(priority, null, message, tag, *args)
188200
}
189201

190202
/** Log at `priority` an exception and a message with optional format args. */
@@ -194,8 +206,9 @@ public class SentryTimberTree(
194206
message: String?,
195207
vararg args: Any?
196208
) {
209+
val tag = explicitTag.get()
197210
super.log(priority, t, message, *args)
198-
logWithSentry(priority, t, message, *args)
211+
logWithSentry(priority, t, message, tag, *args)
199212
}
200213

201214
/** Log at `priority` an exception. */
@@ -204,26 +217,16 @@ public class SentryTimberTree(
204217
t: Throwable?
205218
) {
206219
super.log(priority, t)
207-
logWithSentry(priority, t, null)
208-
}
209-
210-
override fun log(
211-
priority: Int,
212-
tag: String?,
213-
message: String,
214-
t: Throwable?
215-
) {
216-
pendingTag.set(tag)
220+
logWithSentry(priority, t, null, tag, null)
217221
}
218222

219223
private fun logWithSentry(
220224
priority: Int,
221225
throwable: Throwable?,
222226
message: String?,
227+
tag: String?,
223228
vararg args: Any?
224229
) {
225-
val tag = retrieveTag()
226-
227230
if (message.isNullOrEmpty() && throwable == null) {
228231
return // Swallow message if it's null and there's no throwable
229232
}
@@ -238,7 +241,7 @@ public class SentryTimberTree(
238241
}
239242

240243
captureEvent(level, tag, sentryMessage, throwable)
241-
addBreadcrumb(level, sentryMessage, throwable)
244+
addBreadcrumb(level, sentryMessage, tag, throwable)
242245
}
243246

244247
/**
@@ -279,12 +282,13 @@ public class SentryTimberTree(
279282
private fun addBreadcrumb(
280283
sentryLevel: SentryLevel,
281284
msg: Message,
285+
tag: String?,
282286
throwable: Throwable?
283287
) {
284288
// checks the breadcrumb level
285289
if (isLoggable(sentryLevel, minBreadcrumbLevel)) {
286290
val throwableMsg = throwable?.message
287-
val breadCrumb = when {
291+
val breadcrumb = when {
288292
msg.message != null -> Breadcrumb().apply {
289293
level = sentryLevel
290294
category = "Timber"
@@ -295,11 +299,24 @@ public class SentryTimberTree(
295299
}
296300
else -> null
297301
}
298-
299-
breadCrumb?.let { scopes.addBreadcrumb(it) }
302+
if (breadcrumb != null) {
303+
if (tag != null) {
304+
breadcrumb.setData("tag", tag)
305+
}
306+
scopes.addBreadcrumb(breadcrumb)
307+
}
300308
}
301309
}
302310

311+
override fun log(
312+
priority: Int,
313+
tag: String?,
314+
message: String,
315+
t: Throwable?
316+
) {
317+
// no-op
318+
}
319+
303320
/**
304321
* Converts from Timber priority to SentryLevel.
305322
* Fallback to SentryLevel.DEBUG.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class SentryTimberIntegrationTest {
4343
val sut = fixture.getSut()
4444
sut.register(fixture.scopes, fixture.options)
4545

46-
assertEquals(1, Timber.treeCount())
46+
assertEquals(1, Timber.treeCount)
4747

4848
val trees = Timber.forest()
4949
val first = trees.first()
@@ -64,18 +64,18 @@ class SentryTimberIntegrationTest {
6464
val sut = fixture.getSut()
6565
sut.register(fixture.scopes, fixture.options)
6666

67-
assertEquals(1, Timber.treeCount())
67+
assertEquals(1, Timber.treeCount)
6868

6969
sut.close()
70-
assertEquals(0, Timber.treeCount())
70+
assertEquals(0, Timber.treeCount)
7171
}
7272

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

78-
assertEquals(0, Timber.treeCount())
78+
assertEquals(0, Timber.treeCount)
7979
}
8080

8181
@Test

sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberTreeTest.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,45 @@ class SentryTimberTreeTest {
269269
)
270270
}
271271

272+
@Test
273+
fun `Tree adds tag to breadcrumb data`() {
274+
val sut = fixture.getSut()
275+
Timber.plant(sut)
276+
277+
// when a tag is set via tag API
278+
Timber.tag("errorTag")
279+
sut.e("error")
280+
281+
// it should be added to the breadcrumb
282+
verify(fixture.scopes).addBreadcrumb(
283+
check<Breadcrumb> {
284+
assertEquals("error", it.message)
285+
assertEquals("errorTag", it.data["tag"])
286+
}
287+
)
288+
289+
// when a tag is set via method chaining
290+
Timber.tag("warnTag").w("warn")
291+
292+
// it should be added to the breadcrumb
293+
verify(fixture.scopes).addBreadcrumb(
294+
check<Breadcrumb> {
295+
assertEquals("warn", it.message)
296+
assertEquals("warnTag", it.data["tag"])
297+
}
298+
)
299+
300+
// when no tag is set
301+
Timber.w("warn without tag")
302+
// it should not have a tag in the breadcrumb
303+
verify(fixture.scopes).addBreadcrumb(
304+
check<Breadcrumb> {
305+
assertEquals("warn without tag", it.message)
306+
assertNull(it.data["tag"])
307+
}
308+
)
309+
}
310+
272311
@Test
273312
fun `Tree does not add a breadcrumb, if no message provided`() {
274313
val sut = fixture.getSut()

0 commit comments

Comments
 (0)