Skip to content

Commit

Permalink
fix: Do not include stacktrace into Timber message (#1898)
Browse files Browse the repository at this point in the history
Co-authored-by: Bruno Garcia <bruno@brunogarcia.com>
  • Loading branch information
romtsn and bruno-garcia committed Feb 8, 2022
1 parent 3cd777f commit af2b1a3
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 111 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,12 @@

## Unreleased

* Fix: Do not include stacktrace frames into Timber message (#1898)

Breaking changes:
`Timber.tag` is no longer supported by our [Timber integration](https://docs.sentry.io/platforms/android/configuration/integrations/timber/) and will not appear on Sentry for error events.
Please vote on this [issue](https://github.com/getsentry/sentry-java/issues/1900), if you'd like us to provide support for that.

## 5.6.1

* Fix: NPE while adding "response_body_size" breadcrumb, when response body is null (#1884)
Expand Down
21 changes: 21 additions & 0 deletions sentry-android-timber/api/sentry-android-timber.api
Expand Up @@ -19,5 +19,26 @@ public final class io/sentry/android/timber/SentryTimberIntegration : io/sentry/

public final class io/sentry/android/timber/SentryTimberTree : timber/log/Timber$Tree {
public fun <init> (Lio/sentry/IHub;Lio/sentry/SentryLevel;Lio/sentry/SentryLevel;)V
public fun d (Ljava/lang/String;[Ljava/lang/Object;)V
public fun d (Ljava/lang/Throwable;)V
public fun d (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun e (Ljava/lang/String;[Ljava/lang/Object;)V
public fun e (Ljava/lang/Throwable;)V
public fun e (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun i (Ljava/lang/String;[Ljava/lang/Object;)V
public fun i (Ljava/lang/Throwable;)V
public fun i (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (ILjava/lang/String;[Ljava/lang/Object;)V
public fun log (ILjava/lang/Throwable;)V
public fun log (ILjava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun v (Ljava/lang/String;[Ljava/lang/Object;)V
public fun v (Ljava/lang/Throwable;)V
public fun v (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun w (Ljava/lang/String;[Ljava/lang/Object;)V
public fun w (Ljava/lang/Throwable;)V
public fun w (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
public fun wtf (Ljava/lang/String;[Ljava/lang/Object;)V
public fun wtf (Ljava/lang/Throwable;)V
public fun wtf (Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
}

Expand Up @@ -11,48 +11,225 @@ import timber.log.Timber
/**
* Sentry Timber tree which is responsible to capture events via Timber
*/
@Suppress("TooManyFunctions") // we have to override all methods to be able to tweak logging
class SentryTimberTree(
private val hub: IHub,
private val minEventLevel: SentryLevel,
private val minBreadcrumbLevel: SentryLevel
) : Timber.Tree() {

/**
* do not log if it's lower than min. required level.
*/
private fun isLoggable(level: SentryLevel, minLevel: SentryLevel): Boolean = level.ordinal >= minLevel.ordinal
/** Log a verbose message with optional format args. */
override fun v(
message: String?,
vararg args: Any?
) {
logWithSentry(Log.VERBOSE, null, message, *args)
}

/** Log a verbose exception and a message with optional format args. */
override fun v(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.VERBOSE, t, message, *args)
}

/** Log a verbose exception. */
override fun v(t: Throwable?) {
logWithSentry(Log.VERBOSE, t, null)
}

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

/** Log a debug exception and a message with optional format args. */
override fun d(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.DEBUG, t, message, *args)
}

/** Log a debug exception. */
override fun d(t: Throwable?) {
logWithSentry(Log.DEBUG, t, null)
}

/** Log an info message with optional format args. */
override fun i(
message: String?,
vararg args: Any?
) {
logWithSentry(Log.INFO, null, message, *args)
}

/** Log an info exception and a message with optional format args. */
override fun i(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.INFO, t, message, *args)
}

/** Log an info exception. */
override fun i(t: Throwable?) {
logWithSentry(Log.INFO, t, null)
}

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

/** Log a warning exception and a message with optional format args. */
override fun w(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.WARN, t, message, *args)
}

/** Log a warning exception. */
override fun w(t: Throwable?) {
logWithSentry(Log.WARN, t, null)
}

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

/** Log an error exception and a message with optional format args. */
override fun e(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.ERROR, t, message, *args)
}

/** Log an error exception. */
override fun e(t: Throwable?) {
logWithSentry(Log.ERROR, t, null)
}

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

/** Log an assert exception and a message with optional format args. */
override fun wtf(
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(Log.ASSERT, t, message, *args)
}

/** Log an assert exception. */
override fun wtf(t: Throwable?) {
logWithSentry(Log.ASSERT, t, null)
}

/** Log at `priority` a message with optional format args. */
override fun log(
priority: Int,
message: String?,
vararg args: Any?
) {
logWithSentry(priority, null, message, *args)
}

/** Log at `priority` an exception and a message with optional format args. */
override fun log(
priority: Int,
t: Throwable?,
message: String?,
vararg args: Any?
) {
logWithSentry(priority, t, message, *args)
}

/** Log at `priority` an exception. */
override fun log(
priority: Int,
t: Throwable?
) {
logWithSentry(priority, t, null)
}

override fun log(
priority: Int,
tag: String?,
message: String,
t: Throwable?
) {
// no-op as we've overridden all the methods
}

private fun logWithSentry(
priority: Int,
throwable: Throwable?,
message: String?,
vararg args: Any?
) {
if (message.isNullOrEmpty() && throwable == null) {
return // Swallow message if it's null and there's no throwable
}

/**
* Captures a Sentry Event if the min. level is equal or higher than the min. required level.
*/
override fun log(priority: Int, tag: String?, message: String, throwable: Throwable?) {
val level = getSentryLevel(priority)
val sentryMessage = Message().apply {
this.message = message
if (!message.isNullOrEmpty() && args.isNotEmpty()) {
this.formatted = message?.format(*args)
}
this.params = args.map { it.toString() }
}

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

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

/**
* Captures an event with the given attributes
*/
private fun captureEvent(sentryLevel: SentryLevel, tag: String?, msg: String, throwable: Throwable?) {
private fun captureEvent(
sentryLevel: SentryLevel,
msg: Message,
throwable: Throwable?
) {
if (isLoggable(sentryLevel, minEventLevel)) {
val sentryEvent = SentryEvent().apply {

level = sentryLevel

throwable?.let {
setThrowable(it)
}

message = Message().apply {
formatted = msg
}

tag?.let {
setTag("TimberTag", it)
}

throwable?.let { setThrowable(it) }
message = msg
logger = "Timber"
}

Expand All @@ -63,16 +240,27 @@ class SentryTimberTree(
/**
* Adds a breadcrumb
*/
private fun addBreadcrumb(sentryLevel: SentryLevel, msg: String) {
private fun addBreadcrumb(
sentryLevel: SentryLevel,
msg: Message,
throwable: Throwable?
) {
// checks the breadcrumb level
if (isLoggable(sentryLevel, minBreadcrumbLevel)) {
val breadCrumb = Breadcrumb().apply {
level = sentryLevel
category = "Timber"
message = msg
val throwableMsg = throwable?.message
val breadCrumb = when {
msg.message != null -> Breadcrumb().apply {
level = sentryLevel
category = "Timber"
message = msg.message
}
throwableMsg != null -> Breadcrumb.error(throwableMsg).apply {
category = "exception"
}
else -> null
}

hub.addBreadcrumb(breadCrumb)
breadCrumb?.let { hub.addBreadcrumb(it) }
}
}

Expand Down

0 comments on commit af2b1a3

Please sign in to comment.