From 0c858b4a27d4927517d984a9a1132f5403f3d706 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 31 Aug 2020 22:04:48 +0200 Subject: [PATCH 1/3] Attach breadcrumbs to events triggered in Logback integration. --- .../io/sentry/logback/SentryAppender.java | 35 +++++++++++++- .../io/sentry/logback/SentryAppenderTest.kt | 47 +++++++++++++++++-- .../src/main/resources/logback.xml | 8 ++-- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java index 5063a60bc..c8fdb309d 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -4,6 +4,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.logback.core.UnsynchronizedAppenderBase; +import io.sentry.core.Breadcrumb; import io.sentry.core.DateUtils; import io.sentry.core.Sentry; import io.sentry.core.SentryEvent; @@ -29,6 +30,8 @@ public final class SentryAppender extends UnsynchronizedAppenderBase { private @Nullable SentryOptions options; private @Nullable ITransport transport; + private @Nullable Level minimumBreadcrumbLevel; + private @Nullable Level minimumEventLevel; @Override public void start() { @@ -43,7 +46,13 @@ public void start() { @Override protected void append(@NotNull ILoggingEvent eventObject) { - Sentry.captureEvent(createEvent(eventObject)); + if (minimumEventLevel == null || eventObject.getLevel().isGreaterOrEqual(minimumEventLevel)) { + Sentry.captureEvent(createEvent(eventObject)); + } + if (minimumBreadcrumbLevel == null + || eventObject.getLevel().isGreaterOrEqual(minimumBreadcrumbLevel)) { + Sentry.addBreadcrumb(createBreadcrumb(eventObject)); + } } /** @@ -93,6 +102,20 @@ protected void append(@NotNull ILoggingEvent eventObject) { } } + /** + * Creates {@link Breadcrumb} from Logback's {@link ILoggingEvent}. + * + * @param loggingEvent the logback event + * @return the sentry breadcrumb + */ + private @NotNull Breadcrumb createBreadcrumb(final @NotNull ILoggingEvent loggingEvent) { + final Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setLevel(formatLevel(loggingEvent.getLevel())); + breadcrumb.setCategory(loggingEvent.getLoggerName()); + breadcrumb.setMessage(loggingEvent.getFormattedMessage()); + return breadcrumb; + } + /** * Transforms a {@link Level} into an {@link SentryLevel}. * @@ -126,10 +149,18 @@ protected void append(@NotNull ILoggingEvent eventObject) { return sdkVersion; } - public void setOptions(SentryOptions options) { + public void setOptions(final @Nullable SentryOptions options) { this.options = options; } + public void setMinimumBreadcrumbLevel(final @Nullable Level minimumBreadcrumbLevel) { + this.minimumBreadcrumbLevel = minimumBreadcrumbLevel; + } + + public void setMinimumEventLevel(final @Nullable Level minimumEventLevel) { + this.minimumEventLevel = minimumEventLevel; + } + @ApiStatus.Internal void setTransport(@Nullable ITransport transport) { this.transport = transport; diff --git a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt index 262e4b3d9..90b85a3e7 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -1,6 +1,7 @@ package io.sentry.logback import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Level.WARN import ch.qos.logback.classic.LoggerContext import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.check @@ -28,31 +29,30 @@ import org.slf4j.LoggerFactory import org.slf4j.MDC class SentryAppenderTest { - private class Fixture { + private class Fixture(minimumBreadcrumbLevel: Level? = null, minimumEventLevel: Level? = null) { val transport = mock() val logger: Logger = LoggerFactory.getLogger(SentryAppenderTest::class.java) val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext init { whenever(transport.send(any())).thenReturn(TransportResult.success()) - val appender = SentryAppender() val options = SentryOptions() options.dsn = "http://key@localhost/proj" appender.setOptions(options) + appender.setMinimumBreadcrumbLevel(minimumBreadcrumbLevel) + appender.setMinimumEventLevel(minimumEventLevel) appender.context = loggerContext appender.setTransport(transport) - val rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME) rootLogger.level = Level.TRACE rootLogger.addAppender(appender) - appender.start() loggerContext.start() } } - private val fixture = Fixture() + private lateinit var fixture: Fixture @AfterTest fun `stop logback`() { @@ -66,6 +66,7 @@ class SentryAppenderTest { @Test fun `converts message`() { + fixture = Fixture() fixture.logger.debug("testing message conversion {}, {}", 1, 2) await.untilAsserted { @@ -80,6 +81,7 @@ class SentryAppenderTest { @Test fun `event date is in UTC`() { + fixture = Fixture() val utcTime = LocalDateTime.now(ZoneId.of("UTC")) fixture.logger.debug("testing event date") @@ -98,6 +100,7 @@ class SentryAppenderTest { @Test fun `converts trace log level to Sentry level`() { + fixture = Fixture() fixture.logger.trace("testing trace level") await.untilAsserted { @@ -109,6 +112,7 @@ class SentryAppenderTest { @Test fun `converts debug log level to Sentry level`() { + fixture = Fixture() fixture.logger.debug("testing debug level") await.untilAsserted { @@ -120,6 +124,7 @@ class SentryAppenderTest { @Test fun `converts info log level to Sentry level`() { + fixture = Fixture() fixture.logger.info("testing info level") await.untilAsserted { @@ -131,6 +136,7 @@ class SentryAppenderTest { @Test fun `converts warn log level to Sentry level`() { + fixture = Fixture() fixture.logger.warn("testing warn level") await.untilAsserted { @@ -142,6 +148,7 @@ class SentryAppenderTest { @Test fun `converts error log level to Sentry level`() { + fixture = Fixture() fixture.logger.error("testing error level") await.untilAsserted { @@ -153,6 +160,7 @@ class SentryAppenderTest { @Test fun `attaches thread information`() { + fixture = Fixture() fixture.logger.warn("testing thread information") await.untilAsserted { @@ -164,6 +172,7 @@ class SentryAppenderTest { @Test fun `sets tags from MDC`() { + fixture = Fixture() MDC.put("key", "value") fixture.logger.warn("testing MDC tags") @@ -176,6 +185,7 @@ class SentryAppenderTest { @Test fun `does not create MDC context when no MDC tags are set`() { + fixture = Fixture() fixture.logger.warn("testing without MDC tags") await.untilAsserted { @@ -187,6 +197,7 @@ class SentryAppenderTest { @Test fun `attaches throwable`() { + fixture = Fixture() val throwable = RuntimeException("something went wrong") fixture.logger.warn("testing throwable", throwable) @@ -199,6 +210,7 @@ class SentryAppenderTest { @Test fun `sets SDK version`() { + fixture = Fixture() fixture.logger.info("testing sdk version") await.untilAsserted { @@ -213,4 +225,29 @@ class SentryAppenderTest { }) } } + + @Test + fun `attaches breadcrumbs`() { + fixture = Fixture(minimumBreadcrumbLevel = Level.DEBUG, minimumEventLevel = WARN) + val utcTime = LocalDateTime.now(ZoneId.of("UTC")) + + fixture.logger.debug("this should be a breadcrumb #1") + fixture.logger.info("this should be a breadcrumb #2") + fixture.logger.warn("testing message with breadcrumbs") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(2, it.breadcrumbs.size) + val breadcrumb = it.breadcrumbs[0] + val breadcrumbTime = Instant.ofEpochMilli(it.timestamp.time) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + assertTrue { breadcrumbTime.plusSeconds(1).isAfter(utcTime) } + assertTrue { breadcrumbTime.minusSeconds(1).isBefore(utcTime) } + assertEquals("this should be a breadcrumb #1", breadcrumb.message) + assertEquals("io.sentry.logback.SentryAppenderTest", breadcrumb.category) + assertEquals(SentryLevel.DEBUG, breadcrumb.level) + }) + } + } } diff --git a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml index e0004e806..449b84d92 100644 --- a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml +++ b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml @@ -11,13 +11,11 @@ https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 - - - - - + WARN + DEBUG + From b0ec49d830d63243fd5ce92fc9066e87eef6c376 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 31 Aug 2020 23:11:38 +0200 Subject: [PATCH 2/3] Add default log levels, add more test cases. --- .../io/sentry/logback/SentryAppender.java | 17 ++--- .../io/sentry/logback/SentryAppenderTest.kt | 63 ++++++++++++++----- .../src/main/resources/logback.xml | 3 + 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java index c8fdb309d..fb2236b8e 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -30,8 +30,8 @@ public final class SentryAppender extends UnsynchronizedAppenderBase { private @Nullable SentryOptions options; private @Nullable ITransport transport; - private @Nullable Level minimumBreadcrumbLevel; - private @Nullable Level minimumEventLevel; + private @NotNull Level minimumBreadcrumbLevel = Level.INFO; + private @NotNull Level minimumEventLevel = Level.ERROR; @Override public void start() { @@ -46,11 +46,10 @@ public void start() { @Override protected void append(@NotNull ILoggingEvent eventObject) { - if (minimumEventLevel == null || eventObject.getLevel().isGreaterOrEqual(minimumEventLevel)) { + if (eventObject.getLevel().isGreaterOrEqual(minimumEventLevel)) { Sentry.captureEvent(createEvent(eventObject)); } - if (minimumBreadcrumbLevel == null - || eventObject.getLevel().isGreaterOrEqual(minimumBreadcrumbLevel)) { + if (eventObject.getLevel().isGreaterOrEqual(minimumBreadcrumbLevel)) { Sentry.addBreadcrumb(createBreadcrumb(eventObject)); } } @@ -154,11 +153,15 @@ public void setOptions(final @Nullable SentryOptions options) { } public void setMinimumBreadcrumbLevel(final @Nullable Level minimumBreadcrumbLevel) { - this.minimumBreadcrumbLevel = minimumBreadcrumbLevel; + if (minimumBreadcrumbLevel != null) { + this.minimumBreadcrumbLevel = minimumBreadcrumbLevel; + } } public void setMinimumEventLevel(final @Nullable Level minimumEventLevel) { - this.minimumEventLevel = minimumEventLevel; + if (minimumEventLevel != null) { + this.minimumEventLevel = minimumEventLevel; + } } @ApiStatus.Internal diff --git a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt index 90b85a3e7..0eb02a366 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -1,7 +1,6 @@ package io.sentry.logback import ch.qos.logback.classic.Level -import ch.qos.logback.classic.Level.WARN import ch.qos.logback.classic.LoggerContext import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.check @@ -66,7 +65,7 @@ class SentryAppenderTest { @Test fun `converts message`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.DEBUG) fixture.logger.debug("testing message conversion {}, {}", 1, 2) await.untilAsserted { @@ -81,7 +80,7 @@ class SentryAppenderTest { @Test fun `event date is in UTC`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.DEBUG) val utcTime = LocalDateTime.now(ZoneId.of("UTC")) fixture.logger.debug("testing event date") @@ -100,7 +99,7 @@ class SentryAppenderTest { @Test fun `converts trace log level to Sentry level`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.TRACE) fixture.logger.trace("testing trace level") await.untilAsserted { @@ -112,7 +111,7 @@ class SentryAppenderTest { @Test fun `converts debug log level to Sentry level`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.DEBUG) fixture.logger.debug("testing debug level") await.untilAsserted { @@ -124,7 +123,7 @@ class SentryAppenderTest { @Test fun `converts info log level to Sentry level`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.INFO) fixture.logger.info("testing info level") await.untilAsserted { @@ -136,7 +135,7 @@ class SentryAppenderTest { @Test fun `converts warn log level to Sentry level`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing warn level") await.untilAsserted { @@ -148,7 +147,7 @@ class SentryAppenderTest { @Test fun `converts error log level to Sentry level`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.ERROR) fixture.logger.error("testing error level") await.untilAsserted { @@ -160,7 +159,7 @@ class SentryAppenderTest { @Test fun `attaches thread information`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing thread information") await.untilAsserted { @@ -172,7 +171,7 @@ class SentryAppenderTest { @Test fun `sets tags from MDC`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.WARN) MDC.put("key", "value") fixture.logger.warn("testing MDC tags") @@ -185,7 +184,7 @@ class SentryAppenderTest { @Test fun `does not create MDC context when no MDC tags are set`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing without MDC tags") await.untilAsserted { @@ -197,7 +196,7 @@ class SentryAppenderTest { @Test fun `attaches throwable`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.WARN) val throwable = RuntimeException("something went wrong") fixture.logger.warn("testing throwable", throwable) @@ -210,7 +209,7 @@ class SentryAppenderTest { @Test fun `sets SDK version`() { - fixture = Fixture() + fixture = Fixture(minimumEventLevel = Level.INFO) fixture.logger.info("testing sdk version") await.untilAsserted { @@ -227,8 +226,8 @@ class SentryAppenderTest { } @Test - fun `attaches breadcrumbs`() { - fixture = Fixture(minimumBreadcrumbLevel = Level.DEBUG, minimumEventLevel = WARN) + fun `attaches breadcrumbs with level higher than minimumBreadcrumbLevel`() { + fixture = Fixture(minimumBreadcrumbLevel = Level.DEBUG, minimumEventLevel = Level.WARN) val utcTime = LocalDateTime.now(ZoneId.of("UTC")) fixture.logger.debug("this should be a breadcrumb #1") @@ -250,4 +249,38 @@ class SentryAppenderTest { }) } } + + @Test + fun `does not attach breadcrumbs with level lower than minimumBreadcrumbLevel`() { + fixture = Fixture(minimumBreadcrumbLevel = Level.INFO, minimumEventLevel = Level.WARN) + + fixture.logger.debug("this should NOT be a breadcrumb") + fixture.logger.info("this should be a breadcrumb") + fixture.logger.warn("testing message with breadcrumbs") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(1, it.breadcrumbs.size) + assertEquals("this should be a breadcrumb", it.breadcrumbs[0].message) + }) + } + } + + @Test + fun `attaches breadcrumbs for default appender configuration`() { + fixture = Fixture() + + fixture.logger.debug("this should not be a breadcrumb as the level is lower than the minimum INFO") + fixture.logger.info("this should be a breadcrumb") + fixture.logger.warn("this should not be sent as the event but be a breadcrumb") + fixture.logger.error("this should be sent as the event") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(2, it.breadcrumbs.size) + assertEquals("this should be a breadcrumb", it.breadcrumbs[0].message) + assertEquals("this should not be sent as the event but be a breadcrumb", it.breadcrumbs[1].message) + }) + } + } } diff --git a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml index 449b84d92..11a0fa00b 100644 --- a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml +++ b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml @@ -11,7 +11,10 @@ https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 + + WARN + DEBUG From 045b0a99c1871eff96348447f26d7b1ed10e635b Mon Sep 17 00:00:00 2001 From: Bruno Garcia Date: Mon, 31 Aug 2020 17:42:02 -0400 Subject: [PATCH 3/3] Update sentry-samples/sentry-samples-logback/src/main/resources/logback.xml --- .../sentry-samples-logback/src/main/resources/logback.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml index 11a0fa00b..76de7f2f3 100644 --- a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml +++ b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml @@ -14,7 +14,7 @@ WARN - + DEBUG