Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Do not include stacktrace into Timber message #1898

Merged
merged 10 commits into from Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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