Skip to content

Commit

Permalink
Merge ff36acf into 986d057
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor authored Mar 28, 2023
2 parents 986d057 + ff36acf commit 6dbe27a
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Add time-to-initial-display and time-to-full-display measurements to Activity transactions ([#2611](https://github.com/getsentry/sentry-java/pull/2611))
- Read integration list written by sentry gradle plugin from manifest ([#2598](https://github.com/getsentry/sentry-java/pull/2598))
- Add Logcat adapter ([#2620](https://github.com/getsentry/sentry-java/pull/2620))

### Fixes

Expand Down
18 changes: 18 additions & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,24 @@ public final class io/sentry/android/core/SentryInitProvider {
public fun shutdown ()V
}

public final class io/sentry/android/core/SentryLogcatAdapter {
public fun <init> ()V
public static fun d (Ljava/lang/String;Ljava/lang/String;)I
public static fun d (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun e (Ljava/lang/String;Ljava/lang/String;)I
public static fun e (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun i (Ljava/lang/String;Ljava/lang/String;)I
public static fun i (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun v (Ljava/lang/String;Ljava/lang/String;)I
public static fun v (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun w (Ljava/lang/String;Ljava/lang/String;)I
public static fun w (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun w (Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun wtf (Ljava/lang/String;Ljava/lang/String;)I
public static fun wtf (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
public static fun wtf (Ljava/lang/String;Ljava/lang/Throwable;)I
}

public final class io/sentry/android/core/SentryPerformanceProvider : android/app/Application$ActivityLifecycleCallbacks {
public fun <init> ()V
public fun attachInfo (Landroid/content/Context;Landroid/content/pm/ProviderInfo;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package io.sentry.android.core;

import android.util.Log;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* This class replaces {@link android.util.Log} with its own implementations which creates a {@link
* io.sentry.Breadcrumb} for each log. It only replaces log functions that meet a minimum level set
* by the user on the Sentry Android Gradle Plugin.
*/
@ApiStatus.Internal
public final class SentryLogcatAdapter {

private static void addAsBreadcrumb(
@Nullable String tag, @NotNull SentryLevel level, @Nullable String msg) {
addAsBreadcrumb(tag, level, msg, null);
}

private static void addAsBreadcrumb(
@Nullable String tag, @NotNull SentryLevel level, @Nullable Throwable tr) {
addAsBreadcrumb(tag, level, null, tr);
}

private static void addAsBreadcrumb(
@Nullable final String tag,
@NotNull final SentryLevel level,
@Nullable final String msg,
@Nullable final Throwable tr) {
Breadcrumb breadcrumb = new Breadcrumb();
breadcrumb.setCategory("Logcat");
breadcrumb.setMessage(msg);
breadcrumb.setLevel(level);
if (tag != null) {
breadcrumb.setData("tag", tag);
}
if (tr != null && tr.getMessage() != null) {
breadcrumb.setData("throwable", tr.getMessage());
}
Sentry.addBreadcrumb(breadcrumb);
}

public static int v(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.DEBUG, msg);
return Log.v(tag, msg);
}

public static int v(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.DEBUG, msg, tr);
return Log.v(tag, msg, tr);
}

public static int d(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.DEBUG, msg);
return Log.d(tag, msg);
}

public static int d(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.DEBUG, msg, tr);
return Log.d(tag, msg, tr);
}

public static int i(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.INFO, msg);
return Log.i(tag, msg);
}

public static int i(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.INFO, msg, tr);
return Log.i(tag, msg, tr);
}

public static int w(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.WARNING, msg);
return Log.w(tag, msg);
}

public static int w(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.WARNING, msg, tr);
return Log.w(tag, msg, tr);
}

public static int w(@Nullable String tag, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.WARNING, tr);
return Log.w(tag, tr);
}

public static int e(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.ERROR, msg);
return Log.e(tag, msg);
}

public static int e(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.ERROR, msg, tr);
return Log.e(tag, msg, tr);
}

public static int wtf(@Nullable String tag, @Nullable String msg) {
addAsBreadcrumb(tag, SentryLevel.ERROR, msg);
return Log.wtf(tag, msg);
}

public static int wtf(@Nullable String tag, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.ERROR, tr);
return Log.wtf(tag, tr);
}

public static int wtf(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
addAsBreadcrumb(tag, SentryLevel.ERROR, msg, tr);
return Log.wtf(tag, msg, tr);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package io.sentry.android.core

import android.os.Bundle
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.sentry.Breadcrumb
import kotlin.test.BeforeTest
import kotlin.test.Test
import io.sentry.Sentry
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import org.junit.runner.RunWith
import java.lang.RuntimeException
import kotlin.test.assertEquals

@RunWith(AndroidJUnit4::class)
class SentryLogcatAdapterTest {
private val breadcrumbs = mutableListOf<Breadcrumb>()
private val tag = "my-tag"
private val commonMsg = "SentryLogcatAdapter"
private val throwable = RuntimeException("Test Exception")

class Fixture {

fun initSut(
autoInit: Boolean = false,
options: Sentry.OptionsConfiguration<SentryAndroidOptions>? = null
) {
val metadata = Bundle().apply {
putString(ManifestMetadataReader.DSN, "https://[email protected]/123")
putBoolean(ManifestMetadataReader.AUTO_INIT, autoInit)
}
val mockContext = ContextUtilsTest.mockMetaData(metaData = metadata)
when {
options != null -> SentryAndroid.init(mockContext, options)
else -> SentryAndroid.init(mockContext)
}
}
}

private val fixture = Fixture()

@BeforeTest
fun `set up`() {
Sentry.close()
AppStartState.getInstance().resetInstance()
breadcrumbs.clear()

fixture.initSut {
it.beforeBreadcrumb = SentryOptions.BeforeBreadcrumbCallback { breadcrumb, _ ->
breadcrumbs.add(breadcrumb)
breadcrumb
}
}

SentryLogcatAdapter.v(tag, "$commonMsg verbose")
SentryLogcatAdapter.i(tag, "$commonMsg info")
SentryLogcatAdapter.d(tag, "$commonMsg debug")
SentryLogcatAdapter.w(tag, "$commonMsg warning")
SentryLogcatAdapter.e(tag, "$commonMsg error")
SentryLogcatAdapter.wtf(tag, "$commonMsg wtf")
}

@Test
fun `verbose log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.DEBUG && it.message?.contains("verbose") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("verbose") == true)
}

@Test
fun `info log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.INFO && it.message?.contains("info") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("info") == true)
}

@Test
fun `debug log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.DEBUG && it.message?.contains("debug") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("debug") == true)
}

@Test
fun `warning log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.WARNING && it.message?.contains("warning") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("warning") == true)
}

@Test
fun `error log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.ERROR && it.message?.contains("error") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("error") == true)
}

@Test
fun `wtf log message has expected content`() {
val breadcrumb = breadcrumbs.find { it.level == SentryLevel.ERROR && it.message?.contains("wtf") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.data?.get("tag"))
assert(breadcrumb?.message?.contains("wtf") == true)
}

@Test
fun `e log throwable has expected content`() {
SentryLogcatAdapter.e(tag, "$commonMsg error exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.ERROR, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `v log throwable has expected content`() {
SentryLogcatAdapter.v(tag, "$commonMsg verbose exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.DEBUG, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `i log throwable has expected content`() {
SentryLogcatAdapter.i(tag, "$commonMsg info exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.INFO, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `d log throwable has expected content`() {
SentryLogcatAdapter.d(tag, "$commonMsg debug exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.DEBUG, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `w log throwable has expected content`() {
SentryLogcatAdapter.w(tag, "$commonMsg warning exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.WARNING, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `wtf log throwable has expected content`() {
SentryLogcatAdapter.wtf(tag, "$commonMsg wtf exception", throwable)

val breadcrumb = breadcrumbs.find { it.message?.contains("exception") ?: false }
assertEquals("Logcat", breadcrumb?.category)
assertEquals(tag, breadcrumb?.getData("tag"))
assertEquals(SentryLevel.ERROR, breadcrumb?.level)
assertEquals(throwable.message, breadcrumb?.getData("throwable"))
}

@Test
fun `logs add correct number of breadcrumb`() {
assertEquals(6, breadcrumbs.filter {
it.message?.contains("SentryLogcatAdapter") ?: false
}.size)
}
}

0 comments on commit 6dbe27a

Please sign in to comment.