Skip to content

Commit dd482b5

Browse files
authored
Merge 86007fb into a42eb85
2 parents a42eb85 + 86007fb commit dd482b5

File tree

6 files changed

+132
-8
lines changed

6 files changed

+132
-8
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
### Fixes
66

7+
- Send Timber logs through Sentry Logs ([#4490](https://github.com/getsentry/sentry-java/pull/4490))
8+
- Enable the Logs feature in your `SentryOptions` or with the `io.sentry.logs.enabled` manifest option and the SDK will automatically send Timber logs to Sentry, if the TimberIntegration is enabled.
9+
- The SDK will automatically detect Timber and use it to send logs to Sentry.
710
- Send logcat through Sentry Logs ([#4487](https://github.com/getsentry/sentry-java/pull/4487))
811
- Enable the Logs feature in your `SentryOptions` or with the `io.sentry.logs.enabled` manifest option and the SDK will automatically send logcat logs to Sentry, if the Sentry Android Gradle plugin is applied.
912
- To set the logcat level check the [Logcat integration documentation](https://docs.sentry.io/platforms/android/integrations/logcat/#configure).

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ public final class io/sentry/android/timber/BuildConfig {
99

1010
public final class io/sentry/android/timber/SentryTimberIntegration : io/sentry/Integration, java/io/Closeable {
1111
public fun <init> ()V
12-
public fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;)V
13-
public synthetic fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
12+
public fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;)V
13+
public synthetic fun <init> (Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
1414
public fun close ()V
1515
public final fun getMinBreadcrumbLevel ()Lio/sentry/SentryLevel;
1616
public final fun getMinEventLevel ()Lio/sentry/SentryLevel;
17+
public final fun getMinLogsLevel ()Lio/sentry/SentryLogLevel;
1718
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
1819
}
1920

2021
public final class io/sentry/android/timber/SentryTimberTree : timber/log/Timber$Tree {
21-
public fun <init> (Lio/sentry/IScopes;Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;)V
22+
public fun <init> (Lio/sentry/IScopes;Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;)V
23+
public synthetic fun <init> (Lio/sentry/IScopes;Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;Lio/sentry/SentryLogLevel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
2224
public fun d (Ljava/lang/String;[Ljava/lang/Object;)V
2325
public fun d (Ljava/lang/Throwable;)V
2426
public fun d (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.sentry.IScopes
55
import io.sentry.Integration
66
import io.sentry.SentryIntegrationPackageStorage
77
import io.sentry.SentryLevel
8+
import io.sentry.SentryLogLevel
89
import io.sentry.SentryOptions
910
import io.sentry.android.timber.BuildConfig.VERSION_NAME
1011
import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
@@ -15,6 +16,7 @@ import timber.log.Timber
1516
public class SentryTimberIntegration(
1617
public val minEventLevel: SentryLevel = SentryLevel.ERROR,
1718
public val minBreadcrumbLevel: SentryLevel = SentryLevel.INFO,
19+
public val minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
1820
) : Integration, Closeable {
1921
private lateinit var tree: SentryTimberTree
2022
private lateinit var logger: ILogger
@@ -29,7 +31,7 @@ public class SentryTimberIntegration(
2931
override fun register(scopes: IScopes, options: SentryOptions) {
3032
logger = options.logger
3133

32-
tree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel)
34+
tree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel, minLogsLevel)
3335
Timber.plant(tree)
3436

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

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.sentry.Breadcrumb
55
import io.sentry.IScopes
66
import io.sentry.SentryEvent
77
import io.sentry.SentryLevel
8+
import io.sentry.SentryLogLevel
89
import io.sentry.protocol.Message
910
import timber.log.Timber
1011

@@ -14,6 +15,7 @@ public class SentryTimberTree(
1415
private val scopes: IScopes,
1516
private val minEventLevel: SentryLevel,
1617
private val minBreadcrumbLevel: SentryLevel,
18+
private val minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
1719
) : Timber.Tree() {
1820
private val pendingTag = ThreadLocal<String?>()
1921

@@ -168,6 +170,7 @@ public class SentryTimberTree(
168170
}
169171

170172
val level = getSentryLevel(priority)
173+
val logLevel = getSentryLogLevel(priority)
171174
val sentryMessage =
172175
Message().apply {
173176
this.message = message
@@ -179,12 +182,17 @@ public class SentryTimberTree(
179182

180183
captureEvent(level, tag, sentryMessage, throwable)
181184
addBreadcrumb(level, sentryMessage, throwable)
185+
addLog(logLevel, message, throwable, *args)
182186
}
183187

184188
/** do not log if it's lower than min. required level. */
185189
private fun isLoggable(level: SentryLevel, minLevel: SentryLevel): Boolean =
186190
level.ordinal >= minLevel.ordinal
187191

192+
/** do not log if it's lower than min. required level. */
193+
private fun isLoggable(level: SentryLogLevel, minLevel: SentryLogLevel): Boolean =
194+
level.ordinal >= minLevel.ordinal
195+
188196
/** Captures an event with the given attributes */
189197
private fun captureEvent(
190198
sentryLevel: SentryLevel,
@@ -227,6 +235,23 @@ public class SentryTimberTree(
227235
}
228236
}
229237

238+
/** Send a Sentry Logs */
239+
private fun addLog(
240+
sentryLogLevel: SentryLogLevel,
241+
msg: String?,
242+
throwable: Throwable?,
243+
vararg args: Any?,
244+
) {
245+
// checks the log level
246+
if (isLoggable(sentryLogLevel, minLogsLevel)) {
247+
val throwableMsg = throwable?.message
248+
when {
249+
msg != null -> scopes.logger().log(sentryLogLevel, msg, *args)
250+
throwableMsg != null -> scopes.logger().log(sentryLogLevel, throwableMsg, *args)
251+
}
252+
}
253+
}
254+
230255
/** Converts from Timber priority to SentryLevel. Fallback to SentryLevel.DEBUG. */
231256
private fun getSentryLevel(priority: Int): SentryLevel =
232257
when (priority) {
@@ -238,4 +263,17 @@ public class SentryTimberTree(
238263
Log.VERBOSE -> SentryLevel.DEBUG
239264
else -> SentryLevel.DEBUG
240265
}
266+
267+
/** Converts from Timber priority to SentryLogLevel. Fallback to SentryLogLevel.DEBUG. */
268+
private fun getSentryLogLevel(priority: Int): SentryLogLevel {
269+
return when (priority) {
270+
Log.ASSERT -> SentryLogLevel.FATAL
271+
Log.ERROR -> SentryLogLevel.ERROR
272+
Log.WARN -> SentryLogLevel.WARN
273+
Log.INFO -> SentryLogLevel.INFO
274+
Log.DEBUG -> SentryLogLevel.DEBUG
275+
Log.VERBOSE -> SentryLogLevel.TRACE
276+
else -> SentryLogLevel.DEBUG
277+
}
278+
}
241279
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.sentry.android.timber
22

33
import io.sentry.IScopes
44
import io.sentry.SentryLevel
5+
import io.sentry.SentryLogLevel
56
import io.sentry.SentryOptions
67
import io.sentry.protocol.SdkVersion
78
import kotlin.test.BeforeTest
@@ -21,10 +22,12 @@ class SentryTimberIntegrationTest {
2122
fun getSut(
2223
minEventLevel: SentryLevel = SentryLevel.ERROR,
2324
minBreadcrumbLevel: SentryLevel = SentryLevel.INFO,
25+
minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
2426
): SentryTimberIntegration =
2527
SentryTimberIntegration(
2628
minEventLevel = minEventLevel,
2729
minBreadcrumbLevel = minBreadcrumbLevel,
30+
minLogsLevel = minLogsLevel,
2831
)
2932
}
3033

@@ -78,11 +81,16 @@ class SentryTimberIntegrationTest {
7881
@Test
7982
fun `Integrations pass the right min levels`() {
8083
val sut =
81-
fixture.getSut(minEventLevel = SentryLevel.INFO, minBreadcrumbLevel = SentryLevel.DEBUG)
84+
fixture.getSut(
85+
minEventLevel = SentryLevel.INFO,
86+
minBreadcrumbLevel = SentryLevel.DEBUG,
87+
minLogsLevel = SentryLogLevel.TRACE,
88+
)
8289
sut.register(fixture.scopes, fixture.options)
8390

8491
assertEquals(sut.minEventLevel, SentryLevel.INFO)
8592
assertEquals(sut.minBreadcrumbLevel, SentryLevel.DEBUG)
93+
assertEquals(sut.minLogsLevel, SentryLogLevel.TRACE)
8694
}
8795

8896
@Test

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

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,39 @@
11
package io.sentry.android.timber
22

33
import io.sentry.Breadcrumb
4-
import io.sentry.IScopes
4+
import io.sentry.Scopes
55
import io.sentry.SentryLevel
6+
import io.sentry.SentryLogLevel
7+
import io.sentry.logger.ILoggerApi
68
import kotlin.test.BeforeTest
79
import kotlin.test.Test
810
import kotlin.test.assertEquals
911
import kotlin.test.assertNotNull
1012
import kotlin.test.assertNull
1113
import org.mockito.kotlin.any
1214
import org.mockito.kotlin.check
15+
import org.mockito.kotlin.eq
1316
import org.mockito.kotlin.mock
1417
import org.mockito.kotlin.never
1518
import org.mockito.kotlin.verify
19+
import org.mockito.kotlin.verifyNoInteractions
20+
import org.mockito.kotlin.whenever
1621
import timber.log.Timber
1722

1823
class SentryTimberTreeTest {
1924
private class Fixture {
20-
val scopes = mock<IScopes>()
25+
val scopes = mock<Scopes>()
26+
val logs = mock<ILoggerApi>()
27+
28+
init {
29+
whenever(scopes.logger()).thenReturn(logs)
30+
}
2131

2232
fun getSut(
2333
minEventLevel: SentryLevel = SentryLevel.ERROR,
2434
minBreadcrumbLevel: SentryLevel = SentryLevel.INFO,
25-
): SentryTimberTree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel)
35+
minLogsLevel: SentryLogLevel = SentryLogLevel.INFO,
36+
): SentryTimberTree = SentryTimberTree(scopes, minEventLevel, minBreadcrumbLevel, minLogsLevel)
2637
}
2738

2839
private val fixture = Fixture()
@@ -231,4 +242,64 @@ class SentryTimberTreeTest {
231242
val sut = fixture.getSut()
232243
sut.d("test %s, %s", 1, 1)
233244
}
245+
246+
@Test
247+
fun `Tree adds a log with message and arguments, when provided`() {
248+
val sut = fixture.getSut()
249+
sut.e("test count: %d %d", 32, 5)
250+
251+
verify(fixture.logs).log(eq(SentryLogLevel.ERROR), eq("test count: %d %d"), eq(32), eq(5))
252+
}
253+
254+
@Test
255+
fun `Tree adds a log if min level is equal`() {
256+
val sut = fixture.getSut()
257+
sut.i(Throwable("test"))
258+
verify(fixture.logs).log(any(), any())
259+
}
260+
261+
@Test
262+
fun `Tree adds a log if min level is higher`() {
263+
val sut = fixture.getSut()
264+
sut.e(Throwable("test"))
265+
verify(fixture.logs).log(any(), any<String>(), any())
266+
}
267+
268+
@Test
269+
fun `Tree won't add a log if min level is lower`() {
270+
val sut = fixture.getSut(minLogsLevel = SentryLogLevel.ERROR)
271+
sut.i(Throwable("test"))
272+
verifyNoInteractions(fixture.logs)
273+
}
274+
275+
@Test
276+
fun `Tree adds an info log`() {
277+
val sut = fixture.getSut()
278+
sut.i("message")
279+
280+
verify(fixture.logs).log(eq(SentryLogLevel.INFO), eq("message"))
281+
}
282+
283+
@Test
284+
fun `Tree adds an error log`() {
285+
val sut = fixture.getSut()
286+
sut.e(Throwable("test"))
287+
288+
verify(fixture.logs).log(eq(SentryLogLevel.ERROR), eq("test"))
289+
}
290+
291+
@Test
292+
fun `Tree does not add a log, if no message or throwable is provided`() {
293+
val sut = fixture.getSut()
294+
sut.e(null as String?)
295+
verifyNoInteractions(fixture.logs)
296+
}
297+
298+
@Test
299+
fun `Tree logs throwable`() {
300+
val sut = fixture.getSut()
301+
sut.e(Throwable("throwable message"))
302+
303+
verify(fixture.logs).log(eq(SentryLogLevel.ERROR), eq("throwable message"))
304+
}
234305
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy