From 7bbbe08ce71cbb0a0e96c60dc29b5f7028a498fc Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Thu, 23 Jul 2020 14:14:22 +0200 Subject: [PATCH 01/28] ref: fix test linting (#491) --- .../io/sentry/core/DiagnosticLoggerTest.kt | 32 +++++++++---------- ...CachedEventFireAndForgetIntegrationTest.kt | 6 ++-- .../java/io/sentry/core/SentryClientTest.kt | 13 -------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt b/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt index f30280854..110a5e23d 100644 --- a/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt @@ -39,7 +39,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true and level is set to null, a call to log does not throw`() { - fixture.options!!.setDiagnosticLevel(null) + fixture.options.setDiagnosticLevel(null) fixture.getSut().log(SentryLevel.DEBUG, expectedMessage) } @@ -61,7 +61,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true and option level is info, a call to log and level debug is not logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.INFO) + fixture.options.setDiagnosticLevel(SentryLevel.INFO) val sut = fixture.getSut() val expectedLevel = SentryLevel.DEBUG sut.log(expectedLevel, expectedMessage) @@ -70,7 +70,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true and option level is error, a call to log and level fatal is logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.ERROR) + fixture.options.setDiagnosticLevel(SentryLevel.ERROR) val sut = fixture.getSut() val expectedLevel = SentryLevel.FATAL sut.log(expectedLevel, expectedMessage) @@ -79,7 +79,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is false and option level is fatal, a call to log and level error is not logged`() { - fixture.options!!.isDebug = false + fixture.options.isDebug = false val sut = fixture.getSut() val expectedLevel = SentryLevel.FATAL sut.log(expectedLevel, expectedMessage) @@ -88,7 +88,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true option level is info, a call to log and level debug is not logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.FATAL) + fixture.options.setDiagnosticLevel(SentryLevel.FATAL) val sut = fixture.getSut() val expectedLevel = SentryLevel.DEBUG sut.log(expectedLevel, expectedMessage) @@ -97,7 +97,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true option level is debug, a call to log with throwable and level info is logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.DEBUG) + fixture.options.setDiagnosticLevel(SentryLevel.DEBUG) val sut = fixture.getSut() val expectedLevel = SentryLevel.INFO sut.log(expectedLevel, expectedMessage, expectedThrowable) @@ -106,8 +106,8 @@ class DiagnosticLoggerTest { @Test fun `when debug is false option level is debug, a call to log with throwable and level info is not logged`() { - fixture.options!!.isDebug = false - fixture.options!!.setDiagnosticLevel(SentryLevel.DEBUG) + fixture.options.isDebug = false + fixture.options.setDiagnosticLevel(SentryLevel.DEBUG) val sut = fixture.getSut() val expectedLevel = SentryLevel.INFO sut.log(expectedLevel, expectedMessage, expectedThrowable) @@ -116,7 +116,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true option level is error, a call to log with throwable and level fatal is logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.ERROR) + fixture.options.setDiagnosticLevel(SentryLevel.ERROR) val sut = fixture.getSut() val expectedLevel = SentryLevel.FATAL sut.log(expectedLevel, expectedMessage, expectedThrowable) @@ -125,26 +125,26 @@ class DiagnosticLoggerTest { @Test fun `when debug is true option level is error, a call to log with throwable and level error is logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.ERROR) + fixture.options.setDiagnosticLevel(SentryLevel.ERROR) val sut = fixture.getSut() - val expectedLevel = fixture.options!!.diagnosticLevel + val expectedLevel = fixture.options.diagnosticLevel sut.log(expectedLevel, expectedMessage, expectedThrowable) verify(fixture.logger)!!.log(expectedLevel, expectedMessage, expectedThrowable) } @Test fun `when debug is true option level is error, a call to log and level error is logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.ERROR) + fixture.options.setDiagnosticLevel(SentryLevel.ERROR) val sut = fixture.getSut() - val expectedLevel = fixture.options!!.diagnosticLevel + val expectedLevel = fixture.options.diagnosticLevel sut.log(expectedLevel, expectedMessage) verify(fixture.logger)!!.log(expectedLevel, expectedMessage) } @Test fun `when debug is false option level is fatal, a call to log with throwable and level error is not logged`() { - fixture.options!!.isDebug = false - fixture.options!!.setDiagnosticLevel(SentryLevel.FATAL) + fixture.options.isDebug = false + fixture.options.setDiagnosticLevel(SentryLevel.FATAL) val sut = fixture.getSut() val expectedLevel = SentryLevel.ERROR sut.log(expectedLevel, expectedMessage, expectedThrowable) @@ -153,7 +153,7 @@ class DiagnosticLoggerTest { @Test fun `when debug is true option level is info, a call to log with throwable and level debug is not logged`() { - fixture.options!!.setDiagnosticLevel(SentryLevel.INFO) + fixture.options.setDiagnosticLevel(SentryLevel.INFO) val sut = fixture.getSut() val expectedLevel = SentryLevel.DEBUG sut.log(expectedLevel, expectedMessage, expectedThrowable) diff --git a/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt b/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt index 786910dfb..9c242ff75 100644 --- a/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt @@ -37,19 +37,19 @@ class SendCachedEventFireAndForgetIntegrationTest { @Test fun `path is invalid if it is null`() { - val sut = fixture.getSut() + fixture.getSut() assertFalse(fixture.callback.hasValidPath(null, fixture.logger)) } @Test fun `path is invalid if it is empty`() { - val sut = fixture.getSut() + fixture.getSut() assertFalse(fixture.callback.hasValidPath("", fixture.logger)) } @Test fun `path is valid if not null or empty`() { - val sut = fixture.getSut() + fixture.getSut() assertFalse(fixture.callback.hasValidPath("cache", fixture.logger)) } diff --git a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt index 967ad52ac..560ed7e02 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt @@ -403,19 +403,6 @@ class SentryClientTest { assertEquals(transportGate, sentryOptions.transportGate) } - @Test - fun `when transport gate is null, it should init an always on transport gate`() { - val sentryOptions: SentryOptions = SentryOptions().apply { - dsn = dsnString - } - - val connection = mock() - SentryClient(sentryOptions, connection) - - assertNotNull(sentryOptions.transportGate) - assertTrue(sentryOptions.transportGate!!.isConnected) - } - @Test fun `when scope has event processors, they should be applied`() { val event = SentryEvent() From 95cc5f4a72220e7ab4b72d1bcccacf6d41ba55ab Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Thu, 23 Jul 2020 15:41:31 +0200 Subject: [PATCH 02/28] fix: event.level fatal is not a crashed session (#492) --- .../main/java/io/sentry/core/SentryEvent.java | 5 +--- .../java/io/sentry/core/SentryClientTest.kt | 28 +++++++++++++------ .../java/io/sentry/core/SentryEventTest.kt | 22 +++++++-------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java b/sentry-core/src/main/java/io/sentry/core/SentryEvent.java index b4f028b29..6623856ce 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryEvent.java @@ -330,14 +330,11 @@ public void setDebugMeta(DebugMeta debugMeta) { } /** - * Returns true if Level is Fatal or any exception was unhandled by the user. + * Returns true if any exception was unhandled by the user. * * @return true if its crashed or false otherwise */ public boolean isCrashed() { - if (level == SentryLevel.FATAL) { - return true; - } if (exception != null) { for (SentryException e : exception.getValues()) { if (e.getMechanism() != null diff --git a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt index 560ed7e02..32ca1779d 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt @@ -17,6 +17,7 @@ import io.sentry.core.hints.Cached import io.sentry.core.hints.DiskFlushNotification import io.sentry.core.hints.SessionEndHint import io.sentry.core.hints.SessionUpdateHint +import io.sentry.core.protocol.Mechanism import io.sentry.core.protocol.Request import io.sentry.core.protocol.SdkVersion import io.sentry.core.protocol.SentryException @@ -465,11 +466,11 @@ class SentryClientTest { } @Test - fun `When event is Fatal or not handled, mark session as Crashed`() { + fun `When event is non handled, mark session as Crashed`() { val scope = Scope(fixture.sentryOptions) scope.startSession().current val event = SentryEvent().apply { - level = SentryLevel.FATAL + exceptions = createNonHandledException() } fixture.getSut().updateSessionData(event, null, scope) scope.withSession { @@ -478,7 +479,7 @@ class SentryClientTest { } @Test - fun `When event is non fatal, keep level as it is`() { + fun `When event is handled, keep level as it is`() { val scope = Scope(fixture.sentryOptions) val session = scope.startSession().current val level = session.status @@ -488,11 +489,11 @@ class SentryClientTest { } @Test - fun `When event is Fatal, increase errorCount`() { + fun `When event is non handled, increase errorCount`() { val scope = Scope(fixture.sentryOptions) scope.startSession().current val event = SentryEvent().apply { - level = SentryLevel.FATAL + exceptions = createNonHandledException() } fixture.getSut().updateSessionData(event, null, scope) scope.withSession { @@ -516,7 +517,7 @@ class SentryClientTest { } @Test - fun `When event is non fatal nor errored, do not increase errorsCount`() { + fun `When event is handled and not errored, do not increase errorsCount`() { val scope = Scope(fixture.sentryOptions) val session = scope.startSession().current val errorCount = session.errorCount() @@ -569,7 +570,7 @@ class SentryClientTest { val sut = fixture.getSut() val event = SentryEvent().apply { - level = SentryLevel.FATAL + exceptions = createNonHandledException() } val scope = Scope(fixture.sentryOptions) scope.startSession() @@ -586,7 +587,7 @@ class SentryClientTest { val sut = fixture.getSut() val event = SentryEvent().apply { - level = SentryLevel.FATAL + exceptions = createNonHandledException() } val scope = Scope(fixture.sentryOptions) scope.startSession() @@ -602,7 +603,7 @@ class SentryClientTest { val sut = fixture.getSut() val event = SentryEvent().apply { - level = SentryLevel.FATAL + exceptions = createNonHandledException() } val scope = Scope(fixture.sentryOptions) scope.startSession().current @@ -653,6 +654,15 @@ class SentryClientTest { override fun isConnected(): Boolean = false } + private fun createNonHandledException(): List { + val exception = SentryException().apply { + mechanism = Mechanism().apply { + isHandled = false + } + } + return listOf(exception) + } + internal class CustomCachedApplyScopeDataHint : Cached, ApplyScopeData internal class DiskFlushNotificationHint : DiskFlushNotification { diff --git a/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt index 229ce1878..2d8f6b66c 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt @@ -39,13 +39,6 @@ class SentryEventTest { assertEquals(expected, DateUtils.getTimestampIsoFormat(actual.timestamp)) } - @Test - fun `if level Fatal it should return isCrashed=true`() { - val event = SentryEvent() - event.level = SentryLevel.FATAL - assertTrue(event.isCrashed) - } - @Test fun `if mechanism is not handled, it should return isCrashed=true`() { val mechanism = Mechanism() @@ -58,11 +51,10 @@ class SentryEventTest { } @Test - fun `if mechanism is handled and level is not fatal, it should return isCrashed=false`() { + fun `if mechanism is handled, it should return isCrashed=false`() { val mechanism = Mechanism() mechanism.isHandled = true val event = SentryEvent() - event.level = SentryLevel.ERROR val factory = SentryExceptionFactory(mock()) val sentryExceptions = factory.getSentryExceptions(ExceptionMechanismException(mechanism, Throwable(), Thread())) event.exceptions = sentryExceptions @@ -70,14 +62,22 @@ class SentryEventTest { } @Test - fun `if mechanism nas not handled flag and level is not fatal, it should return isCrashed=false`() { + fun `if mechanism handled flag is null, it should return isCrashed=false`() { val mechanism = Mechanism() mechanism.isHandled = null val event = SentryEvent() - event.level = SentryLevel.ERROR val factory = SentryExceptionFactory(mock()) val sentryExceptions = factory.getSentryExceptions(ExceptionMechanismException(mechanism, Throwable(), Thread())) event.exceptions = sentryExceptions assertFalse(event.isCrashed) } + + @Test + fun `if mechanism is not set, it should return isCrashed=false`() { + val event = SentryEvent() + val factory = SentryExceptionFactory(mock()) + val sentryExceptions = factory.getSentryExceptions(RuntimeException(Throwable())) + event.exceptions = sentryExceptions + assertFalse(event.isCrashed) + } } From 50a2165b8aded423f3e5fd9616dc004e36b93486 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Fri, 24 Jul 2020 09:01:55 +0200 Subject: [PATCH 03/28] feat: drop store endpoint in favor of envelope (#490) --- .../java/io/sentry/core/SentryEnvelope.java | 12 ++ .../core/transport/AsyncConnection.java | 9 +- .../sentry/core/transport/HttpTransport.java | 59 ++------ .../io/sentry/core/transport/ITransport.java | 3 - .../sentry/core/transport/NoOpTransport.java | 6 - .../core/transport/StdoutTransport.java | 14 +- .../core/transport/TransportResult.java | 7 +- .../core/transport/AsyncConnectionTest.kt | 18 ++- .../core/transport/HttpTransportTest.kt | 131 +++--------------- .../core/transport/StdoutTransportTest.kt | 12 +- 10 files changed, 67 insertions(+), 204 deletions(-) diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java b/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java index 006c83a56..54ceb3a3b 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java @@ -64,4 +64,16 @@ public SentryEnvelope( return new SentryEnvelope( null, sdkVersion, SentryEnvelopeItem.fromSession(serializer, session)); } + + public static @NotNull SentryEnvelope fromEvent( + final @NotNull ISerializer serializer, + final @NotNull SentryEvent event, + final @Nullable SdkVersion sdkVersion) + throws IOException { + Objects.requireNonNull(serializer, "Serializer is required."); + Objects.requireNonNull(event, "Event is required."); + + return new SentryEnvelope( + event.getEventId(), sdkVersion, SentryEnvelopeItem.fromEvent(serializer, event)); + } } diff --git a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java b/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java index 678b3ddd5..a351597d8 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java @@ -244,7 +244,7 @@ private final class EventSender implements Runnable { private final SentryEvent event; private final Object hint; private final IEventCache eventCache; - private final TransportResult failedResult = TransportResult.error(-1); + private final TransportResult failedResult = TransportResult.error(); EventSender( final @NotNull SentryEvent event, @@ -288,7 +288,10 @@ public void run() { if (transportGate.isConnected()) { try { - result = transport.send(event); + result = + transport.send( + SentryEnvelope.fromEvent( + options.getSerializer(), event, options.getSdkVersion())); if (result.isSuccess()) { eventCache.discard(event); } else { @@ -325,7 +328,7 @@ private final class SessionSender implements Runnable { private final @NotNull SentryEnvelope envelope; private final @Nullable Object hint; private final @NotNull IEnvelopeCache sessionCache; - private final TransportResult failedResult = TransportResult.error(-1); + private final TransportResult failedResult = TransportResult.error(); SessionSender( final @NotNull SentryEnvelope envelope, diff --git a/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java b/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java index bf5f835db..bc0c257f8 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java @@ -9,7 +9,6 @@ import io.sentry.core.ILogger; import io.sentry.core.ISerializer; import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEvent; import io.sentry.core.SentryOptions; import io.sentry.core.util.Objects; import io.sentry.core.util.StringUtils; @@ -76,7 +75,6 @@ public String getCategory() { private final int connectionTimeout; private final int readTimeout; private final boolean bypassSecurity; - private final @NotNull URL storeUrl; private final @NotNull URL envelopeUrl; private final @NotNull SentryOptions options; @@ -139,42 +137,15 @@ public HttpTransport( try { final URI uri = sentryUrl.toURI(); - storeUrl = uri.resolve(uri.getPath() + "/store/").toURL(); envelopeUrl = uri.resolve(uri.getPath() + "/envelope/").toURL(); } catch (URISyntaxException | MalformedURLException e) { throw new IllegalArgumentException("Failed to compose the Sentry's server URL.", e); } } - // giving up on testing this method is probably the simplest way of having the rest of the class - // testable... - protected @NotNull HttpURLConnection open(final @Nullable Proxy proxy) throws IOException { - return open(storeUrl, proxy); - } - - protected @NotNull HttpURLConnection open(final @NotNull URL url, final @Nullable Proxy proxy) - throws IOException { - return (HttpURLConnection) (proxy == null ? url.openConnection() : url.openConnection(proxy)); - } - - @Override - public @NotNull TransportResult send(final @NotNull SentryEvent event) throws IOException { - final HttpURLConnection connection = createConnection(false); - TransportResult result; - - try (final OutputStream outputStream = connection.getOutputStream(); - final GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - final Writer writer = new BufferedWriter(new OutputStreamWriter(gzip, UTF_8))) { - - serializer.serialize(event, writer); - } catch (IOException e) { - logger.log( - ERROR, e, "An exception occurred while submitting the event to the Sentry server."); - } finally { - result = - readAndLog(connection, String.format("Event sent %s successfully.", event.getEventId())); - } - return result; + protected @NotNull HttpURLConnection open() throws IOException { + return (HttpURLConnection) + (proxy == null ? envelopeUrl.openConnection() : envelopeUrl.openConnection(proxy)); } /** @@ -235,19 +206,11 @@ public boolean isRetryAfter(final @NotNull String itemType) { /** * Create a HttpURLConnection connection Sets specific content-type if its an envelope or not * - * @param asEnvelope if its an envelope or not * @return the HttpURLConnection * @throws IOException if connection has a problem */ - private @NotNull HttpURLConnection createConnection(boolean asEnvelope) throws IOException { - String contentType = "application/json"; - HttpURLConnection connection; - if (asEnvelope) { - connection = open(envelopeUrl, proxy); - contentType = "application/x-sentry-envelope"; - } else { - connection = open(proxy); - } + private @NotNull HttpURLConnection createConnection() throws IOException { + HttpURLConnection connection = open(); connectionConfigurator.configure(connection); connection.setRequestMethod("POST"); @@ -255,7 +218,7 @@ public boolean isRetryAfter(final @NotNull String itemType) { connection.setChunkedStreamingMode(0); connection.setRequestProperty("Content-Encoding", "gzip"); - connection.setRequestProperty("Content-Type", contentType); + connection.setRequestProperty("Content-Type", "application/x-sentry-envelope"); connection.setRequestProperty("Accept", "application/json"); // https://stackoverflow.com/questions/52726909/java-io-ioexception-unexpected-end-of-stream-on-connection/53089882 @@ -274,7 +237,7 @@ public boolean isRetryAfter(final @NotNull String itemType) { @Override public @NotNull TransportResult send(final @NotNull SentryEnvelope envelope) throws IOException { - final HttpURLConnection connection = createConnection(true); + final HttpURLConnection connection = createConnection(); TransportResult result; try (final OutputStream outputStream = connection.getOutputStream(); @@ -286,7 +249,7 @@ public boolean isRetryAfter(final @NotNull String itemType) { logger.log( ERROR, e, "An exception occurred while submitting the envelope to the Sentry server."); } finally { - result = readAndLog(connection, "Envelope sent successfully."); + result = readAndLog(connection); } return result; } @@ -295,11 +258,9 @@ public boolean isRetryAfter(final @NotNull String itemType) { * Read responde code, retry after header and its error stream if there are errors and log it * * @param connection the HttpURLConnection - * @param message the message, if custom message if its an event or envelope * @return TransportResult.success if responseCode is 200 or TransportResult.error otherwise */ - private @NotNull TransportResult readAndLog( - final @NotNull HttpURLConnection connection, final @NotNull String message) { + private @NotNull TransportResult readAndLog(final @NotNull HttpURLConnection connection) { try { final int responseCode = connection.getResponseCode(); @@ -316,7 +277,7 @@ public boolean isRetryAfter(final @NotNull String itemType) { return TransportResult.error(responseCode); } - logger.log(DEBUG, message); + logger.log(DEBUG, "Envelope sent successfully."); return TransportResult.success(); } catch (IOException e) { diff --git a/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java b/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java index a2c424521..c0b165285 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java @@ -1,14 +1,11 @@ package io.sentry.core.transport; import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEvent; import java.io.Closeable; import java.io.IOException; /** A transport is in charge of sending the event to the Sentry server. */ public interface ITransport extends Closeable { - TransportResult send(SentryEvent event) throws IOException; - boolean isRetryAfter(String type); TransportResult send(SentryEnvelope envelope) throws IOException; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java b/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java index c0de83a03..f3e856c6c 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java @@ -1,7 +1,6 @@ package io.sentry.core.transport; import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEvent; import java.io.IOException; import org.jetbrains.annotations.ApiStatus; @@ -16,11 +15,6 @@ public static NoOpTransport getInstance() { private NoOpTransport() {} - @Override - public TransportResult send(SentryEvent event) throws IOException { - return TransportResult.success(); - } - @Override public boolean isRetryAfter(String type) { return false; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java b/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java index f82f4e079..f5b9c1929 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java @@ -2,7 +2,6 @@ import io.sentry.core.ISerializer; import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEvent; import io.sentry.core.util.Objects; import java.io.BufferedWriter; import java.io.IOException; @@ -22,17 +21,6 @@ public StdoutTransport(final @NotNull ISerializer serializer) { this.serializer = Objects.requireNonNull(serializer, "Serializer is required"); } - @Override - public TransportResult send(final @NotNull SentryEvent event) throws IOException { - Objects.requireNonNull(event, "SentryEvent is required"); - - try (final Writer writer = new BufferedWriter(new OutputStreamWriter(System.out, UTF_8)); - final Writer printWriter = new PrintWriter(writer)) { - serializer.serialize(event, printWriter); - return TransportResult.success(); - } - } - @Override public boolean isRetryAfter(String type) { return false; @@ -47,7 +35,7 @@ public TransportResult send(final @NotNull SentryEnvelope envelope) throws IOExc serializer.serialize(envelope, printWriter); return TransportResult.success(); } catch (Exception e) { - return TransportResult.error(-1); + return TransportResult.error(); } } diff --git a/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java b/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java index 3ed1cf48e..845eb38b4 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java @@ -1,12 +1,11 @@ package io.sentry.core.transport; -import io.sentry.core.SentryEvent; import org.jetbrains.annotations.NotNull; /** - * A result of {@link ITransport#send(SentryEvent)}. Note that this class is intentionally not - * subclassable and has only two factory methods to capture the 2 possible states - success or - * error. + * A result of {@link ITransport#send(io.sentry.core.SentryEnvelope)}. Note that this class is + * intentionally not subclassable and has only two factory methods to capture the 2 possible states + * - success or error. */ public abstract class TransportResult { diff --git a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt b/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt index ae96c3cec..2b7b8dc05 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt @@ -57,7 +57,7 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.success()) + whenever(fixture.transport.send(any())).thenReturn(TransportResult.success()) // when fixture.getSUT().send(ev) @@ -68,7 +68,9 @@ class AsyncConnectionTest { // because storeBeforeSend is enabled by default order.verify(fixture.eventCache).store(eq(ev)) - order.verify(fixture.transport).send(eq(ev)) + order.verify(fixture.transport).send(check { + assertEquals(ev.eventId, it.header.eventId) + }) order.verify(fixture.eventCache).discard(eq(ev)) } @@ -125,7 +127,7 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.error(500)) + whenever(fixture.transport.send(any())).thenReturn(TransportResult.error(500)) // when try { @@ -140,7 +142,9 @@ class AsyncConnectionTest { // because storeBeforeSend is enabled by default order.verify(fixture.eventCache).store(eq(ev)) - order.verify(fixture.transport).send(eq(ev)) + order.verify(fixture.transport).send(check { + assertEquals(ev.eventId, it.header.eventId) + }) verify(fixture.eventCache, never()).discard(any()) } @@ -173,7 +177,7 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenThrow(IOException()) + whenever(fixture.transport.send(any())).thenThrow(IOException()) // when try { @@ -184,7 +188,9 @@ class AsyncConnectionTest { // then val order = inOrder(fixture.transport, fixture.eventCache) - order.verify(fixture.transport).send(eq(ev)) + order.verify(fixture.transport).send(check { + assertEquals(ev.eventId, it.header.eventId) + }) verify(fixture.eventCache, never()).discard(any()) } diff --git a/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt b/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt index 50f678753..2235747db 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt @@ -45,11 +45,7 @@ class HttpTransportTest { options.proxy = proxy return object : HttpTransport(options, requestUpdater, connectionTimeout, readTimeout, bypassSecurity, dsn, currentDateProvider) { - override fun open(proxy: Proxy?): HttpURLConnection { - return connection - } - - override fun open(url: URL, proxy: Proxy?): HttpURLConnection { + override fun open(): HttpURLConnection { return connection } } @@ -58,19 +54,6 @@ class HttpTransportTest { private val fixture = Fixture() - @Test - fun `test serializes event`() { - val transport = fixture.getSUT() - whenever(fixture.connection.responseCode).thenReturn(200) - - val event = SentryEvent() - - val result = transport.send(event) - - verify(fixture.serializer).serialize(eq(event), any()) - assertTrue(result.isSuccess) - } - @Test fun `test serializes envelope`() { val transport = fixture.getSUT() @@ -84,24 +67,6 @@ class HttpTransportTest { assertTrue(result.isSuccess) } - @Test - fun `uses Retry-After header if X-Sentry-Rate-Limit is not set when sending an event`() { - val transport = fixture.getSUT() - - throwOnEventSerialize() - whenever(fixture.connection.getHeaderField(eq("Retry-After"))).thenReturn("30") - whenever(fixture.connection.responseCode).thenReturn(429) - whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - - val event = SentryEvent() - - val result = transport.send(event) - - verify(fixture.serializer).serialize(eq(event), any()) - assertFalse(result.isSuccess) - assertTrue(transport.isRetryAfter("event")) - } - @Test fun `uses Retry-After header if X-Sentry-Rate-Limit is not set when sending an envelope`() { val transport = fixture.getSUT() @@ -120,22 +85,6 @@ class HttpTransportTest { assertTrue(transport.isRetryAfter("session")) } - @Test - fun `passes on the response code on error when sending an event`() { - val transport = fixture.getSUT() - - throwOnEventSerialize() - whenever(fixture.connection.responseCode).thenReturn(1234) - - val event = SentryEvent() - - val result = transport.send(event) - - verify(fixture.serializer).serialize(eq(event), any()) - assertFalse(result.isSuccess) - assertEquals(1234, result.responseCode) - } - @Test fun `passes on the response code on error when sending an envelope`() { val transport = fixture.getSUT() @@ -152,23 +101,6 @@ class HttpTransportTest { assertEquals(1234, result.responseCode) } - @Test - fun `uses the default retry interval if there is no Retry-After header when sending an event`() { - val transport = fixture.getSUT() - - throwOnEventSerialize() - whenever(fixture.connection.responseCode).thenReturn(429) - whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - - val event = SentryEvent() - - val result = transport.send(event) - - verify(fixture.serializer).serialize(eq(event), any()) - assertFalse(result.isSuccess) - assertTrue(transport.isRetryAfter("event")) - } - @Test fun `uses the default retry interval if there is no Retry-After header when sending an envelope`() { val transport = fixture.getSUT() @@ -186,22 +118,6 @@ class HttpTransportTest { assertTrue(transport.isRetryAfter("session")) } - @Test - fun `failure to get response code doesn't break sending an event`() { - val transport = fixture.getSUT() - - throwOnEventSerialize() - whenever(fixture.connection.responseCode).thenThrow(IOException()) - - val event = SentryEvent() - - val result = transport.send(event) - - verify(fixture.serializer).serialize(eq(event), any()) - assertFalse(result.isSuccess) - assertEquals(-1, result.responseCode) - } - @Test fun `failure to get response code doesn't break sending an envelope`() { val transport = fixture.getSUT() @@ -228,11 +144,10 @@ class HttpTransportTest { .thenReturn("50:transaction:key, 2700:default;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - val event = SentryEvent() - - val result = transport.send(event) + val envelope = createEnvelope() + val result = transport.send(envelope) - verify(fixture.serializer).serialize(eq(event), any()) + verify(fixture.serializer).serialize(eq(envelope), any()) assertFalse(result.isSuccess) assertTrue(transport.isRetryAfter("event")) } @@ -246,11 +161,10 @@ class HttpTransportTest { .thenReturn("50:transaction:key, 1:default;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) - val event = SentryEvent() - - val result = transport.send(event) + val envelope = createEnvelope() + val result = transport.send(envelope) - verify(fixture.serializer).serialize(eq(event), any()) + verify(fixture.serializer).serialize(eq(envelope), any()) assertFalse(result.isSuccess) assertFalse(transport.isRetryAfter("event")) } @@ -264,9 +178,7 @@ class HttpTransportTest { .thenReturn("50:transaction:key, 2700:default;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertTrue(transport.isRetryAfter("transaction")) assertTrue(transport.isRetryAfter("event")) @@ -281,9 +193,8 @@ class HttpTransportTest { .thenReturn("1:transaction:key, 1:default;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) - val event = SentryEvent() + transport.send(createEnvelope()) - transport.send(event) assertFalse(transport.isRetryAfter("transaction")) assertFalse(transport.isRetryAfter("event")) } @@ -297,9 +208,7 @@ class HttpTransportTest { .thenReturn("50::key") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertTrue(transport.isRetryAfter("event")) } @@ -313,9 +222,7 @@ class HttpTransportTest { .thenReturn("60:default;foobar;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertFalse(transport.isRetryAfter("foobar")) } @@ -328,9 +235,7 @@ class HttpTransportTest { .thenReturn("1::key, 60:default;error;security:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertTrue(transport.isRetryAfter("event")) } @@ -343,9 +248,7 @@ class HttpTransportTest { .thenReturn("60:error:key, 1:error:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertTrue(transport.isRetryAfter("event")) } @@ -358,9 +261,7 @@ class HttpTransportTest { .thenReturn("1:error:key, 5:error:organization") whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) - val event = SentryEvent() - - transport.send(event) + transport.send(createEnvelope()) assertTrue(transport.isRetryAfter("event")) } @@ -376,4 +277,8 @@ class HttpTransportTest { private fun throwOnEnvelopeSerialize() { whenever(fixture.serializer.serialize(any(), any())).thenThrow(IOException()) } + + private fun createEnvelope(event: SentryEvent = SentryEvent()): SentryEnvelope { + return SentryEnvelope.fromEvent(fixture.serializer, event, null) + } } diff --git a/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt b/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt index fc2fe1f1d..5b742a14b 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt @@ -5,8 +5,8 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import io.sentry.core.ISerializer +import io.sentry.core.SentryEnvelope import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions import kotlin.test.Test import kotlin.test.assertTrue @@ -15,9 +15,6 @@ class StdoutTransportTest { val serializer = mock() fun getSUT(): ITransport { - val options = SentryOptions() - options.setSerializer(serializer) - return StdoutTransport(serializer) } } @@ -25,13 +22,14 @@ class StdoutTransportTest { private val fixture = Fixture() @Test - fun `test serializes event`() { + fun `test serializes envelope`() { val transport = fixture.getSUT() val event = SentryEvent() + val envelope = SentryEnvelope.fromEvent(fixture.serializer, event, null) - val result = transport.send(event) + val result = transport.send(envelope) - verify(fixture.serializer).serialize(eq(event), any()) + verify(fixture.serializer).serialize(eq(envelope), any()) assertTrue(result.isSuccess) } } From 2f3b563ac888354e12173771b5c89c54fb88aeb0 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Fri, 24 Jul 2020 14:23:39 +0200 Subject: [PATCH 04/28] fix: ktlint for kts files (#493) --- build.gradle.kts | 3 ++- sentry-android-core/build.gradle.kts | 4 ++-- sentry-android-ndk/build.gradle.kts | 4 ++-- sentry-android-timber/build.gradle.kts | 6 +++--- sentry-android/build.gradle.kts | 4 ++-- sentry-core/build.gradle.kts | 5 ++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 42d9b10d6..b6d2b931d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -65,10 +65,11 @@ spotless { } kotlin { - ktlint() target("**/*.kt") + ktlint() } kotlinGradle { + target("**/*.kts") ktlint() } } diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index b64b41cd9..ae4196bfd 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -90,7 +90,7 @@ dependencies { testImplementation(Config.TestLibs.awaitility) } -//TODO: move thse blocks to parent gradle file, DRY +// TODO: move thse blocks to parent gradle file, DRY configure { userOrg = Config.Sentry.userOrg groupId = project.group.toString() @@ -110,5 +110,5 @@ configure { devEmail = Config.Sentry.devEmail scmConnection = Config.Sentry.scmConnection scmDevConnection = Config.Sentry.scmDevConnection - scmUrl = Config.Sentry.scmUrl + scmUrl = Config.Sentry.scmUrl } diff --git a/sentry-android-ndk/build.gradle.kts b/sentry-android-ndk/build.gradle.kts index dee6a9235..a98840944 100644 --- a/sentry-android-ndk/build.gradle.kts +++ b/sentry-android-ndk/build.gradle.kts @@ -114,7 +114,7 @@ tasks.named("preBuild") { dependsOn(initNative) } -//TODO: move thse blocks to parent gradle file, DRY +// TODO: move thse blocks to parent gradle file, DRY configure { userOrg = Config.Sentry.userOrg groupId = project.group.toString() @@ -134,5 +134,5 @@ configure { devEmail = Config.Sentry.devEmail scmConnection = Config.Sentry.scmConnection scmDevConnection = Config.Sentry.scmDevConnection - scmUrl = Config.Sentry.scmUrl + scmUrl = Config.Sentry.scmUrl } diff --git a/sentry-android-timber/build.gradle.kts b/sentry-android-timber/build.gradle.kts index 75a857800..c788ca78c 100644 --- a/sentry-android-timber/build.gradle.kts +++ b/sentry-android-timber/build.gradle.kts @@ -1,7 +1,7 @@ import com.novoda.gradle.release.PublishExtension -import org.jetbrains.kotlin.config.KotlinCompilerVersion import io.gitlab.arturbosch.detekt.Detekt import io.gitlab.arturbosch.detekt.extensions.DetektExtension +import org.jetbrains.kotlin.config.KotlinCompilerVersion plugins { id("com.android.library") @@ -79,7 +79,7 @@ dependencies { testImplementation(Config.TestLibs.mockitoKotlin) } -//TODO: move thse blocks to parent gradle file, DRY +// TODO: move thse blocks to parent gradle file, DRY configure { userOrg = Config.Sentry.userOrg groupId = project.group.toString() @@ -99,7 +99,7 @@ configure { devEmail = Config.Sentry.devEmail scmConnection = Config.Sentry.scmConnection scmDevConnection = Config.Sentry.scmDevConnection - scmUrl = Config.Sentry.scmUrl + scmUrl = Config.Sentry.scmUrl } tasks.withType { diff --git a/sentry-android/build.gradle.kts b/sentry-android/build.gradle.kts index b67f905ba..6e48eb1cc 100644 --- a/sentry-android/build.gradle.kts +++ b/sentry-android/build.gradle.kts @@ -35,7 +35,7 @@ dependencies { api(project(":sentry-android-ndk")) } -//TODO: move these blocks to parent gradle file, DRY +// TODO: move these blocks to parent gradle file, DRY configure { userOrg = Config.Sentry.userOrg groupId = project.group.toString() @@ -55,5 +55,5 @@ configure { devEmail = Config.Sentry.devEmail scmConnection = Config.Sentry.scmConnection scmDevConnection = Config.Sentry.scmDevConnection - scmUrl = Config.Sentry.scmUrl + scmUrl = Config.Sentry.scmUrl } diff --git a/sentry-core/build.gradle.kts b/sentry-core/build.gradle.kts index f86852745..302682dc2 100644 --- a/sentry-core/build.gradle.kts +++ b/sentry-core/build.gradle.kts @@ -65,7 +65,7 @@ tasks { } } -//TODO: move thse blocks to parent gradle file, DRY +// TODO: move thse blocks to parent gradle file, DRY configure { userOrg = Config.Sentry.userOrg groupId = project.group.toString() @@ -85,6 +85,5 @@ configure { devEmail = Config.Sentry.devEmail scmConnection = Config.Sentry.scmConnection scmDevConnection = Config.Sentry.scmDevConnection - scmUrl = Config.Sentry.scmUrl + scmUrl = Config.Sentry.scmUrl } - From 29fbcc7def0a821e0fcd9da251a5922ffe4c55b1 Mon Sep 17 00:00:00 2001 From: Bruno Garcia Date: Mon, 27 Jul 2020 13:43:43 -0400 Subject: [PATCH 05/28] sentry-java readme --- README.md | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cabda930e..85c574e09 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@

-Android SDK for Sentry +Java and Android SDK for Sentry =========== -[![Travis](https://img.shields.io/travis/getsentry/sentry-android?label=Travis)](https://travis-ci.com/getsentry/sentry-android) -[![AppVeyor](https://img.shields.io/appveyor/build/sentry/sentry-android?label=AppVeyor)](https://ci.appveyor.com/project/sentry/sentry-android/branch/master) -[![GH Workflow](https://img.shields.io/github/workflow/status/getsentry/sentry-android/Workflow%20Ubuntu%20macOS?label=GH%20Workflow)](https://github.com/getsentry/sentry-android/actions) -[![Tests](https://img.shields.io/appveyor/tests/sentry/sentry-android/master?compact_message)](https://ci.appveyor.com/project/sentry/sentry-android/branch/master/tests) -[![codecov](https://codecov.io/gh/getsentry/sentry-android/branch/master/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-android) -[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/getsentry/sentry-android.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/getsentry/sentry-android/context:java) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/getsentry/sentry-android.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/getsentry/sentry-android/alerts/) +[![Travis](https://img.shields.io/travis/getsentry/sentry-java/ref/sentry-java-2?label=Travis)](https://travis-ci.com/getsentry/sentry-java) +[![AppVeyor](https://img.shields.io/appveyor/build/sentry/sentry-java?label=AppVeyor)](https://ci.appveyor.com/project/sentry/sentry-java) +[![GH Workflow](https://img.shields.io/github/workflow/status/getsentry/sentry-java/Workflow%20Ubuntu%20macOS?label=GH%20Workflow)](https://github.com/getsentry/sentry-java/actions) +[![Tests](https://img.shields.io/appveyor/tests/sentry/sentry-java/ref/sentry-java-2?compact_message)](https://ci.appveyor.com/project/sentry/sentry-java/branch/ref/sentry-java-2/tests) +[![codecov](https://codecov.io/gh/getsentry/sentry-java/branch/ref/sentry-java-2/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-java) +[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/getsentry/sentry-java.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/getsentry/sentry-java/context:java) +[![Total alerts](https://img.shields.io/lgtm/alerts/g/getsentry/sentry-java/ref/sentry-java-2.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/getsentry/sentry-java/alerts/) | Packages | bintray | API | | ---------------------- | ------- | ------- | @@ -22,8 +22,22 @@ Android SDK for Sentry | sentry-android-ndk | [![sentry-android-ndk](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-android-ndk)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-android-ndk?tab=overview) | 16 | | sentry-android-timber | [![sentry-android-timber](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-android-timber)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-android-timber?tab=overview) | 14 | | sentry-core | [![sentry-core](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-core)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-core?tab=overview) | 14 | +| sentry | [![sentry](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry?tab=overview) | | +| sentry-spring-boot-starter | [![sentry-spring-boot-starter](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter?tab=overview) | | +| sentry-spring | [![sentry-spring](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring?tab=overview) | | +| sentry-spring-boot-starter | [![sentry-spring-boot-starter](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter?tab=overview) | | +| sentry-appengine | [![sentry-appengine](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-appengine)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-appengine?tab=overview) | | +| sentry-log4j | [![sentry-log4j](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-log4j)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-log4j?tab=overview) | | +| sentry-logback | [![sentry-logback](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-logback)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-logback?tab=overview) | | -# Docs + +# Java SDK 2.0 Docs + +The Java SDK documentation [can be found on docs.sentry.io](https://docs.sentry.io/platforms/java/). + +Java SDK version 1.x [can still be found here](https://docs.sentry.io/clients/java/). + +# Android Docs That's the initial page of the release [2.x and its docs](https://docs.sentry.io/platforms/android). @@ -54,7 +68,8 @@ This directory is also included in `.gitignore` not to be shown as pending chang # Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/android/) +* [![Java Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/java/) +* [![Android Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/android/) * [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) * [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry) From 14a5e29d9977c404f9043c4fc65716a93879e19b Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Tue, 28 Jul 2020 14:12:26 +0200 Subject: [PATCH 06/28] feat: rotate cache folder (#494) --- .../io/sentry/core/cache/CacheStrategy.java | 94 +++++++++++++++++++ .../java/io/sentry/core/cache/DiskCache.java | 73 ++++---------- .../io/sentry/core/cache/SessionCache.java | 53 ++--------- .../io/sentry/core/cache/CacheStrategyTest.kt | 89 ++++++++++++++++++ 4 files changed, 209 insertions(+), 100 deletions(-) create mode 100644 sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java create mode 100644 sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt diff --git a/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java b/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java new file mode 100644 index 000000000..e175d7712 --- /dev/null +++ b/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java @@ -0,0 +1,94 @@ +package io.sentry.core.cache; + +import static io.sentry.core.SentryLevel.ERROR; + +import io.sentry.core.ISerializer; +import io.sentry.core.SentryLevel; +import io.sentry.core.SentryOptions; +import io.sentry.core.util.Objects; +import java.io.File; +import java.nio.charset.Charset; +import java.util.Arrays; +import org.jetbrains.annotations.NotNull; + +abstract class CacheStrategy { + + @SuppressWarnings("CharsetObjectCanBeUsed") + protected static final Charset UTF_8 = Charset.forName("UTF-8"); + + protected final @NotNull SentryOptions options; + protected final @NotNull ISerializer serializer; + protected final @NotNull File directory; + private final int maxSize; + + CacheStrategy( + final @NotNull SentryOptions options, + final @NotNull String directoryPath, + final int maxSize) { + Objects.requireNonNull(directoryPath, "Directory is required."); + this.options = Objects.requireNonNull(options, "SentryOptions is required."); + + this.serializer = options.getSerializer(); + this.directory = new File(directoryPath); + + this.maxSize = maxSize; + } + + /** + * Check if a dir. is valid and have write and read permission + * + * @return true if valid and has permissions or false otherwise + */ + protected boolean isDirectoryValid() { + if (!directory.isDirectory() || !directory.canWrite() || !directory.canRead()) { + options + .getLogger() + .log( + ERROR, + "The directory for caching files is inaccessible.: %s", + directory.getAbsolutePath()); + return false; + } + return true; + } + + /** + * Sort files from oldest to the newest using the lastModified method + * + * @param files the Files + */ + private void sortFilesOldestToNewest(@NotNull File[] files) { + // just sort it if more than 1 file + if (files.length > 1) { + Arrays.sort(files, (f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified())); + } + } + + /** + * Rotates the caching folder if full, deleting the oldest files first + * + * @param files the Files + */ + protected void rotateCacheIfNeeded(final @NotNull File[] files) { + final int length = files.length; + if (length >= maxSize) { + options + .getLogger() + .log(SentryLevel.WARNING, "Cache folder if full (respecting maxSize). Rotating files"); + final int totalToBeDeleted = (length - maxSize) + 1; + + sortFilesOldestToNewest(files); + + // delete files from the top of the Array as its sorted by the oldest to the newest + for (int i = 0; i < totalToBeDeleted; i++) { + final File file = files[i]; + // sanity check if the file actually exists. + if (!file.delete()) { + options + .getLogger() + .log(SentryLevel.WARNING, "File can't be deleted: %s", file.getAbsolutePath()); + } + } + } + } +} diff --git a/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java b/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java index 2054c4f80..fd91f3085 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java +++ b/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java @@ -5,11 +5,8 @@ import static io.sentry.core.SentryLevel.WARNING; import static java.lang.String.format; -import io.sentry.core.ISerializer; import io.sentry.core.SentryEvent; -import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -22,7 +19,6 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -34,39 +30,19 @@ * configured directory. */ @ApiStatus.Internal -public final class DiskCache implements IEventCache { +public final class DiskCache extends CacheStrategy implements IEventCache { /** File suffix added to all serialized event files. */ public static final String FILE_SUFFIX = ".sentry-event"; - @SuppressWarnings("CharsetObjectCanBeUsed") - private static final Charset UTF_8 = Charset.forName("UTF-8"); - - private final File directory; - private final int maxSize; - private final ISerializer serializer; - private final SentryOptions options; - - public DiskCache(SentryOptions options) { - Objects.requireNonNull(options.getCacheDirPath(), "Cache dir. path is required."); - this.directory = new File(options.getCacheDirPath()); - this.maxSize = options.getCacheDirSize(); - this.serializer = options.getSerializer(); - this.options = options; + public DiskCache(final @NotNull SentryOptions options) { + super(options, options.getCacheDirPath(), options.getCacheDirSize()); } @Override - public void store(SentryEvent event) { - if (getNumberOfStoredEvents() >= maxSize) { - options - .getLogger() - .log( - SentryLevel.WARNING, - "Disk cache full (respecting maxSize). Not storing event {}", - event); - return; - } + public void store(final @NotNull SentryEvent event) { + rotateCacheIfNeeded(allEventFiles()); - File eventFile = getEventFile(event); + final File eventFile = getEventFile(event); if (eventFile.exists()) { options .getLogger() @@ -92,8 +68,8 @@ public void store(SentryEvent event) { } @Override - public void discard(SentryEvent event) { - File eventFile = getEventFile(event); + public void discard(final @NotNull SentryEvent event) { + final File eventFile = getEventFile(event); if (eventFile.exists()) { options .getLogger() @@ -107,34 +83,17 @@ public void discard(SentryEvent event) { } } - private int getNumberOfStoredEvents() { - return allEventFiles().length; - } - - private boolean isDirectoryValid() { - if (!directory.isDirectory() || !directory.canWrite() || !directory.canRead()) { - options - .getLogger() - .log( - ERROR, - "The directory for caching Sentry events is inaccessible.: %s", - directory.getAbsolutePath()); - return false; - } - return true; - } - - private File getEventFile(SentryEvent event) { + private @NotNull File getEventFile(final @NotNull SentryEvent event) { return new File(directory.getAbsolutePath(), event.getEventId().toString() + FILE_SUFFIX); } @Override public @NotNull Iterator iterator() { - File[] allCachedEvents = allEventFiles(); + final File[] allCachedEvents = allEventFiles(); - List ret = new ArrayList<>(allCachedEvents.length); + final List ret = new ArrayList<>(allCachedEvents.length); - for (File f : allCachedEvents) { + for (final File f : allCachedEvents) { try (final Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f), UTF_8))) { @@ -159,10 +118,12 @@ private File getEventFile(SentryEvent event) { return ret.iterator(); } - private File[] allEventFiles() { + private @NotNull File[] allEventFiles() { if (isDirectoryValid()) { - // TODO: we need to order by oldest to the newest here - return directory.listFiles((__, fileName) -> fileName.endsWith(FILE_SUFFIX)); + final File[] files = directory.listFiles((__, fileName) -> fileName.endsWith(FILE_SUFFIX)); + if (files != null) { + return files; + } } return new File[] {}; } diff --git a/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java b/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java index ce45f601e..1318a10e2 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java +++ b/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java @@ -7,7 +7,6 @@ import static java.lang.String.format; import io.sentry.core.DateUtils; -import io.sentry.core.ISerializer; import io.sentry.core.SentryEnvelope; import io.sentry.core.SentryEnvelopeItem; import io.sentry.core.SentryItemType; @@ -33,7 +32,6 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -46,7 +44,7 @@ import org.jetbrains.annotations.Nullable; @ApiStatus.Internal -public final class SessionCache implements IEnvelopeCache { +public final class SessionCache extends CacheStrategy implements IEnvelopeCache { /** File suffix added to all serialized envelopes files. */ static final String SUFFIX_ENVELOPE_FILE = ".envelope"; @@ -55,37 +53,17 @@ public final class SessionCache implements IEnvelopeCache { static final String SUFFIX_CURRENT_SESSION_FILE = ".json"; static final String CRASH_MARKER_FILE = ".sentry-native/last_crash"; - @SuppressWarnings("CharsetObjectCanBeUsed") - private static final Charset UTF_8 = Charset.forName("UTF-8"); - - private final @NotNull File directory; - private final int maxSize; - private final @NotNull ISerializer serializer; - private final @NotNull SentryOptions options; - private final @NotNull Map fileNameMap = new WeakHashMap<>(); public SessionCache(final @NotNull SentryOptions options) { - Objects.requireNonNull(options.getSessionsPath(), "sessions dir. path is required."); - this.directory = new File(options.getSessionsPath()); - this.maxSize = options.getSessionsDirSize(); - this.serializer = options.getSerializer(); - this.options = options; + super(options, options.getSessionsPath(), options.getSessionsDirSize()); } @Override public void store(final @NotNull SentryEnvelope envelope, final @Nullable Object hint) { Objects.requireNonNull(envelope, "Envelope is required."); - if (getNumberOfStoredEnvelopes() >= maxSize) { - options - .getLogger() - .log( - SentryLevel.WARNING, - "Disk cache full (respecting maxSize). Not storing envelope {}", - envelope); - return; - } + rotateCacheIfNeeded(allEnvelopeFiles()); final File currentSessionFile = getCurrentSessionFile(); @@ -185,7 +163,7 @@ public void store(final @NotNull SentryEnvelope envelope, final @Nullable Object * @param markerFile the marker file * @return the timestamp as Date */ - private Date getTimestampFromCrashMarkerFile(final @NotNull File markerFile) { + private @Nullable Date getTimestampFromCrashMarkerFile(final @NotNull File markerFile) { try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(markerFile), UTF_8))) { final String timestamp = reader.readLine(); @@ -299,23 +277,6 @@ public void discard(final @NotNull SentryEnvelope envelope) { } } - private int getNumberOfStoredEnvelopes() { - return allEnvelopeFiles().length; - } - - private boolean isDirectoryValid() { - if (!directory.isDirectory() || !directory.canWrite() || !directory.canRead()) { - options - .getLogger() - .log( - ERROR, - "The directory for caching Sentry envelopes is inaccessible.: %s", - directory.getAbsolutePath()); - return false; - } - return true; - } - /** * Returns the envelope's file path. If the envelope has no eventId header, it generates a random * file name to it. @@ -378,7 +339,11 @@ private boolean isDirectoryValid() { private @NotNull File[] allEnvelopeFiles() { if (isDirectoryValid()) { // lets filter the session.json here - return directory.listFiles((__, fileName) -> fileName.endsWith(SUFFIX_ENVELOPE_FILE)); + final File[] files = + directory.listFiles((__, fileName) -> fileName.endsWith(SUFFIX_ENVELOPE_FILE)); + if (files != null) { + return files; + } } return new File[] {}; } diff --git a/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt b/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt new file mode 100644 index 000000000..4d7e7c109 --- /dev/null +++ b/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt @@ -0,0 +1,89 @@ +package io.sentry.core.cache + +import com.nhaarman.mockitokotlin2.mock +import io.sentry.core.DateUtils +import io.sentry.core.SentryOptions +import java.io.File +import java.nio.file.Files +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class CacheStrategyTest { + + private class Fixture { + val dir = Files.createTempDirectory("sentry-disk-cache-test").toAbsolutePath().toFile() + val options = SentryOptions().apply { + setSerializer(mock()) + } + + fun getSUT(maxSize: Int = 5): CacheStrategy { + return CustomCache(options, dir.absolutePath, maxSize) + } + } + + private val fixture = Fixture() + + @Test + fun `isDirectoryValid returns true if a valid directory`() { + val sut = fixture.getSUT() + + // sanity check + assertTrue(fixture.dir.isDirectory) + + // this test assumes that the dir. has write/read permission. + assertTrue(sut.isDirectoryValid) + } + + @Test + fun `Sort files from the oldest to the newest`() { + val sut = fixture.getSUT(3) + + val files = createTempFilesSortByOldestToNewest() + val reverseFiles = files.reversedArray() + + sut.rotateCacheIfNeeded(reverseFiles) + + assertEquals(files[0].absolutePath, reverseFiles[0].absolutePath) + assertEquals(files[1].absolutePath, reverseFiles[1].absolutePath) + assertEquals(files[2].absolutePath, reverseFiles[2].absolutePath) + } + + @Test + fun `Rotate cache folder to save new file`() { + val sut = fixture.getSUT(3) + + val files = createTempFilesSortByOldestToNewest() + val reverseFiles = files.reversedArray() + + sut.rotateCacheIfNeeded(reverseFiles) + + assertFalse(files[0].exists()) + assertTrue(files[1].exists()) + assertTrue(files[2].exists()) + } + + @AfterTest + fun shutdown() { + fixture.dir.listFiles()?.forEach { + it.deleteRecursively() + } + } + + private class CustomCache(options: SentryOptions, path: String, maxSize: Int) : CacheStrategy(options, path, maxSize) + + private fun createTempFilesSortByOldestToNewest(): Array { + val f1 = Files.createTempFile(fixture.dir.toPath(), "f1", ".json").toFile() + f1.setLastModified(DateUtils.getDateTime("2020-03-27T08:52:58.015Z").time) + + val f2 = Files.createTempFile(fixture.dir.toPath(), "f2", ".json").toFile() + f2.setLastModified(DateUtils.getDateTime("2020-03-27T08:52:59.015Z").time) + + val f3 = Files.createTempFile(fixture.dir.toPath(), "f3", ".json").toFile() + f3.setLastModified(DateUtils.getDateTime("2020-03-27T08:53:00.015Z").time) + + return arrayOf(f1, f2, f3) + } +} From ad2e0d8753105c996e41ebe840559c3524a86c0d Mon Sep 17 00:00:00 2001 From: David Thompson Date: Wed, 5 Aug 2020 11:02:11 -0400 Subject: [PATCH 07/28] make EventProcessor.process Nullable (#507) --- sentry-core/src/main/java/io/sentry/core/EventProcessor.java | 1 + .../src/main/java/io/sentry/core/MainEventProcessor.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sentry-core/src/main/java/io/sentry/core/EventProcessor.java b/sentry-core/src/main/java/io/sentry/core/EventProcessor.java index 6a809b29f..9e225ed63 100644 --- a/sentry-core/src/main/java/io/sentry/core/EventProcessor.java +++ b/sentry-core/src/main/java/io/sentry/core/EventProcessor.java @@ -3,5 +3,6 @@ import org.jetbrains.annotations.Nullable; public interface EventProcessor { + @Nullable SentryEvent process(SentryEvent event, @Nullable Object hint); } diff --git a/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java b/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java index 3bf038a3f..b3c28d508 100644 --- a/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java +++ b/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @ApiStatus.Internal @@ -38,7 +39,7 @@ public final class MainEventProcessor implements EventProcessor { } @Override - public SentryEvent process(SentryEvent event, @Nullable Object hint) { + public @NotNull SentryEvent process(SentryEvent event, @Nullable Object hint) { if (event.getPlatform() == null) { // this actually means JVM related. event.setPlatform("java"); From d18da368da91437e421b2aa715f5de32fa7721d9 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 20 Aug 2020 03:29:52 +0200 Subject: [PATCH 08/28] Add Logback integration. (#511) --- buildSrc/src/main/java/Config.kt | 4 + .../main/java/io/sentry/core/SentryEvent.java | 3 +- sentry-logback/build.gradle.kts | 102 +++++++++ .../io/sentry/logback/SentryAppender.java | 200 ++++++++++++++++ .../io/sentry/logback/SentryAppenderTest.kt | 213 ++++++++++++++++++ .../org.mockito.plugins.MockMaker | 1 + .../sentry-samples-logback/build.gradle.kts | 14 ++ .../java/io/sentry/samples/logback/Main.java | 26 +++ .../src/main/resources/logback.xml | 22 ++ settings.gradle.kts | 2 + 10 files changed, 586 insertions(+), 1 deletion(-) create mode 100644 sentry-logback/build.gradle.kts create mode 100644 sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java create mode 100644 sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt create mode 100644 sentry-logback/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker create mode 100644 sentry-samples/sentry-samples-logback/build.gradle.kts create mode 100644 sentry-samples/sentry-samples-logback/src/main/java/io/sentry/samples/logback/Main.java create mode 100644 sentry-samples/sentry-samples-logback/src/main/resources/logback.xml diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 8b2894c9c..992c82dcb 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -32,6 +32,9 @@ object Config { val lifecycleVersion = "2.2.0" val lifecycleProcess = "androidx.lifecycle:lifecycle-process:$lifecycleVersion" val lifecycleCommonJava8 = "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion" + + val logbackVersion = "1.2.3" + val logbackClassic = "ch.qos.logback:logback-classic:$logbackVersion" } object TestLibs { @@ -62,6 +65,7 @@ object Config { object Sentry { val SENTRY_JAVA_SDK_NAME = "sentry.java" val SENTRY_ANDROID_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.android" + val SENTRY_LOGBACK_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.logback" val group = "io.sentry" val description = "SDK for sentry.io" val website = "https://sentry.io" diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java b/sentry-core/src/main/java/io/sentry/core/SentryEvent.java index f6a1a8d41..20704edb9 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryEvent.java @@ -67,7 +67,8 @@ public Date getTimestamp() { } @Nullable - Throwable getThrowable() { + @ApiStatus.Internal + public Throwable getThrowable() { return throwable; } diff --git a/sentry-logback/build.gradle.kts b/sentry-logback/build.gradle.kts new file mode 100644 index 000000000..7b42bdd29 --- /dev/null +++ b/sentry-logback/build.gradle.kts @@ -0,0 +1,102 @@ +import com.novoda.gradle.release.PublishExtension + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.Deploy.novodaBintray) + id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + api(project(":sentry-core")) + implementation(Config.Libs.logbackClassic) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + errorproneJavac(Config.CompileOnly.errorProneJavac8) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.jacocoVersion +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = BigDecimal.valueOf(0.6) } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +buildConfig { + useJavaOutput() + packageName("io.sentry.logback") + buildConfigField("String", "SENTRY_LOGBACK_SDK_NAME", "\"${Config.Sentry.SENTRY_LOGBACK_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} + +val generateBuildConfig by tasks +tasks.withType().configureEach { + dependsOn(generateBuildConfig) +} + +//TODO: move these blocks to parent gradle file, DRY +configure { + userOrg = Config.Sentry.userOrg + groupId = project.group.toString() + publishVersion = project.version.toString() + desc = Config.Sentry.description + website = Config.Sentry.website + repoName = Config.Sentry.repoName + setLicences(Config.Sentry.licence) + setLicenceUrls(Config.Sentry.licenceUrl) + issueTracker = Config.Sentry.issueTracker + repository = Config.Sentry.repository + sign = Config.Deploy.sign + artifactId = project.name + uploadName = "${project.group}:${project.name}" + devId = Config.Sentry.userOrg + devName = Config.Sentry.devName + devEmail = Config.Sentry.devEmail + scmConnection = Config.Sentry.scmConnection + scmDevConnection = Config.Sentry.scmDevConnection + scmUrl = Config.Sentry.scmUrl +} + diff --git a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java new file mode 100644 index 000000000..46c532094 --- /dev/null +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -0,0 +1,200 @@ +package io.sentry.logback; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.ThrowableProxy; +import ch.qos.logback.core.UnsynchronizedAppenderBase; +import io.sentry.core.DateUtils; +import io.sentry.core.Sentry; +import io.sentry.core.SentryEvent; +import io.sentry.core.SentryLevel; +import io.sentry.core.SentryOptions; +import io.sentry.core.protocol.Message; +import io.sentry.core.protocol.SdkVersion; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import io.sentry.core.transport.ITransport; +import io.sentry.core.util.CollectionUtils; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Appender for logback in charge of sending the logged events to a Sentry server. */ +public final class SentryAppender extends UnsynchronizedAppenderBase { + private @Nullable String dsn; + private @Nullable String environment; + private @Nullable Integer maxBreadcrumbs; + private @Nullable Integer shutdownTimeoutMillis; + private @Nullable Integer flushTimeoutMillis; + private @Nullable Integer readTimeoutMillis; + private @Nullable Double sampleRate; + private @Nullable Boolean bypassSecurity; + private @Nullable Boolean debug; + private @Nullable Boolean attachThreads; + private @Nullable Boolean attachStacktrace; + private @Nullable ITransport transport; + + @Override + public void start() { + if (dsn != null) { + Sentry.init( + options -> { + options.setDsn(dsn); + Optional.ofNullable(maxBreadcrumbs).ifPresent(options::setMaxBreadcrumbs); + Optional.ofNullable(environment).ifPresent(options::setEnvironment); + Optional.ofNullable(shutdownTimeoutMillis).ifPresent(options::setShutdownTimeout); + Optional.ofNullable(flushTimeoutMillis).ifPresent(options::setFlushTimeoutMillis); + Optional.ofNullable(readTimeoutMillis).ifPresent(options::setReadTimeoutMillis); + Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); + Optional.ofNullable(bypassSecurity).ifPresent(options::setBypassSecurity); + Optional.ofNullable(debug).ifPresent(options::setDebug); + Optional.ofNullable(attachThreads).ifPresent(options::setAttachThreads); + Optional.ofNullable(attachStacktrace).ifPresent(options::setAttachStacktrace); + options.setSentryClientName(BuildConfig.SENTRY_LOGBACK_SDK_NAME); + options.setSdkVersion(createSdkVersion(options)); + Optional.ofNullable(transport).ifPresent(options::setTransport); + }); + } + super.start(); + } + + @Override + protected void append(@NotNull ILoggingEvent eventObject) { + Sentry.captureEvent(createEvent(eventObject)); + } + + /** + * Creates {@link SentryEvent} from Logback's {@link ILoggingEvent}. + * + * @param loggingEvent the logback event + * @return the sentry event + */ + @SuppressWarnings("JdkObsolete") + final @NotNull SentryEvent createEvent(@NotNull ILoggingEvent loggingEvent) { + final SentryEvent event = new SentryEvent(DateUtils.getDateTime(new Date(loggingEvent.getTimeStamp()))); + final Message message = new Message(); + message.setMessage(loggingEvent.getMessage()); + message.setFormatted(loggingEvent.getFormattedMessage()); + message.setParams(toParams(loggingEvent.getArgumentArray())); + event.setMessage(message); + event.setLogger(loggingEvent.getLoggerName()); + event.setLevel(formatLevel(loggingEvent.getLevel())); + + final ThrowableProxy throwableInformation = (ThrowableProxy) loggingEvent.getThrowableProxy(); + if (throwableInformation != null) { + event.setThrowable(throwableInformation.getThrowable()); + } + + if (loggingEvent.getThreadName() != null) { + event.setExtra("thread_name", loggingEvent.getThreadName()); + } + + final Map mdcProperties = CollectionUtils.shallowCopy(loggingEvent.getMDCPropertyMap()); + if (!mdcProperties.isEmpty()) { + event.getContexts().put("MDC", mdcProperties); + } + + return event; + } + + private @NotNull List toParams(@Nullable Object[] arguments) { + if (arguments != null) { + return Arrays.stream(arguments) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + /** + * Transforms a {@link Level} into an {@link SentryLevel}. + * + * @param level original level as defined in log4j. + * @return log level used within sentry. + */ + private static @NotNull SentryLevel formatLevel(@NotNull Level level) { + if (level.isGreaterOrEqual(Level.ERROR)) { + return SentryLevel.ERROR; + } else if (level.isGreaterOrEqual(Level.WARN)) { + return SentryLevel.WARNING; + } else if (level.isGreaterOrEqual(Level.INFO)) { + return SentryLevel.INFO; + } else { + return SentryLevel.DEBUG; + } + } + + private @NotNull SdkVersion createSdkVersion(@NotNull SentryOptions sentryOptions) { + SdkVersion sdkVersion = sentryOptions.getSdkVersion(); + + if (sdkVersion == null) { + sdkVersion = new SdkVersion(); + } + + sdkVersion.setName(BuildConfig.SENTRY_LOGBACK_SDK_NAME); + final String version = BuildConfig.VERSION_NAME; + sdkVersion.setVersion(version); + sdkVersion.addPackage("maven:sentry-logback", version); + + return sdkVersion; + } + + public void setDsn(@Nullable String dsn) { + this.dsn = dsn; + } + + public void setEnvironment(@Nullable String environment) { + this.environment = environment; + } + + public void setMaxBreadcrumbs(@Nullable Integer maxBreadcrumbs) { + this.maxBreadcrumbs = maxBreadcrumbs; + } + + public void setShutdownTimeoutMillis(@Nullable Integer shutdownTimeoutMillis) { + this.shutdownTimeoutMillis = shutdownTimeoutMillis; + } + + public void setFlushTimeoutMillis(@Nullable Integer flushTimeoutMillis) { + this.flushTimeoutMillis = flushTimeoutMillis; + } + + public void setReadTimeoutMillis(@Nullable Integer readTimeoutMillis) { + this.readTimeoutMillis = readTimeoutMillis; + } + + public void setSampleRate(@Nullable Double sampleRate) { + this.sampleRate = sampleRate; + } + + public void setBypassSecurity(@Nullable Boolean bypassSecurity) { + this.bypassSecurity = bypassSecurity; + } + + public void setDebug(@Nullable Boolean debug) { + this.debug = debug; + } + + public void setAttachThreads(@Nullable Boolean attachThreads) { + this.attachThreads = attachThreads; + } + + public void setAttachStacktrace(@Nullable Boolean attachStacktrace) { + this.attachStacktrace = attachStacktrace; + } + + @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 new file mode 100644 index 000000000..d54c4472a --- /dev/null +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -0,0 +1,213 @@ +package io.sentry.logback + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.LoggerContext +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.core.SentryEvent +import io.sentry.core.SentryLevel +import io.sentry.core.transport.ITransport +import io.sentry.core.transport.TransportResult +import org.awaitility.kotlin.await +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.slf4j.MDC +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class SentryAppenderTest { + private class Fixture { + 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() + appender.setDsn("http://key@localhost/proj") + 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() + + @AfterTest + fun `stop logback`() { + fixture.loggerContext.stop() + } + + @BeforeTest + fun `clear MDC`() { + MDC.clear() + } + + @Test + fun `converts message`() { + fixture.logger.debug("testing message conversion {}, {}", 1, 2) + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals("testing message conversion 1, 2", it.message.formatted) + assertEquals("testing message conversion {}, {}", it.message.message) + assertEquals(listOf("1", "2"), it.message.params) + assertEquals("io.sentry.logback.SentryAppenderTest", it.logger) + }) + } + } + + @Test + fun `event date is in UTC`() { + val utcTime = LocalDateTime.now(ZoneId.of("UTC")) + + fixture.logger.debug("testing event date") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + val eventTime = Instant.ofEpochMilli(it.timestamp.time) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + + assertTrue { eventTime.plusSeconds(1).isAfter(utcTime) } + assertTrue { eventTime.minusSeconds(1).isBefore(utcTime) } + }) + } + } + + @Test + fun `converts trace log level to Sentry level`() { + fixture.logger.trace("testing trace level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.DEBUG, it.level) + }) + } + } + + @Test + fun `converts debug log level to Sentry level`() { + fixture.logger.debug("testing debug level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.DEBUG, it.level) + }) + } + } + + @Test + fun `converts info log level to Sentry level`() { + fixture.logger.info("testing info level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.INFO, it.level) + }) + } + } + + @Test + fun `converts warn log level to Sentry level`() { + fixture.logger.warn("testing warn level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.WARNING, it.level) + }) + } + } + + @Test + fun `converts error log level to Sentry level`() { + fixture.logger.error("testing error level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.ERROR, it.level) + }) + } + } + + @Test + fun `attaches thread information`() { + fixture.logger.warn("testing thread information") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertNotNull(it.getExtra("thread_name")) + }) + } + } + + @Test + fun `sets tags from MDC`() { + MDC.put("key", "value") + fixture.logger.warn("testing MDC tags") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(mapOf("key" to "value"), it.contexts["MDC"]) + }) + } + } + + @Test + fun `does not create MDC context when no MDC tags are set`() { + fixture.logger.warn("testing without MDC tags") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertFalse(it.contexts.containsKey("MDC")) + }) + } + } + + @Test + fun `attaches throwable`() { + val throwable = RuntimeException("something went wrong") + fixture.logger.warn("testing throwable", throwable) + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(throwable, it.throwable) + }) + } + } + + @Test + fun `sets SDK version`() { + fixture.logger.info("testing sdk version") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(BuildConfig.SENTRY_LOGBACK_SDK_NAME, it.sdk.name) + assertEquals(BuildConfig.VERSION_NAME, it.sdk.version) + assertNotNull(it.sdk.packages) + assertTrue(it.sdk.packages!!.any { pkg -> + "maven:sentry-logback" == pkg.name + && BuildConfig.VERSION_NAME == pkg.version + }) + }) + } + } +} diff --git a/sentry-logback/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sentry-logback/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..1f0955d45 --- /dev/null +++ b/sentry-logback/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline diff --git a/sentry-samples/sentry-samples-logback/build.gradle.kts b/sentry-samples/sentry-samples-logback/build.gradle.kts new file mode 100644 index 000000000..44841bc56 --- /dev/null +++ b/sentry-samples/sentry-samples-logback/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + java + id(Config.QualityPlugins.gradleVersions) +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + implementation(project(":sentry-logback")) + implementation(Config.Libs.logbackClassic) +} diff --git a/sentry-samples/sentry-samples-logback/src/main/java/io/sentry/samples/logback/Main.java b/sentry-samples/sentry-samples-logback/src/main/java/io/sentry/samples/logback/Main.java new file mode 100644 index 000000000..3de86d711 --- /dev/null +++ b/sentry-samples/sentry-samples-logback/src/main/java/io/sentry/samples/logback/Main.java @@ -0,0 +1,26 @@ +package io.sentry.samples.logback; + +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +public class Main { + private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) { + LOGGER.debug("Hello Sentry!"); + + // MDC parameters are converted to Sentry Event tags + MDC.put("userId", UUID.randomUUID().toString()); + + // logging arguments are converted to Sentry Event parameters + LOGGER.info("User has made a purchase of product: {}", 445); + + try { + throw new RuntimeException("Invalid productId=445"); + } catch (Exception e) { + LOGGER.error("Something went wrong", e); + } + } +} diff --git a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml new file mode 100644 index 000000000..2d10daa78 --- /dev/null +++ b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml @@ -0,0 +1,22 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 + + + + + + + + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index 2cbd97ad2..e377bc76d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,8 @@ include("sentry-android", "sentry-android-ndk", "sentry-android-core", "sentry-core", + "sentry-logback", "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", + "sentry-samples:sentry-samples-logback", "sentry-android-timber") From 68c7ceb3f1446c3fb608182dd7bded36f15edefd Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 27 Aug 2020 16:22:28 +0200 Subject: [PATCH 09/28] Sentry Spring Boot Starter. (#517) --- build.gradle.kts | 2 +- buildSrc/src/main/java/Config.kt | 19 ++ .../src/main/java/io/sentry/core/Sentry.java | 11 + .../java/io/sentry/core/SentryClient.java | 60 ++-- .../java/io/sentry/core/SentryClientTest.kt | 8 + .../build.gradle.kts | 40 +++ .../java/io/sentry/samples/spring/Person.java | 24 ++ .../samples/spring/PersonController.java | 27 ++ .../samples/spring/SecurityConfiguration.java | 55 +++ .../samples/spring/SentryDemoApplication.java | 12 + .../src/main/resources/application.properties | 2 + .../src/main/resources/logback.xml | 16 + sentry-spring-boot-starter/build.gradle.kts | 122 +++++++ .../spring/boot/SentryAutoConfiguration.java | 115 +++++++ .../sentry/spring/boot/SentryProperties.java | 314 ++++++++++++++++++ .../spring/boot/SentryRequestFilter.java | 36 ++ ...tryRequestHttpServletRequestProcessor.java | 56 ++++ .../spring/boot/SentrySecurityFilter.java | 50 +++ ...SentryUserHttpServletRequestProcessor.java | 38 +++ .../main/resources/META-INF/spring.factories | 2 + .../boot/SentryAutoConfigurationTest.kt | 308 +++++++++++++++++ ...yRequestHttpServletRequestProcessorTest.kt | 65 ++++ .../boot/SentrySpringIntegrationTest.kt | 123 +++++++ ...ntryUserHttpServletRequestProcessorTest.kt | 34 ++ settings.gradle.kts | 18 +- 25 files changed, 1522 insertions(+), 35 deletions(-) create mode 100644 sentry-samples/sentry-samples-spring-boot/build.gradle.kts create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml create mode 100644 sentry-spring-boot-starter/build.gradle.kts create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java create mode 100644 sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java create mode 100644 sentry-spring-boot-starter/src/main/resources/META-INF/spring.factories create mode 100644 sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt create mode 100644 sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt create mode 100644 sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt create mode 100644 sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 42d9b10d6..1812809fa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -51,7 +51,7 @@ allprojects { dependsOn("cleanTest") } withType { - options.compilerArgs.addAll(arrayOf("-Xlint:all", "-Werror", "-Xlint:-classfile")) + options.compilerArgs.addAll(arrayOf("-Xlint:all", "-Werror", "-Xlint:-classfile", "-Xlint:-processing")) } } } diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 992c82dcb..5eeb45c99 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -2,11 +2,16 @@ object Config { val kotlinVersion = "1.3.72" val kotlinStdLib = "stdlib-jdk8" + val springBootVersion = "2.3.3.RELEASE" + object BuildPlugins { val androidGradle = "com.android.tools.build:gradle:4.0.1" val kotlinGradlePlugin = "gradle-plugin" val buildConfig = "com.github.gmazzo.buildconfig" val buildConfigVersion = "2.0.2" + val springBoot = "org.springframework.boot" + val springDependencyManagement = "io.spring.dependency-management" + val springDependencyManagementVersion = "1.0.10.RELEASE" } object Android { @@ -35,6 +40,16 @@ object Config { val logbackVersion = "1.2.3" val logbackClassic = "ch.qos.logback:logback-classic:$logbackVersion" + + val springBootStarter = "org.springframework.boot:spring-boot-starter:$springBootVersion" + + val springWeb = "org.springframework:spring-webmvc" + val servletApi = "javax.servlet:javax.servlet-api" + } + + object AnnotationProcessors { + val springBootAutoConfigure = "org.springframework.boot:spring-boot-autoconfigure-processor" + val springBootConfiguration = "org.springframework.boot:spring-boot-configuration-processor" } object TestLibs { @@ -47,6 +62,9 @@ object Config { val robolectric = "org.robolectric:robolectric:4.3.1" val mockitoKotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" val awaitility = "org.awaitility:awaitility-kotlin:4.0.3" + val springBootStarterTest = "org.springframework.boot:spring-boot-starter-test:$springBootVersion" + val springBootStarterWeb = "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + val springBootStarterSecurity = "org.springframework.boot:spring-boot-starter-security:$springBootVersion" } object QualityPlugins { @@ -66,6 +84,7 @@ object Config { val SENTRY_JAVA_SDK_NAME = "sentry.java" val SENTRY_ANDROID_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.android" val SENTRY_LOGBACK_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.logback" + val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot" val group = "io.sentry" val description = "SDK for sentry.io" val website = "https://sentry.io" diff --git a/sentry-core/src/main/java/io/sentry/core/Sentry.java b/sentry-core/src/main/java/io/sentry/core/Sentry.java index edb39f592..9459e2793 100644 --- a/sentry-core/src/main/java/io/sentry/core/Sentry.java +++ b/sentry-core/src/main/java/io/sentry/core/Sentry.java @@ -7,6 +7,7 @@ import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.List; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -123,6 +124,16 @@ public static void init( init(options, globalHubMode); } + /** + * Initializes the SDK with a SentryOptions. + * + * @param options options the SentryOptions + */ + @ApiStatus.Internal + public static void init(final @NotNull SentryOptions options) { + init(options, GLOBAL_HUB_DEFAULT_MODE); + } + /** * Initializes the SDK with a SentryOptions and globalHubMode * diff --git a/sentry-core/src/main/java/io/sentry/core/SentryClient.java b/sentry-core/src/main/java/io/sentry/core/SentryClient.java index e65aac25b..ab6394dc0 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryClient.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryClient.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; import org.jetbrains.annotations.ApiStatus; @@ -78,19 +79,7 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c .log(SentryLevel.DEBUG, "Event was cached so not applying scope: %s", event.getEventId()); } - for (EventProcessor processor : options.getEventProcessors()) { - event = processor.process(event, hint); - - if (event == null) { - options - .getLogger() - .log( - SentryLevel.DEBUG, - "Event was dropped by processor: %s", - processor.getClass().getName()); - break; - } - } + event = processEvent(event, hint, options.getEventProcessors()); if (event == null) { return SentryId.EMPTY_ID; @@ -127,6 +116,37 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c return event.getEventId(); } + @Nullable + private SentryEvent processEvent( + @NotNull SentryEvent event, + final @Nullable Object hint, + final @NotNull List eventProcessors) { + for (EventProcessor processor : eventProcessors) { + try { + event = processor.process(event, hint); + } catch (Exception e) { + options + .getLogger() + .log( + SentryLevel.ERROR, + e, + "An exception occurred while processing event by processor: %s", + processor.getClass().getName()); + } + + if (event == null) { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Event was dropped by a processor: %s", + processor.getClass().getName()); + break; + } + } + return event; + } + /** * Updates the session data based on the event, hint and scope data * @@ -274,19 +294,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec event.setLevel(scope.getLevel()); } - for (EventProcessor processor : scope.getEventProcessors()) { - event = processor.process(event, hint); - - if (event == null) { - options - .getLogger() - .log( - SentryLevel.DEBUG, - "Event was dropped by scope processor: %s", - processor.getClass().getName()); - break; - } - } + event = processEvent(event, hint, scope.getEventProcessors()); } return event; } diff --git a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt index 08cb4531d..2670f9a5b 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt @@ -26,6 +26,7 @@ import io.sentry.core.transport.AsyncConnection import io.sentry.core.transport.HttpTransport import io.sentry.core.transport.ITransportGate import java.io.IOException +import java.lang.RuntimeException import java.net.URL import java.util.UUID import kotlin.test.Ignore @@ -655,6 +656,13 @@ class SentryClientTest { }, anyOrNull()) } + @Test + fun `exception thrown by an event processor is handled gracefully`() { + fixture.sentryOptions.addEventProcessor { _, _ -> throw RuntimeException() } + val sut = fixture.getSut() + sut.captureEvent(SentryEvent()) + } + private fun createScope(): Scope { return Scope(SentryOptions()).apply { addBreadcrumb(Breadcrumb().apply { diff --git a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts new file mode 100644 index 000000000..9676cdb87 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts @@ -0,0 +1,40 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id(Config.BuildPlugins.springBoot) version Config.springBootVersion + id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion + kotlin("jvm") + kotlin("plugin.spring") version Config.kotlinVersion +} + +group = "io.sentry.sample.spring-boot" +version = "0.0.1-SNAPSHOT" +java.sourceCompatibility = JavaVersion.VERSION_1_8 + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-security") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation(project(":sentry-spring-boot-starter")) + implementation(project(":sentry-logback")) + testImplementation("org.springframework.boot:spring-boot-starter-test") { + exclude(group = "org.junit.vintage", module = "junit-vintage-engine") + } +} + +tasks.withType { + useJUnitPlatform() +} + +tasks.withType { + kotlinOptions { + freeCompilerArgs = listOf("-Xjsr305=strict") + jvmTarget = JavaVersion.VERSION_1_8.toString() + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java new file mode 100644 index 000000000..f4588a7f6 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java @@ -0,0 +1,24 @@ +package io.sentry.samples.spring; + +public class Person { + private final String firstName; + private final String lastName; + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + @Override + public String toString() { + return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java new file mode 100644 index 000000000..9a2d97316 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java @@ -0,0 +1,27 @@ +package io.sentry.samples.spring; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/person/") +public class PersonController { + private static final Logger LOGGER = LoggerFactory.getLogger(PersonController.class); + + @GetMapping("{id}") + Person person(@PathVariable Long id) { + throw new IllegalArgumentException("Something went wrong [id=" + id + "]"); + } + + @PostMapping + Person create(@RequestBody Person person) { + LOGGER.warn("Creating person: {}", person); + return person; + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java new file mode 100644 index 000000000..d5527cdbb --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java @@ -0,0 +1,55 @@ +package io.sentry.samples.spring; + +import io.sentry.core.IHub; +import io.sentry.spring.boot.SentrySecurityFilter; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final @NotNull IHub hub; + + public SecurityConfiguration(final @NotNull IHub hub) { + this.hub = hub; + } + + @Override + protected void configure(final @NotNull HttpSecurity http) throws Exception { + // register SentrySecurityFilter to attach user information to SentryEvents + http.addFilterAfter(new SentrySecurityFilter(hub), AnonymousAuthenticationFilter.class) + .csrf() + .disable() + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + } + + @Bean + @Override + public @NotNull UserDetailsService userDetailsService() { + final PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); + + final UserDetails user = + User.builder() + .passwordEncoder(encoder::encode) + .username("user") + .password("password") + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java new file mode 100644 index 000000000..43882fe6c --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java @@ -0,0 +1,12 @@ +package io.sentry.samples.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SentryDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(SentryDemoApplication.class, args); + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties new file mode 100644 index 000000000..3d8acbbc1 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties @@ -0,0 +1,2 @@ +# NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry project/dashboard +sentry.dsn=https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml b/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml new file mode 100644 index 000000000..fe050c21c --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + + + WARN + + + + + + + + diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts new file mode 100644 index 000000000..100ea7aee --- /dev/null +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -0,0 +1,122 @@ +import com.novoda.gradle.release.PublishExtension +import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.springframework.boot.gradle.plugin.SpringBootPlugin + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.Deploy.novodaBintray) + id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion + id(Config.BuildPlugins.springBoot) version Config.springBootVersion apply false +} + +apply(plugin = Config.BuildPlugins.springDependencyManagement) + +the().apply { + imports { + mavenBom(SpringBootPlugin.BOM_COORDINATES) + } +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + api(project(":sentry-core")) + implementation(Config.Libs.springBootStarter) + implementation(Config.Libs.springWeb) + implementation(Config.Libs.servletApi) + + annotationProcessor(Config.AnnotationProcessors.springBootAutoConfigure) + annotationProcessor(Config.AnnotationProcessors.springBootConfiguration) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + errorproneJavac(Config.CompileOnly.errorProneJavac8) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.TestLibs.springBootStarterTest) + testImplementation(Config.TestLibs.springBootStarterWeb) + testImplementation(Config.TestLibs.springBootStarterSecurity) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.jacocoVersion +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = BigDecimal.valueOf(0.6) } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +buildConfig { + useJavaOutput() + packageName("io.sentry.spring.boot") + buildConfigField("String", "SENTRY_SPRING_BOOT_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_BOOT_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} + +val generateBuildConfig by tasks +tasks.withType().configureEach { + dependsOn(generateBuildConfig) +} + +//TODO: move these blocks to parent gradle file, DRY +configure { + userOrg = Config.Sentry.userOrg + groupId = project.group.toString() + publishVersion = project.version.toString() + desc = Config.Sentry.description + website = Config.Sentry.website + repoName = Config.Sentry.repoName + setLicences(Config.Sentry.licence) + setLicenceUrls(Config.Sentry.licenceUrl) + issueTracker = Config.Sentry.issueTracker + repository = Config.Sentry.repository + sign = Config.Deploy.sign + artifactId = project.name + uploadName = "${project.group}:${project.name}" + devId = Config.Sentry.userOrg + devName = Config.Sentry.devName + devEmail = Config.Sentry.devEmail + scmConnection = Config.Sentry.scmConnection + scmDevConnection = Config.Sentry.scmDevConnection + scmUrl = Config.Sentry.scmUrl +} + diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java new file mode 100644 index 000000000..57820d14b --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -0,0 +1,115 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.EventProcessor; +import io.sentry.core.HubAdapter; +import io.sentry.core.IHub; +import io.sentry.core.Integration; +import io.sentry.core.Sentry; +import io.sentry.core.SentryOptions; +import io.sentry.core.protocol.SdkVersion; +import io.sentry.core.transport.ITransport; +import io.sentry.core.transport.ITransportGate; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.info.GitProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +@Configuration +@ConditionalOnProperty(name = "sentry.enabled", havingValue = "true", matchIfMissing = true) +@Open +public class SentryAutoConfiguration { + + /** Registers general purpose Sentry related beans. */ + @Configuration + @ConditionalOnProperty("sentry.dsn") + @EnableConfigurationProperties(SentryProperties.class) + @Open + static class HubConfiguration { + + @Bean + @ConditionalOnMissingBean + public @NotNull Sentry.OptionsConfiguration optionsOptionsConfiguration( + final @NotNull ObjectProvider beforeSendCallback, + final @NotNull ObjectProvider + beforeBreadcrumbCallback, + final @NotNull ObjectProvider eventProcessors, + final @NotNull ObjectProvider integrations, + final @NotNull ObjectProvider transportGate, + final @NotNull ObjectProvider transport) { + return options -> { + beforeSendCallback.ifAvailable(options::setBeforeSend); + beforeBreadcrumbCallback.ifAvailable(options::setBeforeBreadcrumb); + eventProcessors.stream().forEach(options::addEventProcessor); + integrations.stream().forEach(options::addIntegration); + transportGate.ifAvailable(options::setTransportGate); + transport.ifAvailable(options::setTransport); + }; + } + + @Bean + public @NotNull SentryOptions sentryOptions( + final @NotNull Sentry.OptionsConfiguration optionsConfiguration, + final @NotNull SentryProperties properties, + final @NotNull ObjectProvider gitProperties) { + final SentryOptions options = new SentryOptions(); + optionsConfiguration.configure(options); + gitProperties.ifAvailable( + git -> { + if (properties.isUseGitCommitIdAsRelease()) { + options.setRelease(git.getCommitId()); + } + }); + properties.applyTo(options); + options.setSentryClientName(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME); + options.setSdkVersion(createSdkVersion(options)); + return options; + } + + @Bean + public @NotNull IHub sentryHub(final @NotNull SentryOptions sentryOptions) { + Sentry.init(sentryOptions); + return HubAdapter.getInstance(); + } + + /** Registers beans specific to Spring MVC. */ + @Configuration + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) + @ConditionalOnProperty("sentry.dsn") + @Open + static class SentryWebMvcConfiguration { + + @Bean + public @NotNull FilterRegistrationBean sentryRequestFilter( + final @NotNull IHub sentryHub) { + FilterRegistrationBean filterRegistrationBean = + new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub)); + filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); + return filterRegistrationBean; + } + } + + private static @NotNull SdkVersion createSdkVersion( + final @NotNull SentryOptions sentryOptions) { + SdkVersion sdkVersion = sentryOptions.getSdkVersion(); + + if (sdkVersion == null) { + sdkVersion = new SdkVersion(); + } + + sdkVersion.setName(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME); + final String version = BuildConfig.VERSION_NAME; + sdkVersion.setVersion(version); + sdkVersion.addPackage("maven:sentry-spring-boot-starter", version); + + return sdkVersion; + } + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java new file mode 100644 index 000000000..947d750ec --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java @@ -0,0 +1,314 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.SentryLevel; +import io.sentry.core.SentryOptions; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** Configuration for Sentry integration. */ +@ConfigurationProperties("sentry") +@Open +public class SentryProperties { + + /** Whether Sentry integration should be enabled. */ + private boolean enabled = true; + + /** + * The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will + * just not send any events. + */ + private String dsn = ""; + + /** + * Controls how many seconds to wait before shutting down. Sentry SDKs send events from a + * background queue and this queue is given a certain amount to drain pending events. + */ + private Long shutdownTimeoutMillis; + + /** + * Controls how many seconds to wait before flushing down. Sentry SDKs cache events from a + * background queue and this queue is given a certain amount to drain pending events. + */ + private Long flushTimeoutMillis; + + /** Read timeout in milliseconds. */ + private Integer readTimeoutMillis; + + /** Whether to ignore TLS errors. */ + private Boolean bypassSecurity; + + /** + * Turns debug mode on or off. If debug is enabled SDK will attempt to print out useful debugging + * information if something goes wrong. Default is disabled. + */ + private Boolean debug; + + /** minimum LogLevel to be used if debug is enabled */ + private SentryLevel diagnosticLevel = SentryLevel.DEBUG; + + /** This variable controls the total amount of breadcrumbs that should be captured. */ + private Integer maxBreadcrumbs; + + /** Sets the release. SDK will try to automatically configure a release out of the box */ + private String release; + + /** + * Sets the environment. This string is freeform and not set by default. A release can be + * associated with more than one environment to separate them in the UI Think staging vs prod or + * similar. + */ + private String environment; + + /** + * Configures the sample rate as a percentage of events to be sent in the range of 0.0 to 1.0. if + * 1.0 is set it means that 100% of events are sent. If set to 0.1 only 10% of events will be + * sent. Events are picked randomly. + */ + private Double sampleRate; + + /** + * A list of string prefixes of module names that do not belong to the app, but rather third-party + * packages. Modules considered not to be part of the app will be hidden from stack traces by + * default. + */ + private List inAppExcludes = new ArrayList<>(); + + /** + * A list of string prefixes of module names that belong to the app. This option takes precedence + * over inAppExcludes. + */ + private List inAppIncludes = new ArrayList<>(); + + /** Sets the distribution. Think about it together with release and environment */ + private String dist; + + /** When enabled, threads are automatically attached to all logged events. */ + private Boolean attachThreads; + + /** + * When enabled, stack traces are automatically attached to all threads logged. Stack traces are + * always attached to exceptions but when this is set stack traces are also sent with threads + */ + private Boolean attachStacktrace; + + /** The server name used in the Sentry messages. */ + private String serverName; + + /** Weather to use Git commit id as a release. */ + private boolean useGitCommitIdAsRelease = true; + + /** + * Applies configuration from this instance to the {@link SentryOptions} instance. + * + * @param options the instance of {@link SentryOptions} to apply the configuration to + */ + public void applyTo(SentryOptions options) { + options.setDsn(this.getDsn()); + Optional.ofNullable(maxBreadcrumbs).ifPresent(options::setMaxBreadcrumbs); + Optional.ofNullable(environment).ifPresent(options::setEnvironment); + Optional.ofNullable(shutdownTimeoutMillis).ifPresent(options::setShutdownTimeout); + Optional.ofNullable(flushTimeoutMillis).ifPresent(options::setFlushTimeoutMillis); + Optional.ofNullable(readTimeoutMillis).ifPresent(options::setReadTimeoutMillis); + Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); + Optional.ofNullable(bypassSecurity).ifPresent(options::setBypassSecurity); + Optional.ofNullable(debug).ifPresent(options::setDebug); + Optional.ofNullable(attachThreads).ifPresent(options::setAttachThreads); + Optional.ofNullable(attachStacktrace).ifPresent(options::setAttachStacktrace); + Optional.ofNullable(diagnosticLevel).ifPresent(options::setDiagnosticLevel); + Optional.ofNullable(dist).ifPresent(options::setDist); + Optional.ofNullable(release).ifPresent(options::setRelease); + Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); + Optional.ofNullable(serverName).ifPresent(options::setServerName); + Optional.ofNullable(inAppExcludes) + .ifPresent(excludes -> excludes.forEach(options::addInAppExclude)); + Optional.ofNullable(inAppIncludes) + .ifPresent(includes -> includes.forEach(options::addInAppInclude)); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getDsn() { + return dsn; + } + + public void setDsn(String dsn) { + this.dsn = dsn; + } + + public long getShutdownTimeoutMillis() { + return shutdownTimeoutMillis; + } + + public void setShutdownTimeoutMillis(long shutdownTimeoutMillis) { + this.shutdownTimeoutMillis = shutdownTimeoutMillis; + } + + public boolean isDebug() { + return debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + public SentryLevel getDiagnosticLevel() { + return diagnosticLevel; + } + + public void setDiagnosticLevel(SentryLevel diagnosticLevel) { + this.diagnosticLevel = diagnosticLevel; + } + + public int getMaxBreadcrumbs() { + return maxBreadcrumbs; + } + + public void setMaxBreadcrumbs(int maxBreadcrumbs) { + this.maxBreadcrumbs = maxBreadcrumbs; + } + + public String getRelease() { + return release; + } + + public void setRelease(String release) { + this.release = release; + } + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public Double getSampleRate() { + return sampleRate; + } + + public void setSampleRate(Double sampleRate) { + this.sampleRate = sampleRate; + } + + public List getInAppExcludes() { + return inAppExcludes; + } + + public void setInAppExcludes(List inAppExcludes) { + this.inAppExcludes = inAppExcludes; + } + + public List getInAppIncludes() { + return inAppIncludes; + } + + public void setInAppIncludes(List inAppIncludes) { + this.inAppIncludes = inAppIncludes; + } + + public String getDist() { + return dist; + } + + public void setDist(String dist) { + this.dist = dist; + } + + public boolean isAttachThreads() { + return attachThreads; + } + + public void setAttachThreads(boolean attachThreads) { + this.attachThreads = attachThreads; + } + + public boolean isAttachStacktrace() { + return attachStacktrace; + } + + public void setAttachStacktrace(boolean attachStacktrace) { + this.attachStacktrace = attachStacktrace; + } + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public void setShutdownTimeoutMillis(Long shutdownTimeoutMillis) { + this.shutdownTimeoutMillis = shutdownTimeoutMillis; + } + + public Long getFlushTimeoutMillis() { + return flushTimeoutMillis; + } + + public void setFlushTimeoutMillis(Long flushTimeoutMillis) { + this.flushTimeoutMillis = flushTimeoutMillis; + } + + public Integer getReadTimeoutMillis() { + return readTimeoutMillis; + } + + public void setReadTimeoutMillis(Integer readTimeoutMillis) { + this.readTimeoutMillis = readTimeoutMillis; + } + + public Boolean getBypassSecurity() { + return bypassSecurity; + } + + public void setBypassSecurity(Boolean bypassSecurity) { + this.bypassSecurity = bypassSecurity; + } + + public Boolean getDebug() { + return debug; + } + + public void setDebug(Boolean debug) { + this.debug = debug; + } + + public void setMaxBreadcrumbs(Integer maxBreadcrumbs) { + this.maxBreadcrumbs = maxBreadcrumbs; + } + + public Boolean getAttachThreads() { + return attachThreads; + } + + public void setAttachThreads(Boolean attachThreads) { + this.attachThreads = attachThreads; + } + + public Boolean getAttachStacktrace() { + return attachStacktrace; + } + + public void setAttachStacktrace(Boolean attachStacktrace) { + this.attachStacktrace = attachStacktrace; + } + + public boolean isUseGitCommitIdAsRelease() { + return useGitCommitIdAsRelease; + } + + public void setUseGitCommitIdAsRelease(boolean useGitCommitIdAsRelease) { + this.useGitCommitIdAsRelease = useGitCommitIdAsRelease; + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java new file mode 100644 index 000000000..31e72d9a3 --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java @@ -0,0 +1,36 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.IHub; +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.filter.OncePerRequestFilter; + +/** Pushes new {@link io.sentry.core.Scope} on each incoming HTTP request. */ +@Open +public class SentryRequestFilter extends OncePerRequestFilter { + private final @NotNull IHub hub; + + public SentryRequestFilter(final @NotNull IHub hub) { + this.hub = hub; + } + + @Override + protected void doFilterInternal( + final @NotNull HttpServletRequest request, + final @NotNull HttpServletResponse response, + final @NotNull FilterChain filterChain) + throws ServletException, IOException { + hub.pushScope(); + + hub.configureScope( + scope -> { + scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(request)); + }); + filterChain.doFilter(request, response); + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java new file mode 100644 index 000000000..af8c78e9f --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java @@ -0,0 +1,56 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.EventProcessor; +import io.sentry.core.SentryEvent; +import io.sentry.core.protocol.Request; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Attaches information about HTTP request to {@link SentryEvent}. */ +@Open +public class SentryRequestHttpServletRequestProcessor implements EventProcessor { + private final @NotNull HttpServletRequest request; + + public SentryRequestHttpServletRequestProcessor(final @NotNull HttpServletRequest request) { + this.request = request; + } + + @Override + public @NotNull SentryEvent process( + final @NotNull SentryEvent event, final @Nullable Object hint) { + event.setRequest(resolveSentryRequest(request)); + return event; + } + + // httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class. + @SuppressWarnings("JdkObsolete") + private static @NotNull Request resolveSentryRequest( + final @NotNull HttpServletRequest httpRequest) { + final Request sentryRequest = new Request(); + sentryRequest.setMethod(httpRequest.getMethod()); + sentryRequest.setQueryString(httpRequest.getQueryString()); + sentryRequest.setUrl(httpRequest.getRequestURL().toString()); + sentryRequest.setHeaders(resolveHeadersMap(httpRequest)); + sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie"))); + return sentryRequest; + } + + private static @NotNull Map resolveHeadersMap( + final @NotNull HttpServletRequest request) { + final Map headersMap = new HashMap<>(); + for (String headerName : Collections.list(request.getHeaderNames())) { + headersMap.put(headerName, toString(request.getHeaders(headerName))); + } + return headersMap; + } + + private static @Nullable String toString(final @Nullable Enumeration enumeration) { + return enumeration != null ? String.join(",", Collections.list(enumeration)) : null; + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java new file mode 100644 index 000000000..2525b4c7f --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java @@ -0,0 +1,50 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.IHub; +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * Adds {@link SentryUserHttpServletRequestProcessor} to the scope in order to decorate {@link + * io.sentry.core.SentryEvent} with principal name and user ip address. + */ +@Open +public class SentrySecurityFilter extends OncePerRequestFilter { + private final @NotNull IHub hub; + + public SentrySecurityFilter(final @NotNull IHub hub) { + this.hub = hub; + } + + @Override + protected void doFilterInternal( + final @NotNull HttpServletRequest request, + final @NotNull HttpServletResponse response, + final @NotNull FilterChain filterChain) + throws ServletException, IOException { + hub.configureScope( + scope -> + scope.addEventProcessor( + new SentryUserHttpServletRequestProcessor( + request.getUserPrincipal(), toIpAddress(request)))); + filterChain.doFilter(request, response); + } + + // it is advised to not use `String#split` method but since we do not have 3rd party libraries + // this is our only option. + @SuppressWarnings("StringSplitter") + private static @NotNull String toIpAddress(final @NotNull HttpServletRequest request) { + final String ipAddress = request.getHeader("X-FORWARDED-FOR"); + if (ipAddress != null) { + return ipAddress.contains(",") ? ipAddress.split(",")[0].trim() : ipAddress; + } else { + return request.getRemoteAddr(); + } + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java new file mode 100644 index 000000000..c3bf8fe0a --- /dev/null +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java @@ -0,0 +1,38 @@ +package io.sentry.spring.boot; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.EventProcessor; +import io.sentry.core.SentryEvent; +import io.sentry.core.protocol.User; +import java.security.Principal; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Attaches user information to the {@link SentryEvent}. */ +@Open +public class SentryUserHttpServletRequestProcessor implements EventProcessor { + private final @Nullable Principal principal; + private final @Nullable String ipAddress; + + public SentryUserHttpServletRequestProcessor( + final @Nullable Principal principal, final @Nullable String ipAddress) { + this.principal = principal; + this.ipAddress = ipAddress; + } + + @Override + public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) { + final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new); + + if (ipAddress != null) { + user.setIpAddress(ipAddress); + } + if (principal != null) { + user.setUsername(principal.getName()); + } + + event.setUser(user); + return event; + } +} diff --git a/sentry-spring-boot-starter/src/main/resources/META-INF/spring.factories b/sentry-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..2eb623a44 --- /dev/null +++ b/sentry-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.sentry.spring.boot.SentryAutoConfiguration diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt new file mode 100644 index 000000000..cef98d47a --- /dev/null +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -0,0 +1,308 @@ +package io.sentry.spring.boot + +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.core.Breadcrumb +import io.sentry.core.EventProcessor +import io.sentry.core.IHub +import io.sentry.core.Integration +import io.sentry.core.Sentry +import io.sentry.core.SentryEvent +import io.sentry.core.SentryLevel +import io.sentry.core.SentryOptions +import io.sentry.core.transport.ITransport +import io.sentry.core.transport.ITransportGate +import kotlin.test.Test +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.kotlin.await +import org.springframework.boot.autoconfigure.AutoConfigurations +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration +import org.springframework.boot.info.GitProperties +import org.springframework.boot.test.context.runner.ApplicationContextRunner +import org.springframework.boot.test.context.runner.WebApplicationContextRunner +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +class SentryAutoConfigurationTest { + private val contextRunner = ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SentryAutoConfiguration::class.java, WebMvcAutoConfiguration::class.java)) + + private val webContextRunner = WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SentryAutoConfiguration::class.java)) + + @Test + fun `hub is not created when auto-configuration is disabled`() { + contextRunner.withPropertyValues("sentry.enabled=false", "sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it).doesNotHaveBean(IHub::class.java) + } + } + + @Test + fun `hub is created when auto-configuration is enabled`() { + contextRunner.withPropertyValues("sentry.enabled=true", "sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it).hasSingleBean(IHub::class.java) + } + } + + @Test + fun `hub is created when dsn is provided`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it).hasSingleBean(IHub::class.java) + } + } + + @Test + fun `hub is not created when dsn is provided but sentry is disabled`() { + contextRunner.withPropertyValues("sentry.enabled=false", "sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it).doesNotHaveBean(IHub::class.java) + } + } + + @Test + fun `OptionsConfiguration is created if custom one is not provided`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it).hasSingleBean(Sentry.OptionsConfiguration::class.java) + } + } + + @Test + fun `OptionsConfiguration is not created if custom one is provided`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomOptionsConfigurationConfiguration::class.java) + .run { + assertThat(it).hasSingleBean(Sentry.OptionsConfiguration::class.java) + assertThat(it.getBean(Sentry.OptionsConfiguration::class.java, "customOptionsConfiguration")).isNotNull + } + } + + @Test + fun `properties are applied to SentryOptions`() { + contextRunner.withPropertyValues( + "sentry.dsn=http://key@localhost/proj", + "sentry.read-timeout-millis=10", + "sentry.shutdown-timeout-millis=20", + "sentry.flush-timeout-millis=30", + "sentry.bypass-security=true", + "sentry.debug=true", + "sentry.diagnostic-level=INFO", + "sentry.sentry-client-name=my-client", + "sentry.max-breadcrumbs=100", + "sentry.release=1.0.3", + "sentry.environment=production", + "sentry.sample-rate=0.2", + "sentry.in-app-excludes[0]=org.springframework", + "sentry.in-app-includes[0]=com.myapp", + "sentry.dist=my-dist", + "sentry.attach-threads=true", + "sentry.attach-stacktrace=true", + "sentry.server-name=host-001" + ).run { + val options = it.getBean(SentryOptions::class.java) + assertThat(options.readTimeoutMillis).isEqualTo(10) + assertThat(options.shutdownTimeout).isEqualTo(20) + assertThat(options.flushTimeoutMillis).isEqualTo(30) + assertThat(options.isBypassSecurity).isTrue() + assertThat(options.isDebug).isTrue() + assertThat(options.diagnosticLevel).isEqualTo(SentryLevel.INFO) + assertThat(options.maxBreadcrumbs).isEqualTo(100) + assertThat(options.release).isEqualTo("1.0.3") + assertThat(options.environment).isEqualTo("production") + assertThat(options.sampleRate).isEqualTo(0.2) + assertThat(options.inAppExcludes).containsOnly("org.springframework") + assertThat(options.inAppIncludes).containsOnly("com.myapp") + assertThat(options.dist).isEqualTo("my-dist") + assertThat(options.isAttachThreads).isEqualTo(true) + assertThat(options.isAttachStacktrace).isEqualTo(true) + assertThat(options.serverName).isEqualTo("host-001") + } + } + + @Test + fun `sets sentryClientName property on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .run { + assertThat(it.getBean(SentryOptions::class.java).sentryClientName).isEqualTo("sentry.java.spring-boot") + } + } + + @Test + fun `sets SDK version on sent events`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(MockTransportConfiguration::class.java) + .run { + Sentry.captureMessage("Some message") + val transport = it.getBean(ITransport::class.java) + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.sdk.version).isEqualTo(BuildConfig.VERSION_NAME) + assertThat(event.sdk.name).isEqualTo(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME) + assertThat(event.sdk.packages).anyMatch { pkg -> + pkg.name == "maven:sentry-spring-boot-starter" && pkg.version == BuildConfig.VERSION_NAME } + }) + } + } + } + + @Test + fun `registers beforeSendCallback on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomBeforeSendCallbackConfiguration::class.java) + .run { + assertThat(it.getBean(SentryOptions::class.java).beforeSend).isInstanceOf(CustomBeforeSendCallback::class.java) + } + } + + @Test + fun `registers beforeBreadcrumbCallback on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomBeforeBreadcrumbCallbackConfiguration::class.java) + .run { + assertThat(it.getBean(SentryOptions::class.java).beforeBreadcrumb).isInstanceOf(CustomBeforeBreadcrumbCallback::class.java) + } + } + + @Test + fun `registers event processor on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomEventProcessorConfiguration::class.java) + .run { + assertThat(it.getBean(SentryOptions::class.java).eventProcessors).anyMatch { processor -> processor.javaClass == CustomEventProcessor::class.java } + } + } + + @Test + fun `registers transport gate on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomTransportGateConfiguration::class.java) + .run { + assertThat(it.getBean(SentryOptions::class.java).transportGate).isInstanceOf(CustomTransportGate::class.java) + } + } + + @Test + fun `registers custom integration on SentryOptions`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(CustomIntegration::class.java) + .run { + assertThat(it.getBean(SentryOptions::class.java).integrations).anyMatch { integration -> integration.javaClass == CustomIntegration::class.java } + } + } + + @Test + fun `sets release on SentryEvents if Git integration is configured`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") + .withUserConfiguration(MockTransportConfiguration::class.java, MockGitPropertiesConfiguration::class.java) + .run { + Sentry.captureMessage("Some message") + val transport = it.getBean(ITransport::class.java) + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.release).isEqualTo("git-commit-id") + }) + } + } + } + + @Test + fun `sets custom release on SentryEvents if release property is set and Git integration is configured`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.release=my-release") + .withUserConfiguration(MockTransportConfiguration::class.java, MockGitPropertiesConfiguration::class.java) + .run { + Sentry.captureMessage("Some message") + val transport = it.getBean(ITransport::class.java) + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.release).isEqualTo("my-release") + }) + } + } + } + + @Configuration(proxyBeanMethods = false) + open class CustomOptionsConfigurationConfiguration { + + @Bean + open fun customOptionsConfiguration() = Sentry.OptionsConfiguration { + } + } + + @Configuration(proxyBeanMethods = false) + open class MockTransportConfiguration { + + @Bean + open fun sentryTransport() = mock() + } + + @Configuration(proxyBeanMethods = false) + open class CustomBeforeSendCallbackConfiguration { + + @Bean + open fun beforeSendCallback() = CustomBeforeSendCallback() + } + + class CustomBeforeSendCallback : SentryOptions.BeforeSendCallback { + override fun execute(event: SentryEvent, hint: Any?): SentryEvent? = null + } + + @Configuration(proxyBeanMethods = false) + open class CustomBeforeBreadcrumbCallbackConfiguration { + + @Bean + open fun beforeBreadcrumbCallback() = CustomBeforeBreadcrumbCallback() + } + + class CustomBeforeBreadcrumbCallback : SentryOptions.BeforeBreadcrumbCallback { + override fun execute(breadcrumb: Breadcrumb, hint: Any?): Breadcrumb? = null + } + + @Configuration(proxyBeanMethods = false) + open class CustomEventProcessorConfiguration { + + @Bean + open fun customEventProcessor() = CustomEventProcessor() + } + + class CustomEventProcessor : EventProcessor { + override fun process(event: SentryEvent?, hint: Any?) = null + } + + @Configuration(proxyBeanMethods = false) + open class CustomIntegrationConfiguration { + + @Bean + open fun customIntegration() = CustomIntegration() + } + + class CustomIntegration : Integration { + override fun register(hub: IHub?, options: SentryOptions?) {} + } + + @Configuration(proxyBeanMethods = false) + open class CustomTransportGateConfiguration { + + @Bean + open fun customTransportGate() = CustomTransportGate() + } + + class CustomTransportGate : ITransportGate { + override fun isConnected() = true + } + + @Configuration(proxyBeanMethods = false) + open class MockGitPropertiesConfiguration { + + @Bean + open fun gitProperties(): GitProperties { + val git = mock() + whenever(git.commitId).thenReturn("git-commit-id") + return git + } + } +} diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt new file mode 100644 index 000000000..7579e5384 --- /dev/null +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt @@ -0,0 +1,65 @@ +package io.sentry.spring.boot + +import io.sentry.core.SentryEvent +import java.net.URI +import kotlin.test.Test +import kotlin.test.assertEquals +import org.springframework.http.MediaType +import org.springframework.mock.web.MockServletContext +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders + +class SentryRequestHttpServletRequestProcessorTest { + + @Test + fun `attaches basic information from HTTP request to SentryEvent`() { + val request = MockMvcRequestBuilders + .get(URI.create("http://example.com?param1=xyz")) + .header("some-header", "some-header value") + .accept(MediaType.APPLICATION_JSON) + .buildRequest(MockServletContext()) + val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertEquals("GET", event.request.method) + assertEquals(mapOf( + "some-header" to "some-header value", + "Accept" to "application/json" + ), event.request.headers) + assertEquals("http://example.com", event.request.url) + assertEquals("param1=xyz", event.request.queryString) + } + + @Test + fun `attaches header with multiple values`() { + val request = MockMvcRequestBuilders + .get(URI.create("http://example.com?param1=xyz")) + .header("another-header", "another value") + .header("another-header", "another value2") + .buildRequest(MockServletContext()) + val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertEquals(mapOf( + "another-header" to "another value,another value2" + ), event.request.headers) + } + + @Test + fun `attaches cookies information`() { + val request = MockMvcRequestBuilders + .get(URI.create("http://example.com?param1=xyz")) + .header("Cookie", "name=value") + .header("Cookie", "name2=value2") + .buildRequest(MockServletContext()) + val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertEquals("name=value,name2=value2", event.request.cookies) + } +} diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt new file mode 100644 index 000000000..0f6dcbe87 --- /dev/null +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -0,0 +1,123 @@ +package io.sentry.spring.boot + +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.verify +import io.sentry.core.IHub +import io.sentry.core.Sentry +import io.sentry.core.SentryEvent +import io.sentry.core.transport.ITransport +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.kotlin.await +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.boot.web.server.LocalServerPort +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpMethod +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.crypto.factory.PasswordEncoderFactories +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter +import org.springframework.test.context.junit4.SpringRunner +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@RunWith(SpringRunner::class) +@SpringBootTest( + classes = [App::class], + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, + properties = ["sentry.dsn=http://key@localhost/proj"] +) +class SentrySpringIntegrationTest { + + @MockBean + lateinit var transport: ITransport + + @LocalServerPort + lateinit var port: Integer + + @Test + fun `attaches request and user information to SentryEvents`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + val headers = HttpHeaders() + headers["X-FORWARDED-FOR"] = listOf("169.128.0.1") + val entity = HttpEntity(headers) + + restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.request).isNotNull() + assertThat(event.request.url).isEqualTo("http://localhost:$port/hello") + assertThat(event.user).isNotNull() + assertThat(event.user.username).isEqualTo("user") + assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") + }) + } + } + + @Test + fun `attaches first ip address if multiple addresses exist in a header`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + val headers = HttpHeaders() + headers["X-FORWARDED-FOR"] = listOf("169.128.0.1, 192.168.0.1") + val entity = HttpEntity(headers) + + restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") + }) + } + } +} + +@SpringBootApplication +open class App + +@RestController +class HelloController { + + @GetMapping("/hello") + fun hello() { + Sentry.captureMessage("hello") + } +} + +@Configuration +open class SecurityConfiguration(private val hub: IHub) : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http + .addFilterAfter(SentrySecurityFilter(hub), AnonymousAuthenticationFilter::class.java) + .csrf().disable() + .authorizeRequests().anyRequest().authenticated() + .and() + .httpBasic() + } + + @Bean + override fun userDetailsService(): UserDetailsService { + val encoder: PasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder() + val user: UserDetails = User + .builder() + .passwordEncoder { rawPassword -> encoder.encode(rawPassword) } + .username("user") + .password("password") + .roles("USER") + .build() + return InMemoryUserDetailsManager(user) + } +} diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt new file mode 100644 index 000000000..d26907783 --- /dev/null +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt @@ -0,0 +1,34 @@ +package io.sentry.spring.boot + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.core.SentryEvent +import java.security.Principal +import kotlin.test.Test +import kotlin.test.assertEquals + +class SentryUserHttpServletRequestProcessorTest { + + @Test + fun `attaches user's IP address to Sentry Event`() { + val eventProcessor = SentryUserHttpServletRequestProcessor(null, "192.168.0.1") + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertEquals("192.168.0.1", event.user.ipAddress) + } + + @Test + fun `attaches username to Sentry Event`() { + val principal = mock() + whenever(principal.name).thenReturn("janesmith") + + val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertEquals("janesmith", event.user.username) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e377bc76d..84aa5eec2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,11 +2,13 @@ rootProject.name = "sentry" rootProject.buildFileName = "build.gradle.kts" include("sentry-android", - "sentry-android-ndk", - "sentry-android-core", - "sentry-core", - "sentry-logback", - "sentry-samples:sentry-samples-android", - "sentry-samples:sentry-samples-console", - "sentry-samples:sentry-samples-logback", - "sentry-android-timber") + "sentry-android-ndk", + "sentry-android-core", + "sentry-core", + "sentry-logback", + "sentry-spring-boot-starter", + "sentry-android-timber", + "sentry-samples:sentry-samples-android", + "sentry-samples:sentry-samples-console", + "sentry-samples:sentry-samples-logback", + "sentry-samples:sentry-samples-spring-boot") From 2d6e2154b6149be423259adcfb8525e65f87b3e3 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Sat, 29 Aug 2020 22:14:32 +0200 Subject: [PATCH 10/28] Refactor binding options (#530) --- .../java/io/sentry/core/SentryOptions.java | 6 +- .../io/sentry/logback/SentryAppender.java | 91 +----- .../io/sentry/logback/SentryAppenderTest.kt | 23 +- .../src/main/resources/logback.xml | 6 +- .../spring/boot/SentryAutoConfiguration.java | 20 +- .../sentry/spring/boot/SentryProperties.java | 294 +----------------- .../boot/SentryAutoConfigurationTest.kt | 26 +- 7 files changed, 44 insertions(+), 422 deletions(-) diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java index c3246f8d3..101a5f49c 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java @@ -48,7 +48,7 @@ public class SentryOptions { * background queue and this queue is given a certain amount to drain pending events Default is * 2000 = 2s */ - private long shutdownTimeoutMillis = 2000; // 2s + private long shutdownTimeout = 2000; // 2s /** * Controls how many seconds to wait before flushing down. Sentry SDKs cache events from a @@ -369,7 +369,7 @@ public void setEnableNdk(boolean enableNdk) { * @return the timeout in Millis */ public long getShutdownTimeout() { - return shutdownTimeoutMillis; + return shutdownTimeout; } /** @@ -378,7 +378,7 @@ public long getShutdownTimeout() { * @param shutdownTimeoutMillis the shutdown timeout in millis */ public void setShutdownTimeout(long shutdownTimeoutMillis) { - this.shutdownTimeoutMillis = shutdownTimeoutMillis; + this.shutdownTimeout = shutdownTimeoutMillis; } /** 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 46c532094..5063a60bc 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -11,7 +11,8 @@ import io.sentry.core.SentryOptions; import io.sentry.core.protocol.Message; import io.sentry.core.protocol.SdkVersion; - +import io.sentry.core.transport.ITransport; +import io.sentry.core.util.CollectionUtils; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -20,48 +21,22 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; - -import io.sentry.core.transport.ITransport; -import io.sentry.core.util.CollectionUtils; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** Appender for logback in charge of sending the logged events to a Sentry server. */ public final class SentryAppender extends UnsynchronizedAppenderBase { - private @Nullable String dsn; - private @Nullable String environment; - private @Nullable Integer maxBreadcrumbs; - private @Nullable Integer shutdownTimeoutMillis; - private @Nullable Integer flushTimeoutMillis; - private @Nullable Integer readTimeoutMillis; - private @Nullable Double sampleRate; - private @Nullable Boolean bypassSecurity; - private @Nullable Boolean debug; - private @Nullable Boolean attachThreads; - private @Nullable Boolean attachStacktrace; + private @Nullable SentryOptions options; private @Nullable ITransport transport; @Override public void start() { - if (dsn != null) { - Sentry.init( - options -> { - options.setDsn(dsn); - Optional.ofNullable(maxBreadcrumbs).ifPresent(options::setMaxBreadcrumbs); - Optional.ofNullable(environment).ifPresent(options::setEnvironment); - Optional.ofNullable(shutdownTimeoutMillis).ifPresent(options::setShutdownTimeout); - Optional.ofNullable(flushTimeoutMillis).ifPresent(options::setFlushTimeoutMillis); - Optional.ofNullable(readTimeoutMillis).ifPresent(options::setReadTimeoutMillis); - Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); - Optional.ofNullable(bypassSecurity).ifPresent(options::setBypassSecurity); - Optional.ofNullable(debug).ifPresent(options::setDebug); - Optional.ofNullable(attachThreads).ifPresent(options::setAttachThreads); - Optional.ofNullable(attachStacktrace).ifPresent(options::setAttachStacktrace); - options.setSentryClientName(BuildConfig.SENTRY_LOGBACK_SDK_NAME); - options.setSdkVersion(createSdkVersion(options)); - Optional.ofNullable(transport).ifPresent(options::setTransport); - }); + if (options != null && options.getDsn() != null) { + options.setSentryClientName(BuildConfig.SENTRY_LOGBACK_SDK_NAME); + options.setSdkVersion(createSdkVersion(options)); + Optional.ofNullable(transport).ifPresent(options::setTransport); + Sentry.init(options); } super.start(); } @@ -79,7 +54,8 @@ protected void append(@NotNull ILoggingEvent eventObject) { */ @SuppressWarnings("JdkObsolete") final @NotNull SentryEvent createEvent(@NotNull ILoggingEvent loggingEvent) { - final SentryEvent event = new SentryEvent(DateUtils.getDateTime(new Date(loggingEvent.getTimeStamp()))); + final SentryEvent event = + new SentryEvent(DateUtils.getDateTime(new Date(loggingEvent.getTimeStamp()))); final Message message = new Message(); message.setMessage(loggingEvent.getMessage()); message.setFormatted(loggingEvent.getFormattedMessage()); @@ -97,7 +73,8 @@ protected void append(@NotNull ILoggingEvent eventObject) { event.setExtra("thread_name", loggingEvent.getThreadName()); } - final Map mdcProperties = CollectionUtils.shallowCopy(loggingEvent.getMDCPropertyMap()); + final Map mdcProperties = + CollectionUtils.shallowCopy(loggingEvent.getMDCPropertyMap()); if (!mdcProperties.isEmpty()) { event.getContexts().put("MDC", mdcProperties); } @@ -149,48 +126,8 @@ protected void append(@NotNull ILoggingEvent eventObject) { return sdkVersion; } - public void setDsn(@Nullable String dsn) { - this.dsn = dsn; - } - - public void setEnvironment(@Nullable String environment) { - this.environment = environment; - } - - public void setMaxBreadcrumbs(@Nullable Integer maxBreadcrumbs) { - this.maxBreadcrumbs = maxBreadcrumbs; - } - - public void setShutdownTimeoutMillis(@Nullable Integer shutdownTimeoutMillis) { - this.shutdownTimeoutMillis = shutdownTimeoutMillis; - } - - public void setFlushTimeoutMillis(@Nullable Integer flushTimeoutMillis) { - this.flushTimeoutMillis = flushTimeoutMillis; - } - - public void setReadTimeoutMillis(@Nullable Integer readTimeoutMillis) { - this.readTimeoutMillis = readTimeoutMillis; - } - - public void setSampleRate(@Nullable Double sampleRate) { - this.sampleRate = sampleRate; - } - - public void setBypassSecurity(@Nullable Boolean bypassSecurity) { - this.bypassSecurity = bypassSecurity; - } - - public void setDebug(@Nullable Boolean debug) { - this.debug = debug; - } - - public void setAttachThreads(@Nullable Boolean attachThreads) { - this.attachThreads = attachThreads; - } - - public void setAttachStacktrace(@Nullable Boolean attachStacktrace) { - this.attachStacktrace = attachStacktrace; + public void setOptions(SentryOptions options) { + this.options = options; } @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 d54c4472a..262e4b3d9 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -9,22 +9,23 @@ import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import io.sentry.core.SentryEvent import io.sentry.core.SentryLevel +import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport import io.sentry.core.transport.TransportResult -import org.awaitility.kotlin.await -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.slf4j.MDC import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId import kotlin.test.AfterTest import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotNull import kotlin.test.assertTrue +import org.awaitility.kotlin.await +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.slf4j.MDC class SentryAppenderTest { private class Fixture { @@ -36,7 +37,9 @@ class SentryAppenderTest { whenever(transport.send(any())).thenReturn(TransportResult.success()) val appender = SentryAppender() - appender.setDsn("http://key@localhost/proj") + val options = SentryOptions() + options.dsn = "http://key@localhost/proj" + appender.setOptions(options) appender.context = loggerContext appender.setTransport(transport) @@ -204,8 +207,8 @@ class SentryAppenderTest { assertEquals(BuildConfig.VERSION_NAME, it.sdk.version) assertNotNull(it.sdk.packages) assertTrue(it.sdk.packages!!.any { pkg -> - "maven:sentry-logback" == pkg.name - && BuildConfig.VERSION_NAME == pkg.version + "maven:sentry-logback" == pkg.name && + BuildConfig.VERSION_NAME == pkg.version }) }) } 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 2d10daa78..e0004e806 100644 --- a/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml +++ b/sentry-samples/sentry-samples-logback/src/main/resources/logback.xml @@ -7,8 +7,10 @@ - - https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 + + + https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 + diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index 57820d14b..ffda4a04a 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -23,13 +23,12 @@ import org.springframework.core.Ordered; @Configuration -@ConditionalOnProperty(name = "sentry.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnProperty(name = "sentry.dsn") @Open public class SentryAutoConfiguration { /** Registers general purpose Sentry related beans. */ @Configuration - @ConditionalOnProperty("sentry.dsn") @EnableConfigurationProperties(SentryProperties.class) @Open static class HubConfiguration { @@ -55,34 +54,27 @@ static class HubConfiguration { } @Bean - public @NotNull SentryOptions sentryOptions( + public @NotNull IHub sentryHub( final @NotNull Sentry.OptionsConfiguration optionsConfiguration, - final @NotNull SentryProperties properties, + final @NotNull SentryProperties options, final @NotNull ObjectProvider gitProperties) { - final SentryOptions options = new SentryOptions(); optionsConfiguration.configure(options); gitProperties.ifAvailable( git -> { - if (properties.isUseGitCommitIdAsRelease()) { + if (options.getRelease() == null && options.isUseGitCommitIdAsRelease()) { options.setRelease(git.getCommitId()); } }); - properties.applyTo(options); + options.setSentryClientName(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME); options.setSdkVersion(createSdkVersion(options)); - return options; - } - - @Bean - public @NotNull IHub sentryHub(final @NotNull SentryOptions sentryOptions) { - Sentry.init(sentryOptions); + Sentry.init(options); return HubAdapter.getInstance(); } /** Registers beans specific to Spring MVC. */ @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) - @ConditionalOnProperty("sentry.dsn") @Open static class SentryWebMvcConfiguration { diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java index 947d750ec..18cb6f4ee 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java @@ -1,309 +1,17 @@ package io.sentry.spring.boot; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; import org.springframework.boot.context.properties.ConfigurationProperties; /** Configuration for Sentry integration. */ @ConfigurationProperties("sentry") @Open -public class SentryProperties { - - /** Whether Sentry integration should be enabled. */ - private boolean enabled = true; - - /** - * The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will - * just not send any events. - */ - private String dsn = ""; - - /** - * Controls how many seconds to wait before shutting down. Sentry SDKs send events from a - * background queue and this queue is given a certain amount to drain pending events. - */ - private Long shutdownTimeoutMillis; - - /** - * Controls how many seconds to wait before flushing down. Sentry SDKs cache events from a - * background queue and this queue is given a certain amount to drain pending events. - */ - private Long flushTimeoutMillis; - - /** Read timeout in milliseconds. */ - private Integer readTimeoutMillis; - - /** Whether to ignore TLS errors. */ - private Boolean bypassSecurity; - - /** - * Turns debug mode on or off. If debug is enabled SDK will attempt to print out useful debugging - * information if something goes wrong. Default is disabled. - */ - private Boolean debug; - - /** minimum LogLevel to be used if debug is enabled */ - private SentryLevel diagnosticLevel = SentryLevel.DEBUG; - - /** This variable controls the total amount of breadcrumbs that should be captured. */ - private Integer maxBreadcrumbs; - - /** Sets the release. SDK will try to automatically configure a release out of the box */ - private String release; - - /** - * Sets the environment. This string is freeform and not set by default. A release can be - * associated with more than one environment to separate them in the UI Think staging vs prod or - * similar. - */ - private String environment; - - /** - * Configures the sample rate as a percentage of events to be sent in the range of 0.0 to 1.0. if - * 1.0 is set it means that 100% of events are sent. If set to 0.1 only 10% of events will be - * sent. Events are picked randomly. - */ - private Double sampleRate; - - /** - * A list of string prefixes of module names that do not belong to the app, but rather third-party - * packages. Modules considered not to be part of the app will be hidden from stack traces by - * default. - */ - private List inAppExcludes = new ArrayList<>(); - - /** - * A list of string prefixes of module names that belong to the app. This option takes precedence - * over inAppExcludes. - */ - private List inAppIncludes = new ArrayList<>(); - - /** Sets the distribution. Think about it together with release and environment */ - private String dist; - - /** When enabled, threads are automatically attached to all logged events. */ - private Boolean attachThreads; - - /** - * When enabled, stack traces are automatically attached to all threads logged. Stack traces are - * always attached to exceptions but when this is set stack traces are also sent with threads - */ - private Boolean attachStacktrace; - - /** The server name used in the Sentry messages. */ - private String serverName; +public class SentryProperties extends SentryOptions { /** Weather to use Git commit id as a release. */ private boolean useGitCommitIdAsRelease = true; - /** - * Applies configuration from this instance to the {@link SentryOptions} instance. - * - * @param options the instance of {@link SentryOptions} to apply the configuration to - */ - public void applyTo(SentryOptions options) { - options.setDsn(this.getDsn()); - Optional.ofNullable(maxBreadcrumbs).ifPresent(options::setMaxBreadcrumbs); - Optional.ofNullable(environment).ifPresent(options::setEnvironment); - Optional.ofNullable(shutdownTimeoutMillis).ifPresent(options::setShutdownTimeout); - Optional.ofNullable(flushTimeoutMillis).ifPresent(options::setFlushTimeoutMillis); - Optional.ofNullable(readTimeoutMillis).ifPresent(options::setReadTimeoutMillis); - Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); - Optional.ofNullable(bypassSecurity).ifPresent(options::setBypassSecurity); - Optional.ofNullable(debug).ifPresent(options::setDebug); - Optional.ofNullable(attachThreads).ifPresent(options::setAttachThreads); - Optional.ofNullable(attachStacktrace).ifPresent(options::setAttachStacktrace); - Optional.ofNullable(diagnosticLevel).ifPresent(options::setDiagnosticLevel); - Optional.ofNullable(dist).ifPresent(options::setDist); - Optional.ofNullable(release).ifPresent(options::setRelease); - Optional.ofNullable(sampleRate).ifPresent(options::setSampleRate); - Optional.ofNullable(serverName).ifPresent(options::setServerName); - Optional.ofNullable(inAppExcludes) - .ifPresent(excludes -> excludes.forEach(options::addInAppExclude)); - Optional.ofNullable(inAppIncludes) - .ifPresent(includes -> includes.forEach(options::addInAppInclude)); - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getDsn() { - return dsn; - } - - public void setDsn(String dsn) { - this.dsn = dsn; - } - - public long getShutdownTimeoutMillis() { - return shutdownTimeoutMillis; - } - - public void setShutdownTimeoutMillis(long shutdownTimeoutMillis) { - this.shutdownTimeoutMillis = shutdownTimeoutMillis; - } - - public boolean isDebug() { - return debug; - } - - public void setDebug(boolean debug) { - this.debug = debug; - } - - public SentryLevel getDiagnosticLevel() { - return diagnosticLevel; - } - - public void setDiagnosticLevel(SentryLevel diagnosticLevel) { - this.diagnosticLevel = diagnosticLevel; - } - - public int getMaxBreadcrumbs() { - return maxBreadcrumbs; - } - - public void setMaxBreadcrumbs(int maxBreadcrumbs) { - this.maxBreadcrumbs = maxBreadcrumbs; - } - - public String getRelease() { - return release; - } - - public void setRelease(String release) { - this.release = release; - } - - public String getEnvironment() { - return environment; - } - - public void setEnvironment(String environment) { - this.environment = environment; - } - - public Double getSampleRate() { - return sampleRate; - } - - public void setSampleRate(Double sampleRate) { - this.sampleRate = sampleRate; - } - - public List getInAppExcludes() { - return inAppExcludes; - } - - public void setInAppExcludes(List inAppExcludes) { - this.inAppExcludes = inAppExcludes; - } - - public List getInAppIncludes() { - return inAppIncludes; - } - - public void setInAppIncludes(List inAppIncludes) { - this.inAppIncludes = inAppIncludes; - } - - public String getDist() { - return dist; - } - - public void setDist(String dist) { - this.dist = dist; - } - - public boolean isAttachThreads() { - return attachThreads; - } - - public void setAttachThreads(boolean attachThreads) { - this.attachThreads = attachThreads; - } - - public boolean isAttachStacktrace() { - return attachStacktrace; - } - - public void setAttachStacktrace(boolean attachStacktrace) { - this.attachStacktrace = attachStacktrace; - } - - public String getServerName() { - return serverName; - } - - public void setServerName(String serverName) { - this.serverName = serverName; - } - - public void setShutdownTimeoutMillis(Long shutdownTimeoutMillis) { - this.shutdownTimeoutMillis = shutdownTimeoutMillis; - } - - public Long getFlushTimeoutMillis() { - return flushTimeoutMillis; - } - - public void setFlushTimeoutMillis(Long flushTimeoutMillis) { - this.flushTimeoutMillis = flushTimeoutMillis; - } - - public Integer getReadTimeoutMillis() { - return readTimeoutMillis; - } - - public void setReadTimeoutMillis(Integer readTimeoutMillis) { - this.readTimeoutMillis = readTimeoutMillis; - } - - public Boolean getBypassSecurity() { - return bypassSecurity; - } - - public void setBypassSecurity(Boolean bypassSecurity) { - this.bypassSecurity = bypassSecurity; - } - - public Boolean getDebug() { - return debug; - } - - public void setDebug(Boolean debug) { - this.debug = debug; - } - - public void setMaxBreadcrumbs(Integer maxBreadcrumbs) { - this.maxBreadcrumbs = maxBreadcrumbs; - } - - public Boolean getAttachThreads() { - return attachThreads; - } - - public void setAttachThreads(Boolean attachThreads) { - this.attachThreads = attachThreads; - } - - public Boolean getAttachStacktrace() { - return attachStacktrace; - } - - public void setAttachStacktrace(Boolean attachStacktrace) { - this.attachStacktrace = attachStacktrace; - } - public boolean isUseGitCommitIdAsRelease() { return useGitCommitIdAsRelease; } diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index cef98d47a..43571670a 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -21,7 +21,6 @@ import org.springframework.boot.autoconfigure.AutoConfigurations import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration import org.springframework.boot.info.GitProperties import org.springframework.boot.test.context.runner.ApplicationContextRunner -import org.springframework.boot.test.context.runner.WebApplicationContextRunner import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -29,25 +28,14 @@ class SentryAutoConfigurationTest { private val contextRunner = ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(SentryAutoConfiguration::class.java, WebMvcAutoConfiguration::class.java)) - private val webContextRunner = WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(SentryAutoConfiguration::class.java)) - @Test - fun `hub is not created when auto-configuration is disabled`() { - contextRunner.withPropertyValues("sentry.enabled=false", "sentry.dsn=http://key@localhost/proj") + fun `hub is not created when auto-configuration dsn is not set`() { + contextRunner .run { assertThat(it).doesNotHaveBean(IHub::class.java) } } - @Test - fun `hub is created when auto-configuration is enabled`() { - contextRunner.withPropertyValues("sentry.enabled=true", "sentry.dsn=http://key@localhost/proj") - .run { - assertThat(it).hasSingleBean(IHub::class.java) - } - } - @Test fun `hub is created when dsn is provided`() { contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") @@ -56,14 +44,6 @@ class SentryAutoConfigurationTest { } } - @Test - fun `hub is not created when dsn is provided but sentry is disabled`() { - contextRunner.withPropertyValues("sentry.enabled=false", "sentry.dsn=http://key@localhost/proj") - .run { - assertThat(it).doesNotHaveBean(IHub::class.java) - } - } - @Test fun `OptionsConfiguration is created if custom one is not provided`() { contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj") @@ -87,7 +67,7 @@ class SentryAutoConfigurationTest { contextRunner.withPropertyValues( "sentry.dsn=http://key@localhost/proj", "sentry.read-timeout-millis=10", - "sentry.shutdown-timeout-millis=20", + "sentry.shutdown-timeout=20", "sentry.flush-timeout-millis=30", "sentry.bypass-security=true", "sentry.debug=true", From 0a8bde665c0c918acf4af449207ffa544e6edf4a Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Sun, 30 Aug 2020 15:26:38 +0200 Subject: [PATCH 11/28] Add `sendDefaultPii` flag to `SentryOptions`. (#531) * Add `sendDefaultPii` flag to `SentryOptions`. Filters out user information and sensitive request headers in Spring Boot integration if this flag is set to false. * Polish. --- .../java/io/sentry/core/SentryOptions.java | 11 ++++ .../samples/spring/SecurityConfiguration.java | 9 +++- .../src/main/resources/application.properties | 1 + .../spring/boot/SentryAutoConfiguration.java | 4 +- .../spring/boot/SentryRequestFilter.java | 7 ++- ...tryRequestHttpServletRequestProcessor.java | 26 ++++++--- .../spring/boot/SentrySecurityFilter.java | 7 ++- ...SentryUserHttpServletRequestProcessor.java | 25 +++++---- ...yRequestHttpServletRequestProcessorTest.kt | 54 +++++++++++++++++-- .../boot/SentrySpringIntegrationTest.kt | 10 ++-- ...ntryUserHttpServletRequestProcessorTest.kt | 25 ++++++++- 11 files changed, 147 insertions(+), 32 deletions(-) diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java index 101a5f49c..7c10b1702 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java @@ -210,6 +210,9 @@ public class SentryOptions { /** SdkVersion object that contains the Sentry Client Name and its version */ private @Nullable SdkVersion sdkVersion; + /** whether to send personal identifiable information along with events */ + private boolean sendDefaultPii = false; + /** * Adds an event processor * @@ -996,6 +999,14 @@ public void setSdkVersion(final @Nullable SdkVersion sdkVersion) { this.sdkVersion = sdkVersion; } + public boolean isSendDefaultPii() { + return sendDefaultPii; + } + + public void setSendDefaultPii(boolean sendDefaultPii) { + this.sendDefaultPii = sendDefaultPii; + } + /** The BeforeSend callback */ public interface BeforeSendCallback { diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java index d5527cdbb..5d8173881 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java @@ -1,6 +1,7 @@ package io.sentry.samples.spring; import io.sentry.core.IHub; +import io.sentry.core.SentryOptions; import io.sentry.spring.boot.SentrySecurityFilter; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; @@ -19,15 +20,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { private final @NotNull IHub hub; + private final @NotNull SentryOptions options; - public SecurityConfiguration(final @NotNull IHub hub) { + public SecurityConfiguration(final @NotNull IHub hub, final @NotNull SentryOptions options) { this.hub = hub; + this.options = options; } + // this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed. @Override + @SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]") protected void configure(final @NotNull HttpSecurity http) throws Exception { // register SentrySecurityFilter to attach user information to SentryEvents - http.addFilterAfter(new SentrySecurityFilter(hub), AnonymousAuthenticationFilter.class) + http.addFilterAfter(new SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter.class) .csrf() .disable() .authorizeRequests() diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties index 3d8acbbc1..9f28892b0 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties +++ b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties @@ -1,2 +1,3 @@ # NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry project/dashboard sentry.dsn=https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 +sentry.send-default-pii=true diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index ffda4a04a..4f768765d 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -80,9 +80,9 @@ static class SentryWebMvcConfiguration { @Bean public @NotNull FilterRegistrationBean sentryRequestFilter( - final @NotNull IHub sentryHub) { + final @NotNull IHub sentryHub, final @NotNull SentryOptions sentryOptions) { FilterRegistrationBean filterRegistrationBean = - new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub)); + new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub, sentryOptions)); filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return filterRegistrationBean; } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java index 31e72d9a3..fe0fb81aa 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java @@ -2,6 +2,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.core.IHub; +import io.sentry.core.SentryOptions; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -14,9 +15,11 @@ @Open public class SentryRequestFilter extends OncePerRequestFilter { private final @NotNull IHub hub; + private final @NotNull SentryOptions options; - public SentryRequestFilter(final @NotNull IHub hub) { + public SentryRequestFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) { this.hub = hub; + this.options = options; } @Override @@ -29,7 +32,7 @@ protected void doFilterInternal( hub.configureScope( scope -> { - scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(request)); + scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(request, options)); }); filterChain.doFilter(request, response); } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java index af8c78e9f..7b718377f 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java @@ -3,10 +3,13 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.core.EventProcessor; import io.sentry.core.SentryEvent; +import io.sentry.core.SentryOptions; import io.sentry.core.protocol.Request; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.jetbrains.annotations.NotNull; @@ -15,10 +18,16 @@ /** Attaches information about HTTP request to {@link SentryEvent}. */ @Open public class SentryRequestHttpServletRequestProcessor implements EventProcessor { + private static final List SENSITIVE_HEADERS = + Arrays.asList("X-FORWARDED-FOR", "AUTHORIZATION", "COOKIES"); + private final @NotNull HttpServletRequest request; + private final @NotNull SentryOptions options; - public SentryRequestHttpServletRequestProcessor(final @NotNull HttpServletRequest request) { + public SentryRequestHttpServletRequestProcessor( + final @NotNull HttpServletRequest request, final @NotNull SentryOptions options) { this.request = request; + this.options = options; } @Override @@ -30,22 +39,27 @@ public SentryRequestHttpServletRequestProcessor(final @NotNull HttpServletReques // httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class. @SuppressWarnings("JdkObsolete") - private static @NotNull Request resolveSentryRequest( - final @NotNull HttpServletRequest httpRequest) { + private @NotNull Request resolveSentryRequest(final @NotNull HttpServletRequest httpRequest) { final Request sentryRequest = new Request(); sentryRequest.setMethod(httpRequest.getMethod()); sentryRequest.setQueryString(httpRequest.getQueryString()); sentryRequest.setUrl(httpRequest.getRequestURL().toString()); sentryRequest.setHeaders(resolveHeadersMap(httpRequest)); - sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie"))); + + if (options.isSendDefaultPii()) { + sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie"))); + } return sentryRequest; } - private static @NotNull Map resolveHeadersMap( + private @NotNull Map resolveHeadersMap( final @NotNull HttpServletRequest request) { final Map headersMap = new HashMap<>(); for (String headerName : Collections.list(request.getHeaderNames())) { - headersMap.put(headerName, toString(request.getHeaders(headerName))); + // do not copy personal information identifiable headers + if (options.isSendDefaultPii() || !SENSITIVE_HEADERS.contains(headerName.toUpperCase())) { + headersMap.put(headerName, toString(request.getHeaders(headerName))); + } } return headersMap; } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java index 2525b4c7f..546e8dd79 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java @@ -2,6 +2,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.core.IHub; +import io.sentry.core.SentryOptions; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -17,9 +18,11 @@ @Open public class SentrySecurityFilter extends OncePerRequestFilter { private final @NotNull IHub hub; + private final @NotNull SentryOptions options; - public SentrySecurityFilter(final @NotNull IHub hub) { + public SentrySecurityFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) { this.hub = hub; + this.options = options; } @Override @@ -32,7 +35,7 @@ protected void doFilterInternal( scope -> scope.addEventProcessor( new SentryUserHttpServletRequestProcessor( - request.getUserPrincipal(), toIpAddress(request)))); + request.getUserPrincipal(), toIpAddress(request), options))); filterChain.doFilter(request, response); } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java index c3bf8fe0a..c9bfff93e 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java @@ -3,6 +3,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.core.EventProcessor; import io.sentry.core.SentryEvent; +import io.sentry.core.SentryOptions; import io.sentry.core.protocol.User; import java.security.Principal; import java.util.Optional; @@ -14,25 +15,31 @@ public class SentryUserHttpServletRequestProcessor implements EventProcessor { private final @Nullable Principal principal; private final @Nullable String ipAddress; + private final @NotNull SentryOptions options; public SentryUserHttpServletRequestProcessor( - final @Nullable Principal principal, final @Nullable String ipAddress) { + final @Nullable Principal principal, + final @Nullable String ipAddress, + final @NotNull SentryOptions options) { this.principal = principal; this.ipAddress = ipAddress; + this.options = options; } @Override public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) { - final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new); + if (options.isSendDefaultPii()) { + final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new); - if (ipAddress != null) { - user.setIpAddress(ipAddress); - } - if (principal != null) { - user.setUsername(principal.getName()); - } + if (ipAddress != null) { + user.setIpAddress(ipAddress); + } + if (principal != null) { + user.setUsername(principal.getName()); + } - event.setUser(user); + event.setUser(user); + } return event; } } diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt index 7579e5384..ba709d6c9 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt @@ -1,9 +1,13 @@ package io.sentry.spring.boot import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions import java.net.URI import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNull +import kotlin.test.assertTrue import org.springframework.http.MediaType import org.springframework.mock.web.MockServletContext import org.springframework.test.web.servlet.request.MockMvcRequestBuilders @@ -17,7 +21,7 @@ class SentryRequestHttpServletRequestProcessorTest { .header("some-header", "some-header value") .accept(MediaType.APPLICATION_JSON) .buildRequest(MockServletContext()) - val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val eventProcessor = SentryRequestHttpServletRequestProcessor(request, SentryOptions()) val event = SentryEvent() eventProcessor.process(event, null) @@ -38,7 +42,7 @@ class SentryRequestHttpServletRequestProcessorTest { .header("another-header", "another value") .header("another-header", "another value2") .buildRequest(MockServletContext()) - val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val eventProcessor = SentryRequestHttpServletRequestProcessor(request, SentryOptions()) val event = SentryEvent() eventProcessor.process(event, null) @@ -49,17 +53,59 @@ class SentryRequestHttpServletRequestProcessorTest { } @Test - fun `attaches cookies information`() { + fun `when sendDefaultPii is set to true, attaches cookies information`() { val request = MockMvcRequestBuilders .get(URI.create("http://example.com?param1=xyz")) .header("Cookie", "name=value") .header("Cookie", "name2=value2") .buildRequest(MockServletContext()) - val eventProcessor = SentryRequestHttpServletRequestProcessor(request) + val sentryOptions = SentryOptions() + sentryOptions.isSendDefaultPii = true + val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions) val event = SentryEvent() eventProcessor.process(event, null) assertEquals("name=value,name2=value2", event.request.cookies) } + + @Test + fun `when sendDefaultPii is set to false, does not attach cookies`() { + val request = MockMvcRequestBuilders + .get(URI.create("http://example.com?param1=xyz")) + .header("Cookie", "name=value") + .buildRequest(MockServletContext()) + val sentryOptions = SentryOptions() + sentryOptions.isSendDefaultPii = false + val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertNull(event.request.cookies) + } + + @Test + fun `when sendDefaultPii is set to false, does not attach sensitive headers`() { + val request = MockMvcRequestBuilders + .get(URI.create("http://example.com?param1=xyz")) + .header("some-header", "some-header value") + .header("X-FORWARDED-FOR", "192.168.0.1") + .header("authorization", "Token") + .header("Authorization", "Token") + .header("Cookies", "some cookies") + .buildRequest(MockServletContext()) + val sentryOptions = SentryOptions() + sentryOptions.isSendDefaultPii = false + val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertFalse(event.request.headers.containsKey("X-FORWARDED-FOR")) + assertFalse(event.request.headers.containsKey("Authorization")) + assertFalse(event.request.headers.containsKey("authorization")) + assertFalse(event.request.headers.containsKey("Cookies")) + assertTrue(event.request.headers.containsKey("some-header")) + } } diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt index 0f6dcbe87..e5d0cd1ee 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockitokotlin2.verify import io.sentry.core.IHub import io.sentry.core.Sentry import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await @@ -37,7 +38,7 @@ import org.springframework.web.bind.annotation.RestController @SpringBootTest( classes = [App::class], webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, - properties = ["sentry.dsn=http://key@localhost/proj"] + properties = ["sentry.dsn=http://key@localhost/proj", "sentry.send-default-pii=true"] ) class SentrySpringIntegrationTest { @@ -97,11 +98,14 @@ class HelloController { } @Configuration -open class SecurityConfiguration(private val hub: IHub) : WebSecurityConfigurerAdapter() { +open class SecurityConfiguration( + private val hub: IHub, + private val options: SentryOptions +) : WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { http - .addFilterAfter(SentrySecurityFilter(hub), AnonymousAuthenticationFilter::class.java) + .addFilterAfter(SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter::class.java) .csrf().disable() .authorizeRequests().anyRequest().authenticated() .and() diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt index d26907783..9fa3fe46e 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt @@ -3,15 +3,19 @@ package io.sentry.spring.boot import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions import java.security.Principal import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNull class SentryUserHttpServletRequestProcessorTest { @Test fun `attaches user's IP address to Sentry Event`() { - val eventProcessor = SentryUserHttpServletRequestProcessor(null, "192.168.0.1") + val options = SentryOptions() + options.isSendDefaultPii = true + val eventProcessor = SentryUserHttpServletRequestProcessor(null, "192.168.0.1", options) val event = SentryEvent() eventProcessor.process(event, null) @@ -24,11 +28,28 @@ class SentryUserHttpServletRequestProcessorTest { val principal = mock() whenever(principal.name).thenReturn("janesmith") - val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null) + val options = SentryOptions() + options.isSendDefaultPii = true + val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null, options) val event = SentryEvent() eventProcessor.process(event, null) assertEquals("janesmith", event.user.username) } + + @Test + fun `when sendDefaultPii is set to false, does not attach user data Sentry Event`() { + val principal = mock() + whenever(principal.name).thenReturn("janesmith") + + val options = SentryOptions() + options.isSendDefaultPii = false + val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null, options) + val event = SentryEvent() + + eventProcessor.process(event, null) + + assertNull(event.user) + } } From 82e4efec5f92b351b34088df04121b7a53d37f93 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 1 Sep 2020 00:05:30 +0200 Subject: [PATCH 12/28] Attach breadcrumbs to events triggered in Logback integration. (#532) --- .../io/sentry/logback/SentryAppender.java | 38 ++++++++- .../io/sentry/logback/SentryAppenderTest.kt | 80 +++++++++++++++++-- .../src/main/resources/logback.xml | 11 +-- 3 files changed, 117 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..fb2236b8e 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 @NotNull Level minimumBreadcrumbLevel = Level.INFO; + private @NotNull Level minimumEventLevel = Level.ERROR; @Override public void start() { @@ -43,7 +46,12 @@ public void start() { @Override protected void append(@NotNull ILoggingEvent eventObject) { - Sentry.captureEvent(createEvent(eventObject)); + if (eventObject.getLevel().isGreaterOrEqual(minimumEventLevel)) { + Sentry.captureEvent(createEvent(eventObject)); + } + if (eventObject.getLevel().isGreaterOrEqual(minimumBreadcrumbLevel)) { + Sentry.addBreadcrumb(createBreadcrumb(eventObject)); + } } /** @@ -93,6 +101,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 +148,22 @@ 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) { + if (minimumBreadcrumbLevel != null) { + this.minimumBreadcrumbLevel = minimumBreadcrumbLevel; + } + } + + public void setMinimumEventLevel(final @Nullable Level minimumEventLevel) { + if (minimumEventLevel != null) { + 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..0eb02a366 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -28,31 +28,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 +65,7 @@ class SentryAppenderTest { @Test fun `converts message`() { + fixture = Fixture(minimumEventLevel = Level.DEBUG) fixture.logger.debug("testing message conversion {}, {}", 1, 2) await.untilAsserted { @@ -80,6 +80,7 @@ class SentryAppenderTest { @Test fun `event date is in UTC`() { + fixture = Fixture(minimumEventLevel = Level.DEBUG) val utcTime = LocalDateTime.now(ZoneId.of("UTC")) fixture.logger.debug("testing event date") @@ -98,6 +99,7 @@ class SentryAppenderTest { @Test fun `converts trace log level to Sentry level`() { + fixture = Fixture(minimumEventLevel = Level.TRACE) fixture.logger.trace("testing trace level") await.untilAsserted { @@ -109,6 +111,7 @@ class SentryAppenderTest { @Test fun `converts debug log level to Sentry level`() { + fixture = Fixture(minimumEventLevel = Level.DEBUG) fixture.logger.debug("testing debug level") await.untilAsserted { @@ -120,6 +123,7 @@ class SentryAppenderTest { @Test fun `converts info log level to Sentry level`() { + fixture = Fixture(minimumEventLevel = Level.INFO) fixture.logger.info("testing info level") await.untilAsserted { @@ -131,6 +135,7 @@ class SentryAppenderTest { @Test fun `converts warn log level to Sentry level`() { + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing warn level") await.untilAsserted { @@ -142,6 +147,7 @@ class SentryAppenderTest { @Test fun `converts error log level to Sentry level`() { + fixture = Fixture(minimumEventLevel = Level.ERROR) fixture.logger.error("testing error level") await.untilAsserted { @@ -153,6 +159,7 @@ class SentryAppenderTest { @Test fun `attaches thread information`() { + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing thread information") await.untilAsserted { @@ -164,6 +171,7 @@ class SentryAppenderTest { @Test fun `sets tags from MDC`() { + fixture = Fixture(minimumEventLevel = Level.WARN) MDC.put("key", "value") fixture.logger.warn("testing MDC tags") @@ -176,6 +184,7 @@ class SentryAppenderTest { @Test fun `does not create MDC context when no MDC tags are set`() { + fixture = Fixture(minimumEventLevel = Level.WARN) fixture.logger.warn("testing without MDC tags") await.untilAsserted { @@ -187,6 +196,7 @@ class SentryAppenderTest { @Test fun `attaches throwable`() { + fixture = Fixture(minimumEventLevel = Level.WARN) val throwable = RuntimeException("something went wrong") fixture.logger.warn("testing throwable", throwable) @@ -199,6 +209,7 @@ class SentryAppenderTest { @Test fun `sets SDK version`() { + fixture = Fixture(minimumEventLevel = Level.INFO) fixture.logger.info("testing sdk version") await.untilAsserted { @@ -213,4 +224,63 @@ class SentryAppenderTest { }) } } + + @Test + 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") + 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) + }) + } + } + + @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 e0004e806..76de7f2f3 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,14 @@ https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 - - - - - + + + WARN + + DEBUG + From 944f4780d579fe52239b70b82df31270d0d2158b Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:51:53 +0200 Subject: [PATCH 13/28] Bump to 3.0.0-alpha.1 (#535) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index fbcd63e15..5ee4f9c38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ android.useAndroidX=true # Release information buildVersionCode=20038 -versionName=2.3.2-SNAPSHOT +versionName=3.0.0-alpha.1-SNAPSHOT # disable renderscript, it's enabled by default android.defaults.buildfeatures.renderscript=false From eefdd315146c2c867fe81bc452431688c5505c0d Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:52:16 +0200 Subject: [PATCH 14/28] feat: enable release health by default (#534) --- .../io/sentry/android/core/ManifestMetadataReaderTest.kt | 6 +++--- sentry-core/src/main/java/io/sentry/core/SentryOptions.java | 4 ++-- .../sentry-samples-android/src/main/AndroidManifest.xml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt index aebc78a1a..08b8ca85d 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt @@ -97,13 +97,13 @@ class ManifestMetadataReaderTest { val options = SentryAndroidOptions() val bundle = Bundle() val mockContext = ContextUtilsTest.mockMetaData(metaData = bundle) - bundle.putBoolean(ManifestMetadataReader.SESSION_TRACKING_ENABLE, true) + bundle.putBoolean(ManifestMetadataReader.SESSION_TRACKING_ENABLE, false) // Act ManifestMetadataReader.applyMetadata(mockContext, options) // Assert - assertTrue(options.isEnableSessionTracking) + assertFalse(options.isEnableSessionTracking) } @Test @@ -117,7 +117,7 @@ class ManifestMetadataReaderTest { ManifestMetadataReader.applyMetadata(mockContext, options) // Assert - assertFalse(options.isEnableSessionTracking) + assertTrue(options.isEnableSessionTracking) } @Test diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java index c3246f8d3..f3310859e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java @@ -169,8 +169,8 @@ public class SentryOptions { */ private boolean attachStacktrace; - /** Whether to enable automatic session tracking. */ - private boolean enableSessionTracking; + /** Whether to enable or disable automatic session tracking. */ + private boolean enableSessionTracking = true; /** * The session tracking interval in millis. This is the interval to end a session if the App goes diff --git a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml index 8920c9db0..dc9962982 100644 --- a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml +++ b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml @@ -59,8 +59,8 @@ - - + + From 35750dd2c4e595aa9aaff6759a3aec235f320bb2 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 2 Sep 2020 19:53:08 +0200 Subject: [PATCH 15/28] Add Log4j2 integration. (#537) --- buildSrc/src/main/java/Config.kt | 5 + sentry-log4j2/build.gradle.kts | 103 ++++++ .../java/io/sentry/log4j2/SentryAppender.java | 206 +++++++++++ .../io/sentry/log4j2/SentryAppenderTest.kt | 319 ++++++++++++++++++ .../org.mockito.plugins.MockMaker | 1 + .../io/sentry/logback/SentryAppender.java | 1 + .../sentry-samples-log4j2/build.gradle.kts | 14 + .../java/io/sentry/samples/log4j2/Main.java | 30 ++ .../src/main/resources/log4j2.xml | 22 ++ settings.gradle.kts | 2 + 10 files changed, 703 insertions(+) create mode 100644 sentry-log4j2/build.gradle.kts create mode 100644 sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java create mode 100644 sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt create mode 100644 sentry-log4j2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker create mode 100644 sentry-samples/sentry-samples-log4j2/build.gradle.kts create mode 100644 sentry-samples/sentry-samples-log4j2/src/main/java/io/sentry/samples/log4j2/Main.java create mode 100644 sentry-samples/sentry-samples-log4j2/src/main/resources/log4j2.xml diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 5eeb45c99..9246dbb3d 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -41,6 +41,10 @@ object Config { val logbackVersion = "1.2.3" val logbackClassic = "ch.qos.logback:logback-classic:$logbackVersion" + val log4j2Version = "2.13.3" + val log4j2Api = "org.apache.logging.log4j:log4j-api:$log4j2Version" + val log4j2Core = "org.apache.logging.log4j:log4j-core:$log4j2Version" + val springBootStarter = "org.springframework.boot:spring-boot-starter:$springBootVersion" val springWeb = "org.springframework:spring-webmvc" @@ -84,6 +88,7 @@ object Config { val SENTRY_JAVA_SDK_NAME = "sentry.java" val SENTRY_ANDROID_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.android" val SENTRY_LOGBACK_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.logback" + val SENTRY_LOG4J2_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.log4j2" val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot" val group = "io.sentry" val description = "SDK for sentry.io" diff --git a/sentry-log4j2/build.gradle.kts b/sentry-log4j2/build.gradle.kts new file mode 100644 index 000000000..f2c4408c7 --- /dev/null +++ b/sentry-log4j2/build.gradle.kts @@ -0,0 +1,103 @@ +import com.novoda.gradle.release.PublishExtension + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.Deploy.novodaBintray) + id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + api(project(":sentry-core")) + implementation(Config.Libs.log4j2Api) + implementation(Config.Libs.log4j2Core) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + errorproneJavac(Config.CompileOnly.errorProneJavac8) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.jacocoVersion +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = BigDecimal.valueOf(0.6) } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +buildConfig { + useJavaOutput() + packageName("io.sentry.log4j2") + buildConfigField("String", "SENTRY_LOG4J2_SDK_NAME", "\"${Config.Sentry.SENTRY_LOG4J2_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} + +val generateBuildConfig by tasks +tasks.withType().configureEach { + dependsOn(generateBuildConfig) +} + +//TODO: move these blocks to parent gradle file, DRY +configure { + userOrg = Config.Sentry.userOrg + groupId = project.group.toString() + publishVersion = project.version.toString() + desc = Config.Sentry.description + website = Config.Sentry.website + repoName = Config.Sentry.repoName + setLicences(Config.Sentry.licence) + setLicenceUrls(Config.Sentry.licenceUrl) + issueTracker = Config.Sentry.issueTracker + repository = Config.Sentry.repository + sign = Config.Deploy.sign + artifactId = project.name + uploadName = "${project.group}:${project.name}" + devId = Config.Sentry.userOrg + devName = Config.Sentry.devName + devEmail = Config.Sentry.devEmail + scmConnection = Config.Sentry.scmConnection + scmDevConnection = Config.Sentry.scmDevConnection + scmUrl = Config.Sentry.scmUrl +} + diff --git a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java new file mode 100644 index 000000000..c12dd6ecf --- /dev/null +++ b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java @@ -0,0 +1,206 @@ +package io.sentry.log4j2; + +import io.sentry.core.Breadcrumb; +import io.sentry.core.DateUtils; +import io.sentry.core.HubAdapter; +import io.sentry.core.IHub; +import io.sentry.core.Sentry; +import io.sentry.core.SentryEvent; +import io.sentry.core.SentryLevel; +import io.sentry.core.SentryOptions; +import io.sentry.core.protocol.Message; +import io.sentry.core.protocol.SdkVersion; +import io.sentry.core.transport.ITransport; +import io.sentry.core.util.CollectionUtils; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Appender for Log4j2 in charge of sending the logged events to a Sentry server. */ +@Plugin(name = "Sentry", category = "Core", elementType = "appender", printObject = true) +public final class SentryAppender extends AbstractAppender { + private final @Nullable String dsn; + private final @Nullable ITransport transport; + private @NotNull Level minimumBreadcrumbLevel = Level.INFO; + private @NotNull Level minimumEventLevel = Level.ERROR; + private final @NotNull IHub hub; + + public SentryAppender( + final @NotNull String name, + final @Nullable Filter filter, + final @Nullable String dsn, + final @Nullable Level minimumBreadcrumbLevel, + final @Nullable Level minimumEventLevel, + final @Nullable ITransport transport, + final @NotNull IHub hub) { + super(name, filter, null, true, null); + this.dsn = dsn; + if (minimumBreadcrumbLevel != null) { + this.minimumBreadcrumbLevel = minimumBreadcrumbLevel; + } + if (minimumEventLevel != null) { + this.minimumEventLevel = minimumEventLevel; + } + this.transport = transport; + this.hub = hub; + } + + /** + * Create a Sentry Appender. + * + * @param name The name of the Appender. + * @param filter The filter, if any, to use. + * @return The SentryAppender. + */ + @PluginFactory + public static SentryAppender createAppender( + @PluginAttribute("name") final String name, + @PluginAttribute("minimumBreadcrumbLevel") final Level minimumBreadcrumbLevel, + @PluginAttribute("minimumEventLevel") final Level minimumEventLevel, + @PluginAttribute("dsn") final String dsn, + @PluginElement("filter") final Filter filter) { + + if (name == null) { + LOGGER.error("No name provided for SentryAppender"); + return null; + } + return new SentryAppender(name, filter, dsn, minimumBreadcrumbLevel, minimumEventLevel, null, HubAdapter.getInstance()); + } + + @Override + public void start() { + if (dsn != null) { + Sentry.init( + options -> { + options.setDsn(dsn); + options.setSentryClientName(BuildConfig.SENTRY_LOG4J2_SDK_NAME); + options.setSdkVersion(createSdkVersion(options)); + Optional.ofNullable(transport).ifPresent(options::setTransport); + }); + } + super.start(); + } + + @Override + public void append(final @NotNull LogEvent eventObject) { + if (eventObject.getLevel().isMoreSpecificThan(minimumEventLevel)) { + hub.captureEvent(createEvent(eventObject)); + } + if (eventObject.getLevel().isMoreSpecificThan(minimumBreadcrumbLevel)) { + hub.addBreadcrumb(createBreadcrumb(eventObject)); + } + } + + /** + * Creates {@link SentryEvent} from Log4j2 {@link LogEvent}. + * + * @param loggingEvent the log4j2 event + * @return the sentry event + */ + // for the Android compatibility we must use old Java Date class + @SuppressWarnings("JdkObsolete") + final @NotNull SentryEvent createEvent(final @NotNull LogEvent loggingEvent) { + final SentryEvent event = + new SentryEvent(DateUtils.getDateTime(new Date(loggingEvent.getTimeMillis()))); + final Message message = new Message(); + message.setMessage(loggingEvent.getMessage().getFormat()); + message.setFormatted(loggingEvent.getMessage().getFormattedMessage()); + message.setParams(toParams(loggingEvent.getMessage().getParameters())); + event.setMessage(message); + event.setLogger(loggingEvent.getLoggerName()); + event.setLevel(formatLevel(loggingEvent.getLevel())); + + final ThrowableProxy throwableInformation = loggingEvent.getThrownProxy(); + if (throwableInformation != null) { + event.setThrowable(throwableInformation.getThrowable()); + } + + if (loggingEvent.getThreadName() != null) { + event.setExtra("thread_name", loggingEvent.getThreadName()); + } + + final Map contextData = + CollectionUtils.shallowCopy(loggingEvent.getContextData().toMap()); + if (!contextData.isEmpty()) { + event.getContexts().put("Context Data", contextData); + } + + return event; + } + + private @NotNull List toParams(final @Nullable Object[] arguments) { + if (arguments != null) { + return Arrays.stream(arguments) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + /** + * Creates {@link Breadcrumb} from log4j2 {@link LogEvent}. + * + * @param loggingEvent the log4j2 event + * @return the sentry breadcrumb + */ + private @NotNull Breadcrumb createBreadcrumb(final @NotNull LogEvent loggingEvent) { + final Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setLevel(formatLevel(loggingEvent.getLevel())); + breadcrumb.setCategory(loggingEvent.getLoggerName()); + breadcrumb.setMessage(loggingEvent.getMessage().getFormattedMessage()); + return breadcrumb; + } + + /** + * Transforms a {@link Level} into an {@link SentryLevel}. + * + * @param level original level as defined in log4j. + * @return log level used within sentry. + */ + private static @NotNull SentryLevel formatLevel(final @NotNull Level level) { + if (level.isMoreSpecificThan(Level.FATAL)) { + return SentryLevel.FATAL; + } else if (level.isMoreSpecificThan(Level.ERROR)) { + return SentryLevel.ERROR; + } else if (level.isMoreSpecificThan(Level.WARN)) { + return SentryLevel.WARNING; + } else if (level.isMoreSpecificThan(Level.INFO)) { + return SentryLevel.INFO; + } else { + return SentryLevel.DEBUG; + } + } + + private @NotNull SdkVersion createSdkVersion(final @NotNull SentryOptions sentryOptions) { + SdkVersion sdkVersion = sentryOptions.getSdkVersion(); + + if (sdkVersion == null) { + sdkVersion = new SdkVersion(); + } + + sdkVersion.setName(BuildConfig.SENTRY_LOG4J2_SDK_NAME); + final String version = BuildConfig.VERSION_NAME; + sdkVersion.setVersion(version); + sdkVersion.addPackage("maven:sentry-log4j2", version); + + return sdkVersion; + } +} diff --git a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt new file mode 100644 index 000000000..f1c5bd1ce --- /dev/null +++ b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt @@ -0,0 +1,319 @@ +package io.sentry.log4j2 + +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import io.sentry.core.HubAdapter +import io.sentry.core.SentryEvent +import io.sentry.core.SentryLevel +import io.sentry.core.transport.ITransport +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.ThreadContext +import org.apache.logging.log4j.core.LoggerContext +import org.apache.logging.log4j.core.config.AppenderRef +import org.apache.logging.log4j.core.config.Configuration +import org.apache.logging.log4j.core.config.LoggerConfig +import org.apache.logging.log4j.spi.ExtendedLogger +import org.awaitility.kotlin.await + +class SentryAppenderTest { + private class Fixture { + val transport = mock() + val loggerContext = LogManager.getContext() as LoggerContext + var minimumBreadcrumbLevel: Level? = null + var minimumEventLevel: Level? = null + + fun getSut(): ExtendedLogger { + loggerContext.start() + val config: Configuration = loggerContext.configuration + val appender = SentryAppender("sentry", null, "http://key@localhost/proj", minimumBreadcrumbLevel, minimumEventLevel, transport, HubAdapter.getInstance()) + config.addAppender(appender) + + val ref = AppenderRef.createAppenderRef("sentry", null, null) + + val loggerConfig = LoggerConfig.createLogger(false, Level.TRACE, "sentry_logger", "true", arrayOf(ref), null, config, null) + loggerConfig.addAppender(appender, null, null) + config.addLogger(SentryAppenderTest::class.java.name, loggerConfig) + + loggerContext.updateLoggers(config) + + appender.start() + loggerContext.start() + + return LogManager.getContext().getLogger(SentryAppenderTest::class.java.name) + } + } + + private var fixture = Fixture() + + @AfterTest + fun `stop log4j2`() { + fixture.loggerContext.stop() + } + + @BeforeTest + fun `clear MDC`() { + ThreadContext.clearAll() + } + + @Test + fun `converts message`() { + fixture.minimumEventLevel = Level.DEBUG + val logger = fixture.getSut() + logger.debug("testing message conversion {}, {}", 1, 2) + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals("testing message conversion 1, 2", it.message.formatted) + assertEquals("testing message conversion {}, {}", it.message.message) + assertEquals(listOf("1", "2"), it.message.params) + assertEquals("io.sentry.log4j2.SentryAppenderTest", it.logger) + }) + } + } + + @Test + fun `event date is in UTC`() { + fixture.minimumEventLevel = Level.DEBUG + val logger = fixture.getSut() + val utcTime = LocalDateTime.now(ZoneId.of("UTC")) + + logger.debug("testing event date") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + val eventTime = Instant.ofEpochMilli(it.timestamp.time) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + + assertTrue { eventTime.plusSeconds(1).isAfter(utcTime) } + assertTrue { eventTime.minusSeconds(1).isBefore(utcTime) } + }) + } + } + + @Test + fun `converts trace log level to Sentry level`() { + fixture.minimumEventLevel = Level.TRACE + val logger = fixture.getSut() + logger.trace("testing trace level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.DEBUG, it.level) + }) + } + } + + @Test + fun `converts debug log level to Sentry level`() { + fixture.minimumEventLevel = Level.DEBUG + val logger = fixture.getSut() + logger.debug("testing debug level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.DEBUG, it.level) + }) + } + } + + @Test + fun `converts info log level to Sentry level`() { + fixture.minimumEventLevel = Level.INFO + val logger = fixture.getSut() + logger.info("testing info level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.INFO, it.level) + }) + } + } + + @Test + fun `converts warn log level to Sentry level`() { + fixture.minimumEventLevel = Level.WARN + val logger = fixture.getSut() + logger.warn("testing warn level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.WARNING, it.level) + }) + } + } + + @Test + fun `converts error log level to Sentry level`() { + fixture.minimumEventLevel = Level.ERROR + val logger = fixture.getSut() + logger.error("testing error level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.ERROR, it.level) + }) + } + } + + @Test + fun `converts fatal log level to Sentry level`() { + fixture.minimumEventLevel = Level.FATAL + val logger = fixture.getSut() + logger.fatal("testing fatal level") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(SentryLevel.FATAL, it.level) + }) + } + } + + @Test + fun `attaches thread information`() { + fixture.minimumEventLevel = Level.WARN + val logger = fixture.getSut() + logger.warn("testing thread information") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertNotNull(it.getExtra("thread_name")) + }) + } + } + + @Test + fun `sets tags from ThreadContext`() { + fixture.minimumEventLevel = Level.WARN + val logger = fixture.getSut() + ThreadContext.put("key", "value") + logger.warn("testing MDC tags") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(mapOf("key" to "value"), it.contexts["Context Data"]) + }) + } + } + + @Test + fun `does not create MDC context when no MDC tags are set`() { + fixture.minimumEventLevel = Level.WARN + val logger = fixture.getSut() + logger.warn("testing without MDC tags") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertFalse(it.contexts.containsKey("MDC")) + }) + } + } + + @Test + fun `attaches throwable`() { + fixture.minimumEventLevel = Level.WARN + val logger = fixture.getSut() + val throwable = RuntimeException("something went wrong") + logger.warn("testing throwable", throwable) + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(throwable, it.throwable) + }) + } + } + + @Test + fun `sets SDK version`() { + fixture.minimumEventLevel = Level.INFO + val logger = fixture.getSut() + logger.info("testing sdk version") + + await.untilAsserted { + verify(fixture.transport).send(check { it: SentryEvent -> + assertEquals(BuildConfig.SENTRY_LOG4J2_SDK_NAME, it.sdk.name) + assertEquals(BuildConfig.VERSION_NAME, it.sdk.version) + assertNotNull(it.sdk.packages) + assertTrue(it.sdk.packages!!.any { pkg -> + "maven:sentry-log4j2" == pkg.name && + BuildConfig.VERSION_NAME == pkg.version + }) + }) + } + } + + @Test + fun `attaches breadcrumbs with level higher than minimumBreadcrumbLevel`() { + fixture.minimumEventLevel = Level.WARN + fixture.minimumBreadcrumbLevel = Level.DEBUG + val logger = fixture.getSut() + val utcTime = LocalDateTime.now(ZoneId.of("UTC")) + + logger.debug("this should be a breadcrumb #1") + logger.info("this should be a breadcrumb #2") + 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.log4j2.SentryAppenderTest", breadcrumb.category) + assertEquals(SentryLevel.DEBUG, breadcrumb.level) + }) + } + } + + @Test + fun `does not attach breadcrumbs with level lower than minimumBreadcrumbLevel`() { + fixture.minimumEventLevel = Level.WARN + fixture.minimumBreadcrumbLevel = Level.INFO + val logger = fixture.getSut() + + logger.debug("this should NOT be a breadcrumb") + logger.info("this should be a breadcrumb") + 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`() { + val logger = fixture.getSut() + + logger.debug("this should not be a breadcrumb as the level is lower than the minimum INFO") + logger.info("this should be a breadcrumb") + logger.warn("this should not be sent as the event but be a breadcrumb") + 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-log4j2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sentry-log4j2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..1f0955d45 --- /dev/null +++ b/sentry-log4j2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline 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 fb2236b8e..35e69b829 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -60,6 +60,7 @@ protected void append(@NotNull ILoggingEvent eventObject) { * @param loggingEvent the logback event * @return the sentry event */ + // for the Android compatibility we must use old Java Date class @SuppressWarnings("JdkObsolete") final @NotNull SentryEvent createEvent(@NotNull ILoggingEvent loggingEvent) { final SentryEvent event = diff --git a/sentry-samples/sentry-samples-log4j2/build.gradle.kts b/sentry-samples/sentry-samples-log4j2/build.gradle.kts new file mode 100644 index 000000000..69785a28e --- /dev/null +++ b/sentry-samples/sentry-samples-log4j2/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + java + id(Config.QualityPlugins.gradleVersions) +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + implementation(project(":sentry-log4j2")) + implementation(Config.Libs.log4j2Api) +} diff --git a/sentry-samples/sentry-samples-log4j2/src/main/java/io/sentry/samples/log4j2/Main.java b/sentry-samples/sentry-samples-log4j2/src/main/java/io/sentry/samples/log4j2/Main.java new file mode 100644 index 000000000..6f1a4b79c --- /dev/null +++ b/sentry-samples/sentry-samples-log4j2/src/main/java/io/sentry/samples/log4j2/Main.java @@ -0,0 +1,30 @@ +package io.sentry.samples.log4j2; + +import java.util.UUID; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; + +public class Main { + private static final Logger LOGGER = LogManager.getLogger(Main.class); + + public static void main(String[] args) { + // The SDK was initialized through the appender configuration because a DSN was set there. + // Update the DSN in log4j2.xml to see these events in your Sentry dashboard. + LOGGER.debug("Hello Sentry!"); + + // ThreadContext parameters are converted to Sentry Event tags + ThreadContext.put("userId", UUID.randomUUID().toString()); + + // logging arguments are converted to Sentry Event parameters + LOGGER.info("User has made a purchase of product: {}", 445); + // because minimumEventLevel is set to WARN this raises an event + LOGGER.warn("Important warning"); + + try { + throw new RuntimeException("Invalid productId=445"); + } catch (Exception e) { + LOGGER.error("Something went wrong", e); + } + } +} diff --git a/sentry-samples/sentry-samples-log4j2/src/main/resources/log4j2.xml b/sentry-samples/sentry-samples-log4j2/src/main/resources/log4j2.xml new file mode 100644 index 000000000..b7df67f12 --- /dev/null +++ b/sentry-samples/sentry-samples-log4j2/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index 84aa5eec2..1a05fde78 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,10 +5,12 @@ include("sentry-android", "sentry-android-ndk", "sentry-android-core", "sentry-core", + "sentry-log4j2", "sentry-logback", "sentry-spring-boot-starter", "sentry-android-timber", "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", + "sentry-samples:sentry-samples-log4j2", "sentry-samples:sentry-samples-logback", "sentry-samples:sentry-samples-spring-boot") From 3737aab7ba1588736ca7234015c8690099fc90bb Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Thu, 3 Sep 2020 10:18:52 +0200 Subject: [PATCH 16/28] feat: session updates along with the event (#514) --- .../core/AndroidOptionsInitializer.java | 16 +- .../core/EnvelopeFileObserverIntegration.java | 8 +- .../android/core/ManifestMetadataReader.java | 1 + .../core/AndroidOptionsInitializerTest.kt | 16 +- .../sentry/core/AsyncConnectionFactory.java | 7 +- .../io/sentry/core/DirectoryProcessor.java | 14 +- .../java/io/sentry/core/EnvelopeSender.java | 218 +++++------------- .../java/io/sentry/core/OutboxSender.java | 176 ++++++++++++++ .../src/main/java/io/sentry/core/Scope.java | 10 +- ...chedEnvelopeFireAndForgetIntegration.java} | 5 +- .../java/io/sentry/core/SendCachedEvent.java | 130 ----------- .../core/SendFireAndForgetEnvelopeSender.java | 14 +- .../core/SendFireAndForgetEventSender.java | 34 --- .../core/SendFireAndForgetOutboxSender.java | 44 ++++ .../src/main/java/io/sentry/core/Sentry.java | 9 +- .../java/io/sentry/core/SentryClient.java | 166 +++++++------ .../java/io/sentry/core/SentryOptions.java | 58 +---- .../UncaughtExceptionHandlerIntegration.java | 4 +- .../java/io/sentry/core/cache/DiskCache.java | 130 ----------- .../{SessionCache.java => EnvelopeCache.java} | 16 +- .../io/sentry/core/cache/IEventCache.java | 30 --- .../io/sentry/core/hints/SessionUpdate.java | 4 - .../sentry/core/hints/SessionUpdateHint.java | 3 - .../core/transport/AsyncConnection.java | 187 ++------------- .../io/sentry/core/transport/Connection.java | 7 - .../sentry/core/transport/NoOpEventCache.java | 28 --- .../io/sentry/core/DirectoryProcessorTest.kt | 18 +- .../java/io/sentry/core/EnvelopeSenderTest.kt | 194 +++++----------- .../java/io/sentry/core/OutboxSenderTest.kt | 187 +++++++++++++++ ...edEnvelopeFireAndForgetIntegrationTest.kt} | 14 +- .../io/sentry/core/SendCachedEventTest.kt | 115 --------- .../java/io/sentry/core/SentryClientTest.kt | 73 +++--- .../java/io/sentry/core/SentryOptionsTest.kt | 13 -- .../test/java/io/sentry/core/SentryTest.kt | 14 -- .../io/sentry/core/cache/DiskCacheTest.kt | 114 --------- ...ssionCacheTest.kt => EnvelopeCacheTest.kt} | 75 ++---- .../core/transport/AsyncConnectionTest.kt | 142 +++--------- 37 files changed, 797 insertions(+), 1497 deletions(-) create mode 100644 sentry-core/src/main/java/io/sentry/core/OutboxSender.java rename sentry-core/src/main/java/io/sentry/core/{SendCachedEventFireAndForgetIntegration.java => SendCachedEnvelopeFireAndForgetIntegration.java} (93%) delete mode 100644 sentry-core/src/main/java/io/sentry/core/SendCachedEvent.java delete mode 100644 sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEventSender.java create mode 100644 sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java delete mode 100644 sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java rename sentry-core/src/main/java/io/sentry/core/cache/{SessionCache.java => EnvelopeCache.java} (96%) delete mode 100644 sentry-core/src/main/java/io/sentry/core/cache/IEventCache.java delete mode 100644 sentry-core/src/main/java/io/sentry/core/hints/SessionUpdate.java delete mode 100644 sentry-core/src/main/java/io/sentry/core/hints/SessionUpdateHint.java delete mode 100644 sentry-core/src/main/java/io/sentry/core/transport/NoOpEventCache.java create mode 100644 sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt rename sentry-core/src/test/java/io/sentry/core/{SendCachedEventFireAndForgetIntegrationTest.kt => SendCachedEnvelopeFireAndForgetIntegrationTest.kt} (77%) delete mode 100644 sentry-core/src/test/java/io/sentry/core/SendCachedEventTest.kt delete mode 100644 sentry-core/src/test/java/io/sentry/core/cache/DiskCacheTest.kt rename sentry-core/src/test/java/io/sentry/core/cache/{SessionCacheTest.kt => EnvelopeCacheTest.kt} (69%) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 7454566ce..d58393b40 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -7,9 +7,9 @@ import android.content.pm.PackageInfo; import android.os.Build; import io.sentry.core.ILogger; -import io.sentry.core.SendCachedEventFireAndForgetIntegration; +import io.sentry.core.SendCachedEnvelopeFireAndForgetIntegration; import io.sentry.core.SendFireAndForgetEnvelopeSender; -import io.sentry.core.SendFireAndForgetEventSender; +import io.sentry.core.SendFireAndForgetOutboxSender; import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; import io.sentry.core.util.Objects; @@ -116,12 +116,8 @@ private static void installDefaultIntegrations( final @NotNull ILoadClass loadClass) { options.addIntegration( - new SendCachedEventFireAndForgetIntegration( - new SendFireAndForgetEventSender(() -> options.getCacheDirPath()))); - - options.addIntegration( - new SendCachedEventFireAndForgetIntegration( - new SendFireAndForgetEnvelopeSender(() -> options.getSessionsPath()))); + new SendCachedEnvelopeFireAndForgetIntegration( + new SendFireAndForgetEnvelopeSender(() -> options.getCacheDirPath()))); // Integrations are registered in the same order. NDK before adding Watch outbox, // because sentry-native move files around and we don't want to watch that. @@ -136,8 +132,8 @@ private static void installDefaultIntegrations( // this should be executed after NdkIntegration because sentry-native move files on init. // and we'd like to send them right away options.addIntegration( - new SendCachedEventFireAndForgetIntegration( - new SendFireAndForgetEnvelopeSender(() -> options.getOutboxPath()))); + new SendCachedEnvelopeFireAndForgetIntegration( + new SendFireAndForgetOutboxSender(() -> options.getOutboxPath()))); options.addIntegration(new AnrIntegration(context)); options.addIntegration(new AppLifecycleIntegration()); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java index dcfdcc6ed..340fd9e92 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java @@ -1,9 +1,9 @@ package io.sentry.android.core; -import io.sentry.core.EnvelopeSender; import io.sentry.core.IHub; import io.sentry.core.ILogger; import io.sentry.core.Integration; +import io.sentry.core.OutboxSender; import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; import io.sentry.core.util.Objects; @@ -37,8 +37,8 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions logger.log( SentryLevel.DEBUG, "Registering EnvelopeFileObserverIntegration for path: %s", path); - final EnvelopeSender envelopeSender = - new EnvelopeSender( + final OutboxSender outboxSender = + new OutboxSender( hub, options.getEnvelopeReader(), options.getSerializer(), @@ -46,7 +46,7 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions options.getFlushTimeoutMillis()); observer = - new EnvelopeFileObserver(path, envelopeSender, logger, options.getFlushTimeoutMillis()); + new EnvelopeFileObserver(path, outboxSender, logger, options.getFlushTimeoutMillis()); observer.startWatching(); logger.log(SentryLevel.DEBUG, "EnvelopeFileObserverIntegration installed."); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java index 11fad962a..6077b528d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java @@ -84,6 +84,7 @@ static void applyMetadata( options.setEnableSessionTracking(sessionTrackingEnabled); if (options.getSampleRate() == null) { + // TODO: it needs to read a Float I guess Double sampleRate = metadata.getDouble(SAMPLE_RATE, -1); options.getLogger().log(SentryLevel.DEBUG, "sampleRate read: %s", sampleRate); if (sampleRate != -1) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index e0c04602b..658935874 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -13,7 +13,7 @@ import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import io.sentry.core.ILogger import io.sentry.core.MainEventProcessor -import io.sentry.core.SendCachedEventFireAndForgetIntegration +import io.sentry.core.SendCachedEnvelopeFireAndForgetIntegration import io.sentry.core.SentryLevel import io.sentry.core.SentryOptions import java.io.File @@ -92,16 +92,6 @@ class AndroidOptionsInitializerTest { assertTrue(sentryOptions.outboxPath?.endsWith("${File.separator}cache${File.separator}sentry${File.separator}outbox")!!) } - @Test - fun `sessionDir should be set at initialization`() { - val sentryOptions = SentryAndroidOptions() - val mockContext = createMockContext() - - AndroidOptionsInitializer.init(sentryOptions, mockContext) - - assertTrue(sentryOptions.sessionsPath?.endsWith("${File.separator}cache${File.separator}sentry${File.separator}sessions")!!) - } - @Test fun `init should set context package name as appInclude`() { val sentryOptions = SentryAndroidOptions() @@ -271,12 +261,12 @@ class AndroidOptionsInitializerTest { } @Test - fun `SendCachedEventFireAndForgetIntegration added to integration list`() { + fun `SendCachedEnvelopeFireAndForgetIntegration added to integration list`() { val sentryOptions = SentryAndroidOptions() val mockContext = createMockContext() AndroidOptionsInitializer.init(sentryOptions, mockContext) - val actual = sentryOptions.integrations.firstOrNull { it is SendCachedEventFireAndForgetIntegration } + val actual = sentryOptions.integrations.firstOrNull { it is SendCachedEnvelopeFireAndForgetIntegration } assertNotNull(actual) } diff --git a/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java b/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java index e7c2cf483..6d51298e5 100644 --- a/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java +++ b/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java @@ -1,22 +1,19 @@ package io.sentry.core; import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.cache.IEventCache; import io.sentry.core.transport.AsyncConnection; final class AsyncConnectionFactory { private AsyncConnectionFactory() {} - public static AsyncConnection create( - SentryOptions options, IEventCache eventCache, IEnvelopeCache sessionCache) { + public static AsyncConnection create(SentryOptions options, IEnvelopeCache envelopeCache) { // the connection doesn't do any retries of failed sends and can hold at most the same number // of pending events as there are being cached. The rest is dropped. return new AsyncConnection( options.getTransport(), options.getTransportGate(), - eventCache, - sessionCache, + envelopeCache, options.getMaxQueueSize(), options); } diff --git a/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java b/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java index 578d1aef9..b5edc27c7 100644 --- a/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java +++ b/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java @@ -22,7 +22,7 @@ abstract class DirectoryProcessor { this.flushTimeoutMillis = flushTimeoutMillis; } - public void processDirectory(@NotNull File directory) { + public void processDirectory(final @NotNull File directory) { try { logger.log(SentryLevel.DEBUG, "Processing dir. %s", directory.getAbsolutePath()); @@ -39,13 +39,13 @@ public void processDirectory(@NotNull File directory) { return; } - File[] listFiles = directory.listFiles(); + final File[] listFiles = directory.listFiles(); if (listFiles == null) { logger.log(SentryLevel.ERROR, "Cache dir %s is null.", directory.getAbsolutePath()); return; } - File[] filteredListFiles = directory.listFiles((d, name) -> isRelevantFileName(name)); + final File[] filteredListFiles = directory.listFiles((d, name) -> isRelevantFileName(name)); logger.log( SentryLevel.DEBUG, @@ -62,7 +62,7 @@ public void processDirectory(@NotNull File directory) { logger.log(SentryLevel.DEBUG, "Processing file: %s", file.getAbsolutePath()); - final SendCachedEventHint hint = new SendCachedEventHint(flushTimeoutMillis, logger); + final SendCachedEnvelopeHint hint = new SendCachedEnvelopeHint(flushTimeoutMillis, logger); processFile(file, hint); } } catch (Exception e) { @@ -70,11 +70,11 @@ public void processDirectory(@NotNull File directory) { } } - protected abstract void processFile(File file, @Nullable Object hint); + protected abstract void processFile(final @NotNull File file, final @Nullable Object hint); protected abstract boolean isRelevantFileName(String fileName); - private static final class SendCachedEventHint + private static final class SendCachedEnvelopeHint implements Cached, Retryable, SubmissionResult, Flushable { boolean retry = false; boolean succeeded = false; @@ -83,7 +83,7 @@ private static final class SendCachedEventHint private final long flushTimeoutMillis; private final @NotNull ILogger logger; - public SendCachedEventHint(final long flushTimeoutMillis, final @NotNull ILogger logger) { + public SendCachedEnvelopeHint(final long flushTimeoutMillis, final @NotNull ILogger logger) { this.flushTimeoutMillis = flushTimeoutMillis; this.latch = new CountDownLatch(1); this.logger = logger; diff --git a/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java b/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java index 676301e95..2c10965ce 100644 --- a/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java +++ b/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java @@ -1,24 +1,16 @@ package io.sentry.core; -import static io.sentry.core.SentryLevel.ERROR; -import static io.sentry.core.cache.SessionCache.PREFIX_CURRENT_SESSION_FILE; - +import io.sentry.core.cache.EnvelopeCache; import io.sentry.core.hints.Flushable; import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SubmissionResult; -import io.sentry.core.util.CollectionUtils; import io.sentry.core.util.LogUtils; import io.sentry.core.util.Objects; import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,59 +18,77 @@ @ApiStatus.Internal public final class EnvelopeSender extends DirectoryProcessor implements IEnvelopeSender { - @SuppressWarnings("CharsetObjectCanBeUsed") - private static final Charset UTF_8 = Charset.forName("UTF-8"); - private final @NotNull IHub hub; - private final @NotNull IEnvelopeReader envelopeReader; private final @NotNull ISerializer serializer; private final @NotNull ILogger logger; public EnvelopeSender( final @NotNull IHub hub, - final @NotNull IEnvelopeReader envelopeReader, final @NotNull ISerializer serializer, final @NotNull ILogger logger, final long flushTimeoutMillis) { super(logger, flushTimeoutMillis); this.hub = Objects.requireNonNull(hub, "Hub is required."); - this.envelopeReader = Objects.requireNonNull(envelopeReader, "Envelope reader is required."); this.serializer = Objects.requireNonNull(serializer, "Serializer is required."); this.logger = Objects.requireNonNull(logger, "Logger is required."); } @Override - protected void processFile(final @NotNull File file, @Nullable Object hint) { - Objects.requireNonNull(file, "File is required."); + protected void processFile(@NotNull File file, @Nullable Object hint) { + if (!file.isFile()) { + logger.log(SentryLevel.DEBUG, "'%s' is not a file.", file.getAbsolutePath()); + return; + } if (!isRelevantFileName(file.getName())) { - logger.log(SentryLevel.DEBUG, "File '%s' should be ignored.", file.getAbsolutePath()); + logger.log( + SentryLevel.DEBUG, "File '%s' doesn't match extension expected.", file.getAbsolutePath()); return; } - try (final InputStream stream = new BufferedInputStream(new FileInputStream(file))) { - final SentryEnvelope envelope = envelopeReader.read(stream); - if (envelope == null) { - logger.log( - SentryLevel.ERROR, - "Stream from path %s resulted in a null envelope.", - file.getAbsolutePath()); + if (!file.getParentFile().canWrite()) { + logger.log( + SentryLevel.WARNING, + "File '%s' cannot be deleted so it will not be processed.", + file.getAbsolutePath()); + return; + } + + try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) { + SentryEnvelope envelope = serializer.deserializeEnvelope(is); + hub.captureEnvelope(envelope, hint); + + if (hint instanceof Flushable) { + if (!((Flushable) hint).waitFlush()) { + logger.log(SentryLevel.WARNING, "Timed out waiting for envelope submission."); + } } else { - processEnvelope(envelope, hint); - logger.log(SentryLevel.DEBUG, "File '%s' is done.", file.getAbsolutePath()); + LogUtils.logIfNotFlushable(logger, hint); } + } catch (FileNotFoundException e) { + logger.log(SentryLevel.ERROR, e, "File '%s' cannot be found.", file.getAbsolutePath()); } catch (IOException e) { - logger.log(SentryLevel.ERROR, "Error processing envelope.", e); + logger.log(SentryLevel.ERROR, e, "I/O on file '%s' failed.", file.getAbsolutePath()); + } catch (Exception e) { + logger.log( + SentryLevel.ERROR, e, "Failed to capture cached envelope %s", file.getAbsolutePath()); + if (hint instanceof Retryable) { + ((Retryable) hint).setRetry(false); + logger.log(SentryLevel.INFO, e, "File '%s' won't retry.", file.getAbsolutePath()); + } else { + LogUtils.logIfNotRetryable(logger, hint); + } } finally { + // Unless the transport marked this to be retried, it'll be deleted. if (hint instanceof Retryable) { if (!((Retryable) hint).isRetry()) { - try { - if (!file.delete()) { - logger.log(SentryLevel.ERROR, "Failed to delete: %s", file.getAbsolutePath()); - } - } catch (RuntimeException e) { - logger.log(SentryLevel.ERROR, e, "Failed to delete: %s", file.getAbsolutePath()); - } + safeDelete(file, "after trying to capture it"); + logger.log(SentryLevel.DEBUG, "Deleted file %s.", file.getAbsolutePath()); + } else { + logger.log( + SentryLevel.INFO, + "File not deleted since retry was marked. %s.", + file.getAbsolutePath()); } } else { LogUtils.logIfNotRetryable(logger, hint); @@ -87,10 +97,8 @@ protected void processFile(final @NotNull File file, @Nullable Object hint) { } @Override - protected boolean isRelevantFileName(final @Nullable String fileName) { - // ignore current.envelope - return fileName != null && !fileName.startsWith(PREFIX_CURRENT_SESSION_FILE); - // TODO: Use an extension to filter out relevant files + protected boolean isRelevantFileName(String fileName) { + return fileName.endsWith(EnvelopeCache.SUFFIX_ENVELOPE_FILE); } @Override @@ -100,124 +108,22 @@ public void processEnvelopeFile(@NotNull String path, @Nullable Object hint) { processFile(new File(path), hint); } - private void processEnvelope(final @NotNull SentryEnvelope envelope, final @Nullable Object hint) - throws IOException { - logger.log( - SentryLevel.DEBUG, - "Processing Envelope with %d item(s)", - CollectionUtils.size(envelope.getItems())); - int items = 0; - for (final SentryEnvelopeItem item : envelope.getItems()) { - items++; - - if (item.getHeader() == null) { - logger.log(SentryLevel.ERROR, "Item %d has no header", items); - continue; - } - if (SentryItemType.Event.equals(item.getHeader().getType())) { - try (final Reader eventReader = - new BufferedReader( - new InputStreamReader(new ByteArrayInputStream(item.getData()), UTF_8))) { - SentryEvent event = serializer.deserializeEvent(eventReader); - if (event == null) { - logger.log( - SentryLevel.ERROR, - "Item %d of type %s returned null by the parser.", - items, - item.getHeader().getType()); - } else { - if (envelope.getHeader().getEventId() != null - && !envelope.getHeader().getEventId().equals(event.getEventId())) { - logger.log( - SentryLevel.ERROR, - "Item %d of has a different event id (%s) to the envelope header (%s)", - items, - envelope.getHeader().getEventId(), - event.getEventId()); - continue; - } - hub.captureEvent(event, hint); - logger.log(SentryLevel.DEBUG, "Item %d is being captured.", items); - if (hint instanceof Flushable) { - if (!((Flushable) hint).waitFlush()) { - logger.log( - SentryLevel.WARNING, - "Timed out waiting for event submission: %s", - event.getEventId()); - - // TODO: find out about the time out - // if (hint instanceof Retryable) { - // ((Retryable) hint).setRetry(true); - // } - - break; - } - } else { - LogUtils.logIfNotFlushable(logger, hint); - } - } - } catch (Exception e) { - logger.log(ERROR, "Item failed to process.", e); - } - } else if (SentryItemType.Session.equals(item.getHeader().getType())) { - try (final Reader reader = - new BufferedReader( - new InputStreamReader(new ByteArrayInputStream(item.getData()), UTF_8))) { - final Session session = serializer.deserializeSession(reader); - if (session == null) { - logger.log( - SentryLevel.ERROR, - "Item %d of type %s returned null by the parser.", - items, - item.getHeader().getType()); - } else { - // TODO: Bundle all session in a single envelope - hub.captureEnvelope( - SentryEnvelope.fromSession( - serializer, session, envelope.getHeader().getSdkVersion()), - hint); - logger.log(SentryLevel.DEBUG, "Item %d is being captured.", items); - - if (hint instanceof Flushable) { - logger.log(SentryLevel.DEBUG, "Going to wait flush %d item.", items); - if (!((Flushable) hint).waitFlush()) { - logger.log( - SentryLevel.WARNING, - "Timed out waiting for item submission: %s", - session.getSessionId()); - - // TODO: find out about the time out - // if (hint instanceof Retryable) { - // ((Retryable) hint).setRetry(true); - // } - - break; - } - logger.log(SentryLevel.DEBUG, "Flushed %d item.", items); - } else { - LogUtils.logIfNotFlushable(logger, hint); - } - } - } catch (Exception e) { - logger.log(ERROR, "Item failed to process.", e); - } - } else { - // TODO: Handle attachments and other types + private void safeDelete(File file, String errorMessageSuffix) { + try { + if (!file.delete()) { logger.log( - SentryLevel.WARNING, "Item %d of type: %s ignored.", items, item.getHeader().getType()); - } - - if (hint instanceof SubmissionResult) { - if (!((SubmissionResult) hint).isSuccess()) { - // Failed to send an item of the envelope: Stop attempting to send the rest (an attachment - // without the event that created it isn't useful) - logger.log( - SentryLevel.WARNING, - "Envelope had a failed capture at item %d. No more items will be sent.", - items); - break; - } + SentryLevel.ERROR, + "Failed to delete '%s' %s", + file.getAbsolutePath(), + errorMessageSuffix); } + } catch (Exception e) { + logger.log( + SentryLevel.ERROR, + e, + "Failed to delete '%s' %s", + file.getAbsolutePath(), + errorMessageSuffix); } } } diff --git a/sentry-core/src/main/java/io/sentry/core/OutboxSender.java b/sentry-core/src/main/java/io/sentry/core/OutboxSender.java new file mode 100644 index 000000000..3d466e409 --- /dev/null +++ b/sentry-core/src/main/java/io/sentry/core/OutboxSender.java @@ -0,0 +1,176 @@ +package io.sentry.core; + +import static io.sentry.core.SentryLevel.ERROR; +import static io.sentry.core.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE; + +import io.sentry.core.hints.Flushable; +import io.sentry.core.hints.Retryable; +import io.sentry.core.hints.SubmissionResult; +import io.sentry.core.util.CollectionUtils; +import io.sentry.core.util.LogUtils; +import io.sentry.core.util.Objects; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class OutboxSender extends DirectoryProcessor implements IEnvelopeSender { + + @SuppressWarnings("CharsetObjectCanBeUsed") + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + private final @NotNull IHub hub; + private final @NotNull IEnvelopeReader envelopeReader; + private final @NotNull ISerializer serializer; + private final @NotNull ILogger logger; + + public OutboxSender( + final @NotNull IHub hub, + final @NotNull IEnvelopeReader envelopeReader, + final @NotNull ISerializer serializer, + final @NotNull ILogger logger, + final long flushTimeoutMillis) { + super(logger, flushTimeoutMillis); + this.hub = Objects.requireNonNull(hub, "Hub is required."); + this.envelopeReader = Objects.requireNonNull(envelopeReader, "Envelope reader is required."); + this.serializer = Objects.requireNonNull(serializer, "Serializer is required."); + this.logger = Objects.requireNonNull(logger, "Logger is required."); + } + + @Override + protected void processFile(final @NotNull File file, @Nullable Object hint) { + Objects.requireNonNull(file, "File is required."); + + if (!isRelevantFileName(file.getName())) { + logger.log(SentryLevel.DEBUG, "File '%s' should be ignored.", file.getAbsolutePath()); + return; + } + + try (final InputStream stream = new BufferedInputStream(new FileInputStream(file))) { + final SentryEnvelope envelope = envelopeReader.read(stream); + if (envelope == null) { + logger.log( + SentryLevel.ERROR, + "Stream from path %s resulted in a null envelope.", + file.getAbsolutePath()); + } else { + processEnvelope(envelope, hint); + logger.log(SentryLevel.DEBUG, "File '%s' is done.", file.getAbsolutePath()); + } + } catch (IOException e) { + logger.log(SentryLevel.ERROR, "Error processing envelope.", e); + } finally { + if (hint instanceof Retryable) { + if (!((Retryable) hint).isRetry()) { + try { + if (!file.delete()) { + logger.log(SentryLevel.ERROR, "Failed to delete: %s", file.getAbsolutePath()); + } + } catch (RuntimeException e) { + logger.log(SentryLevel.ERROR, e, "Failed to delete: %s", file.getAbsolutePath()); + } + } + } else { + LogUtils.logIfNotRetryable(logger, hint); + } + } + } + + @Override + protected boolean isRelevantFileName(final @Nullable String fileName) { + // ignore current.envelope + return fileName != null && !fileName.startsWith(PREFIX_CURRENT_SESSION_FILE); + // TODO: Use an extension to filter out relevant files + } + + @Override + public void processEnvelopeFile(@NotNull String path, @Nullable Object hint) { + Objects.requireNonNull(path, "Path is required."); + + processFile(new File(path), hint); + } + + private void processEnvelope(final @NotNull SentryEnvelope envelope, final @Nullable Object hint) + throws IOException { + logger.log( + SentryLevel.DEBUG, + "Processing Envelope with %d item(s)", + CollectionUtils.size(envelope.getItems())); + int items = 0; + for (final SentryEnvelopeItem item : envelope.getItems()) { + items++; + + if (item.getHeader() == null) { + logger.log(SentryLevel.ERROR, "Item %d has no header", items); + continue; + } + if (SentryItemType.Event.equals(item.getHeader().getType())) { + try (final Reader eventReader = + new BufferedReader( + new InputStreamReader(new ByteArrayInputStream(item.getData()), UTF_8))) { + SentryEvent event = serializer.deserializeEvent(eventReader); + if (event == null) { + logger.log( + SentryLevel.ERROR, + "Item %d of type %s returned null by the parser.", + items, + item.getHeader().getType()); + } else { + if (envelope.getHeader().getEventId() != null + && !envelope.getHeader().getEventId().equals(event.getEventId())) { + logger.log( + SentryLevel.ERROR, + "Item %d of has a different event id (%s) to the envelope header (%s)", + items, + envelope.getHeader().getEventId(), + event.getEventId()); + continue; + } + hub.captureEvent(event, hint); + logger.log(SentryLevel.DEBUG, "Item %d is being captured.", items); + if (hint instanceof Flushable) { + if (!((Flushable) hint).waitFlush()) { + logger.log( + SentryLevel.WARNING, + "Timed out waiting for event submission: %s", + event.getEventId()); + + break; + } + } else { + LogUtils.logIfNotFlushable(logger, hint); + } + } + } catch (Exception e) { + logger.log(ERROR, "Item failed to process.", e); + } + } else { + // TODO: Handle attachments and other types + logger.log( + SentryLevel.WARNING, "Item %d of type: %s ignored.", items, item.getHeader().getType()); + } + + if (hint instanceof SubmissionResult) { + if (!((SubmissionResult) hint).isSuccess()) { + // Failed to send an item of the envelope: Stop attempting to send the rest (an attachment + // without the event that created it isn't useful) + logger.log( + SentryLevel.WARNING, + "Envelope had a failed capture at item %d. No more items will be sent.", + items); + break; + } + } + } + } +} diff --git a/sentry-core/src/main/java/io/sentry/core/Scope.java b/sentry-core/src/main/java/io/sentry/core/Scope.java index 8860de7f1..ec54ab860 100644 --- a/sentry-core/src/main/java/io/sentry/core/Scope.java +++ b/sentry-core/src/main/java/io/sentry/core/Scope.java @@ -392,11 +392,19 @@ public void addEventProcessor(@NotNull EventProcessor eventProcessor) { * Callback to do atomic operations on session * * @param sessionCallback the IWithSession callback + * @return a clone of the Session after executing the callback and mutating the session */ - void withSession(@NotNull IWithSession sessionCallback) { + @Nullable + Session withSession(@NotNull IWithSession sessionCallback) { + Session cloneSession = null; synchronized (sessionLock) { sessionCallback.accept(session); + + if (session != null) { + cloneSession = session.clone(); + } } + return cloneSession; } /** the IWithSession callback */ diff --git a/sentry-core/src/main/java/io/sentry/core/SendCachedEventFireAndForgetIntegration.java b/sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/SendCachedEventFireAndForgetIntegration.java rename to sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java index 9dabe1bad..8200be48d 100644 --- a/sentry-core/src/main/java/io/sentry/core/SendCachedEventFireAndForgetIntegration.java +++ b/sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; /** Sends cached events over when your App. is starting. */ -public final class SendCachedEventFireAndForgetIntegration implements Integration { +public final class SendCachedEnvelopeFireAndForgetIntegration implements Integration { private final SendFireAndForgetFactory factory; @@ -46,7 +46,8 @@ default boolean hasValidPath(final @Nullable String dirPath, final @NotNull ILog } } - public SendCachedEventFireAndForgetIntegration(final @NotNull SendFireAndForgetFactory factory) { + public SendCachedEnvelopeFireAndForgetIntegration( + final @NotNull SendFireAndForgetFactory factory) { this.factory = Objects.requireNonNull(factory, "SendFireAndForgetFactory is required"); } diff --git a/sentry-core/src/main/java/io/sentry/core/SendCachedEvent.java b/sentry-core/src/main/java/io/sentry/core/SendCachedEvent.java deleted file mode 100644 index 13f8480d4..000000000 --- a/sentry-core/src/main/java/io/sentry/core/SendCachedEvent.java +++ /dev/null @@ -1,130 +0,0 @@ -package io.sentry.core; - -import io.sentry.core.cache.DiskCache; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.Retryable; -import io.sentry.core.util.LogUtils; -import io.sentry.core.util.Objects; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -final class SendCachedEvent extends DirectoryProcessor { - private static final Charset UTF_8 = Charset.forName("UTF-8"); - private final ISerializer serializer; - private final IHub hub; - private final @NotNull ILogger logger; - - SendCachedEvent( - @NotNull ISerializer serializer, - @NotNull IHub hub, - final @NotNull ILogger logger, - final long flushTimeoutMillis) { - super(logger, flushTimeoutMillis); - this.serializer = Objects.requireNonNull(serializer, "Serializer is required."); - this.hub = Objects.requireNonNull(hub, "Hub is required."); - this.logger = Objects.requireNonNull(logger, "Logger is required."); - } - - @Override - protected void processFile(@NotNull File file, @Nullable Object hint) { - if (!file.isFile()) { - logger.log(SentryLevel.DEBUG, "'%s' is not a file.", file.getAbsolutePath()); - return; - } - - if (!isRelevantFileName(file.getName())) { - logger.log( - SentryLevel.DEBUG, "File '%s' doesn't match extension expected.", file.getAbsolutePath()); - return; - } - - if (!file.getParentFile().canWrite()) { - logger.log( - SentryLevel.WARNING, - "File '%s' cannot be delete so it will not be processed.", - file.getAbsolutePath()); - return; - } - - try (final Reader reader = - new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF_8))) { - SentryEvent event = serializer.deserializeEvent(reader); - hub.captureEvent(event, hint); - - if (hint instanceof Flushable) { - if (!((Flushable) hint).waitFlush()) { - logger.log( - SentryLevel.WARNING, - "Timed out waiting for event submission: %s", - event.getEventId()); - - // TODO: find out about the time out - // if (hint instanceof Retryable) { - // ((Retryable) hint).setRetry(true); - // } - } - } else { - LogUtils.logIfNotFlushable(logger, hint); - } - } catch (FileNotFoundException e) { - logger.log(SentryLevel.ERROR, e, "File '%s' cannot be found.", file.getAbsolutePath()); - } catch (IOException e) { - logger.log(SentryLevel.ERROR, e, "I/O on file '%s' failed.", file.getAbsolutePath()); - } catch (Exception e) { - logger.log(SentryLevel.ERROR, e, "Failed to capture cached event %s", file.getAbsolutePath()); - if (hint instanceof Retryable) { - ((Retryable) hint).setRetry(false); - logger.log(SentryLevel.INFO, e, "File '%s' won't retry.", file.getAbsolutePath()); - } else { - LogUtils.logIfNotRetryable(logger, hint); - } - } finally { - // Unless the transport marked this to be retried, it'll be deleted. - if (hint instanceof Retryable) { - if (!((Retryable) hint).isRetry()) { - safeDelete(file, "after trying to capture it"); - logger.log(SentryLevel.DEBUG, "Deleted file %s.", file.getAbsolutePath()); - } else { - logger.log( - SentryLevel.INFO, - "File not deleted since retry was marked. %s.", - file.getAbsolutePath()); - } - } else { - LogUtils.logIfNotRetryable(logger, hint); - } - } - } - - @Override - protected boolean isRelevantFileName(String fileName) { - return fileName.endsWith(DiskCache.FILE_SUFFIX); - } - - private void safeDelete(File file, String errorMessageSuffix) { - try { - if (!file.delete()) { - logger.log( - SentryLevel.ERROR, - "Failed to delete '%s' %s", - file.getAbsolutePath(), - errorMessageSuffix); - } - } catch (Exception e) { - logger.log( - SentryLevel.ERROR, - e, - "Failed to delete '%s' %s", - file.getAbsolutePath(), - errorMessageSuffix); - } - } -} diff --git a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java b/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java index 2f05ad305..172fe51f2 100644 --- a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java +++ b/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java @@ -7,20 +7,20 @@ @ApiStatus.Internal public final class SendFireAndForgetEnvelopeSender - implements SendCachedEventFireAndForgetIntegration.SendFireAndForgetFactory { + implements SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetFactory { - private final @NotNull SendCachedEventFireAndForgetIntegration.SendFireAndForgetDirPath + private final @NotNull SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetDirPath sendFireAndForgetDirPath; public SendFireAndForgetEnvelopeSender( - final @NotNull SendCachedEventFireAndForgetIntegration.SendFireAndForgetDirPath + final @NotNull SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetDirPath sendFireAndForgetDirPath) { this.sendFireAndForgetDirPath = Objects.requireNonNull(sendFireAndForgetDirPath, "SendFireAndForgetDirPath is required"); } @Override - public @Nullable SendCachedEventFireAndForgetIntegration.SendFireAndForget create( + public @Nullable SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget create( final @NotNull IHub hub, final @NotNull SentryOptions options) { Objects.requireNonNull(hub, "Hub is required"); Objects.requireNonNull(options, "SentryOptions is required"); @@ -33,11 +33,7 @@ public SendFireAndForgetEnvelopeSender( final EnvelopeSender envelopeSender = new EnvelopeSender( - hub, - options.getEnvelopeReader(), - options.getSerializer(), - options.getLogger(), - options.getFlushTimeoutMillis()); + hub, options.getSerializer(), options.getLogger(), options.getFlushTimeoutMillis()); return processDir(envelopeSender, dirPath, options.getLogger()); } diff --git a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEventSender.java b/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEventSender.java deleted file mode 100644 index 8bdfc314c..000000000 --- a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEventSender.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.sentry.core; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -public final class SendFireAndForgetEventSender - implements SendCachedEventFireAndForgetIntegration.SendFireAndForgetFactory { - - private final @NotNull SendCachedEventFireAndForgetIntegration.SendFireAndForgetDirPath - sendFireAndForgetDirPath; - - public SendFireAndForgetEventSender( - final @NotNull SendCachedEventFireAndForgetIntegration.SendFireAndForgetDirPath - sendFireAndForgetDirPath) { - this.sendFireAndForgetDirPath = sendFireAndForgetDirPath; - } - - @Override - public SendCachedEventFireAndForgetIntegration.SendFireAndForget create( - final @NotNull IHub hub, final @NotNull SentryOptions options) { - final String dirPath = sendFireAndForgetDirPath.getDirPath(); - if (!hasValidPath(dirPath, options.getLogger())) { - options.getLogger().log(SentryLevel.ERROR, "No cache dir path is defined in options."); - return null; - } - - final SendCachedEvent sender = - new SendCachedEvent( - options.getSerializer(), hub, options.getLogger(), options.getFlushTimeoutMillis()); - - return processDir(sender, dirPath, options.getLogger()); - } -} diff --git a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java b/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java new file mode 100644 index 000000000..a56b1a7da --- /dev/null +++ b/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java @@ -0,0 +1,44 @@ +package io.sentry.core; + +import io.sentry.core.util.Objects; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class SendFireAndForgetOutboxSender + implements SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetFactory { + + private final @NotNull SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetDirPath + sendFireAndForgetDirPath; + + public SendFireAndForgetOutboxSender( + final @NotNull SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetDirPath + sendFireAndForgetDirPath) { + this.sendFireAndForgetDirPath = + Objects.requireNonNull(sendFireAndForgetDirPath, "SendFireAndForgetDirPath is required"); + } + + @Override + public @Nullable SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget create( + final @NotNull IHub hub, final @NotNull SentryOptions options) { + Objects.requireNonNull(hub, "Hub is required"); + Objects.requireNonNull(options, "SentryOptions is required"); + + final String dirPath = sendFireAndForgetDirPath.getDirPath(); + if (!hasValidPath(dirPath, options.getLogger())) { + options.getLogger().log(SentryLevel.ERROR, "No outbox dir path is defined in options."); + return null; + } + + final OutboxSender outboxSender = + new OutboxSender( + hub, + options.getEnvelopeReader(), + options.getSerializer(), + options.getLogger(), + options.getFlushTimeoutMillis()); + + return processDir(outboxSender, dirPath, options.getLogger()); + } +} diff --git a/sentry-core/src/main/java/io/sentry/core/Sentry.java b/sentry-core/src/main/java/io/sentry/core/Sentry.java index 90adbb4c0..6404668cd 100644 --- a/sentry-core/src/main/java/io/sentry/core/Sentry.java +++ b/sentry-core/src/main/java/io/sentry/core/Sentry.java @@ -1,7 +1,6 @@ package io.sentry.core; -import io.sentry.core.cache.DiskCache; -import io.sentry.core.cache.SessionCache; +import io.sentry.core.cache.EnvelopeCache; import io.sentry.core.protocol.SentryId; import io.sentry.core.protocol.User; import java.io.File; @@ -197,11 +196,7 @@ private static boolean initConfigurations(final @NotNull SentryOptions options) final File outboxDir = new File(options.getOutboxPath()); outboxDir.mkdirs(); - final File sessionsDir = new File(options.getSessionsPath()); - sessionsDir.mkdirs(); - - options.setEventDiskCache(new DiskCache(options)); - options.setEnvelopeDiskCache(new SessionCache(options)); + options.setEnvelopeDiskCache(new EnvelopeCache(options)); } else { logger.log(SentryLevel.INFO, "No outbox dir path is defined in options."); } diff --git a/sentry-core/src/main/java/io/sentry/core/SentryClient.java b/sentry-core/src/main/java/io/sentry/core/SentryClient.java index e65aac25b..7b5086226 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryClient.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryClient.java @@ -1,8 +1,6 @@ package io.sentry.core; import io.sentry.core.hints.DiskFlushNotification; -import io.sentry.core.hints.SessionEndHint; -import io.sentry.core.hints.SessionUpdateHint; import io.sentry.core.protocol.SentryId; import io.sentry.core.transport.Connection; import io.sentry.core.transport.ITransport; @@ -12,6 +10,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; import org.jetbrains.annotations.ApiStatus; @@ -48,9 +47,7 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c } if (connection == null) { - connection = - AsyncConnectionFactory.create( - options, options.getEventDiskCache(), options.getEnvelopeDiskCache()); + connection = AsyncConnectionFactory.create(options, options.getEnvelopeDiskCache()); } this.connection = connection; random = options.getSampleRate() == null ? null : new Random(); @@ -70,7 +67,7 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c event = applyScope(event, scope, hint); if (event == null) { - return SentryId.EMPTY_ID; + options.getLogger().log(SentryLevel.DEBUG, "Event was dropped by applyScope"); } } else { options @@ -92,39 +89,79 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c } } - if (event == null) { - return SentryId.EMPTY_ID; + Session session = null; + + if (event != null) { + session = updateSessionData(event, hint, scope); + + if (!sample()) { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Event %s was dropped due to sampling decision.", + event.getEventId()); + // setting event as null to not be sent as its been discarded by sample rate + event = null; + } } - // TODO: should it be done on the HUB? - updateSessionData(event, hint, scope); + if (event != null) { + event = executeBeforeSend(event, hint); - if (!sample()) { - options - .getLogger() - .log( - SentryLevel.DEBUG, - "Event %s was dropped due to sampling decision.", - event.getEventId()); - return SentryId.EMPTY_ID; + if (event == null) { + options.getLogger().log(SentryLevel.DEBUG, "Event was dropped by beforeSend"); + } } - event = executeBeforeSend(event, hint); + SentryId sentryId = SentryId.EMPTY_ID; - if (event == null) { - options.getLogger().log(SentryLevel.DEBUG, "Event was dropped by beforeSend"); - return SentryId.EMPTY_ID; + if (event != null) { + sentryId = event.getEventId(); } try { - connection.send(event, hint); + final SentryEnvelope envelope = buildEnvelope(event, session); + + if (envelope != null) { + connection.send(envelope, hint); + } } catch (IOException e) { - options - .getLogger() - .log(SentryLevel.WARNING, "Capturing event " + event.getEventId() + " failed.", e); + options.getLogger().log(SentryLevel.WARNING, e, "Capturing event %s failed.", sentryId); + + // if there was an error capturing the event, we return an emptyId + sentryId = SentryId.EMPTY_ID; } - return event.getEventId(); + return sentryId; + } + + private @Nullable SentryEnvelope buildEnvelope( + final @Nullable SentryEvent event, final @Nullable Session session) throws IOException { + SentryId sentryId = null; + + final List envelopeItems = new ArrayList<>(); + + if (event != null) { + final SentryEnvelopeItem eventItem = + SentryEnvelopeItem.fromEvent(options.getSerializer(), event); + envelopeItems.add(eventItem); + sentryId = event.getEventId(); + } + + if (session != null) { + final SentryEnvelopeItem sessionItem = + SentryEnvelopeItem.fromSession(options.getSerializer(), session); + envelopeItems.add(sessionItem); + } + + if (!envelopeItems.isEmpty()) { + final SentryEnvelopeHeader envelopeHeader = + new SentryEnvelopeHeader(sentryId, options.getSdkVersion()); + return new SentryEnvelope(envelopeHeader, envelopeItems); + } + + return null; } /** @@ -135,53 +172,52 @@ public SentryClient(final @NotNull SentryOptions options, @Nullable Connection c * @param scope the Scope or null */ @TestOnly - void updateSessionData( + @Nullable + Session updateSessionData( final @NotNull SentryEvent event, final @Nullable Object hint, final @Nullable Scope scope) { + Session clonedSession = null; + if (ApplyScopeUtils.shouldApplyScopeData(hint)) { if (scope != null) { - scope.withSession( - session -> { - if (session != null) { - Session.State status = null; - if (event.isCrashed()) { - status = Session.State.Crashed; - } - - boolean crashedOrErrored = false; - if (Session.State.Crashed == status || event.isErrored()) { - crashedOrErrored = true; - } - - String userAgent = null; - if (event.getRequest() != null && event.getRequest().getHeaders() != null) { - if (event.getRequest().getHeaders().containsKey("user-agent")) { - userAgent = event.getRequest().getHeaders().get("user-agent"); - } - } - - if (session.update(status, userAgent, crashedOrErrored)) { - - Object sessionHint; - - // if hint is DiskFlushNotification, it means we have an uncaughtException - // and we can end the session. - if (hint instanceof DiskFlushNotification) { - sessionHint = new SessionEndHint(); - session.end(); + clonedSession = + scope.withSession( + session -> { + if (session != null) { + Session.State status = null; + if (event.isCrashed()) { + status = Session.State.Crashed; + } + + boolean crashedOrErrored = false; + if (Session.State.Crashed == status || event.isErrored()) { + crashedOrErrored = true; + } + + String userAgent = null; + if (event.getRequest() != null && event.getRequest().getHeaders() != null) { + if (event.getRequest().getHeaders().containsKey("user-agent")) { + userAgent = event.getRequest().getHeaders().get("user-agent"); + } + } + + if (session.update(status, userAgent, crashedOrErrored)) { + // if hint is DiskFlushNotification, it means we have an uncaughtException + // and we can end the session. + if (hint instanceof DiskFlushNotification) { + session.end(); + } + } } else { - // otherwise we just cache in the disk but do not flush to the network. - sessionHint = new SessionUpdateHint(); + options + .getLogger() + .log(SentryLevel.INFO, "Session is null on scope.withSession"); } - captureSession(session, sessionHint); - } - } else { - options.getLogger().log(SentryLevel.INFO, "Session is null on scope.withSession"); - } - }); + }); } else { options.getLogger().log(SentryLevel.INFO, "Scope is null on client.captureEvent"); } } + return clonedSession; } @ApiStatus.Internal diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java index f3310859e..01e3b819e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java @@ -2,12 +2,10 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.cache.IEventCache; import io.sentry.core.protocol.SdkVersion; import io.sentry.core.transport.ITransport; import io.sentry.core.transport.ITransportGate; import io.sentry.core.transport.NoOpEnvelopeCache; -import io.sentry.core.transport.NoOpEventCache; import io.sentry.core.transport.NoOpTransport; import io.sentry.core.transport.NoOpTransportGate; import java.io.File; @@ -101,11 +99,8 @@ public class SentryOptions { /** The cache dir. size for capping the number of events Default is 10 */ private int cacheDirSize = 10; - /** The sessions dir. size for capping the number of envelopes Default is 100 */ - private int sessionsDirSize = 100; - /** Max. queue size before flushing events/envelopes to the disk */ - private int maxQueueSize = cacheDirSize + sessionsDirSize; + private int maxQueueSize = cacheDirSize; /** * This variable controls the total amount of breadcrumbs that should be captured Default is 100 @@ -201,9 +196,6 @@ public class SentryOptions { /** whether to ignore TLS errors */ private boolean bypassSecurity = false; - /** Reads and caches event json files in the disk */ - private @NotNull IEventCache eventDiskCache = NoOpEventCache.getInstance(); - /** Reads and caches envelope files in the disk */ private @NotNull IEnvelopeCache envelopeDiskCache = NoOpEnvelopeCache.getInstance(); @@ -456,18 +448,6 @@ public void setBeforeBreadcrumb(@Nullable BeforeBreadcrumbCallback beforeBreadcr return cacheDirPath + File.separator + "outbox"; } - /** - * Returns the sessions path if cacheDirPath is set - * - * @return the sessions path or null if not set - */ - public @Nullable String getSessionsPath() { - if (cacheDirPath == null || cacheDirPath.isEmpty()) { - return null; - } - return cacheDirPath + File.separator + "sessions"; - } - /** * Sets the cache dir. path * @@ -753,24 +733,6 @@ public void setServerName(@Nullable String serverName) { this.serverName = serverName; } - /** - * Returns the sessions dir size - * - * @return the dir size - */ - public int getSessionsDirSize() { - return sessionsDirSize; - } - - /** - * Sets the sessions dir size - * - * @param sessionsDirSize the sessions dir size - */ - public void setSessionsDirSize(int sessionsDirSize) { - this.sessionsDirSize = sessionsDirSize; - } - /** * Returns the session tracking interval in millis * @@ -920,24 +882,6 @@ public void setBypassSecurity(boolean bypassSecurity) { this.bypassSecurity = bypassSecurity; } - /** - * Returns the EventCache interface - * - * @return the EventCache object - */ - public @NotNull IEventCache getEventDiskCache() { - return eventDiskCache; - } - - /** - * Sets the EventCache interface - * - * @param eventDiskCache the EventCache object - */ - public void setEventDiskCache(final @Nullable IEventCache eventDiskCache) { - this.eventDiskCache = eventDiskCache != null ? eventDiskCache : NoOpEventCache.getInstance(); - } - /** * Returns the EnvelopeCache interface * diff --git a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java b/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java index dc6ca5822..10ea15646 100644 --- a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java +++ b/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java @@ -5,6 +5,7 @@ import io.sentry.core.exception.ExceptionMechanismException; import io.sentry.core.hints.DiskFlushNotification; import io.sentry.core.hints.Flushable; +import io.sentry.core.hints.SessionEnd; import io.sentry.core.protocol.Mechanism; import io.sentry.core.util.Objects; import java.io.Closeable; @@ -137,7 +138,8 @@ public void close() { } } - private static final class UncaughtExceptionHint implements DiskFlushNotification, Flushable { + private static final class UncaughtExceptionHint + implements DiskFlushNotification, Flushable, SessionEnd { private final CountDownLatch latch; private final long flushTimeoutMillis; diff --git a/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java b/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java deleted file mode 100644 index fd91f3085..000000000 --- a/sentry-core/src/main/java/io/sentry/core/cache/DiskCache.java +++ /dev/null @@ -1,130 +0,0 @@ -package io.sentry.core.cache; - -import static io.sentry.core.SentryLevel.DEBUG; -import static io.sentry.core.SentryLevel.ERROR; -import static io.sentry.core.SentryLevel.WARNING; -import static java.lang.String.format; - -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryOptions; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -/** - * A simple cache implementation storing the events to a disk, each event in a separater file in a - * configured directory. - */ -@ApiStatus.Internal -public final class DiskCache extends CacheStrategy implements IEventCache { - /** File suffix added to all serialized event files. */ - public static final String FILE_SUFFIX = ".sentry-event"; - - public DiskCache(final @NotNull SentryOptions options) { - super(options, options.getCacheDirPath(), options.getCacheDirSize()); - } - - @Override - public void store(final @NotNull SentryEvent event) { - rotateCacheIfNeeded(allEventFiles()); - - final File eventFile = getEventFile(event); - if (eventFile.exists()) { - options - .getLogger() - .log( - WARNING, - "Not adding Event to offline storage because it already exists: %s", - eventFile.getAbsolutePath()); - return; - } else { - options - .getLogger() - .log(DEBUG, "Adding Event to offline storage: %s", eventFile.getAbsolutePath()); - } - - try (final OutputStream outputStream = new FileOutputStream(eventFile); - final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) { - serializer.serialize(event, writer); - } catch (Exception e) { - options - .getLogger() - .log(ERROR, e, "Error writing Event to offline storage: %s", event.getEventId()); - } - } - - @Override - public void discard(final @NotNull SentryEvent event) { - final File eventFile = getEventFile(event); - if (eventFile.exists()) { - options - .getLogger() - .log(DEBUG, "Discarding event from cache: %s", eventFile.getAbsolutePath()); - - if (!eventFile.delete()) { - options.getLogger().log(ERROR, "Failed to delete Event: %s", eventFile.getAbsolutePath()); - } - } else { - options.getLogger().log(DEBUG, "Event was not cached: %s", eventFile.getAbsolutePath()); - } - } - - private @NotNull File getEventFile(final @NotNull SentryEvent event) { - return new File(directory.getAbsolutePath(), event.getEventId().toString() + FILE_SUFFIX); - } - - @Override - public @NotNull Iterator iterator() { - final File[] allCachedEvents = allEventFiles(); - - final List ret = new ArrayList<>(allCachedEvents.length); - - for (final File f : allCachedEvents) { - try (final Reader reader = - new BufferedReader(new InputStreamReader(new FileInputStream(f), UTF_8))) { - - ret.add(serializer.deserializeEvent(reader)); - } catch (FileNotFoundException e) { - options - .getLogger() - .log( - DEBUG, - "Event file '%s' disappeared while converting all cached files to events.", - f.getAbsolutePath()); - } catch (IOException e) { - options - .getLogger() - .log( - ERROR, - format("Error while reading cached event from file %s", f.getAbsolutePath()), - e); - } - } - - return ret.iterator(); - } - - private @NotNull File[] allEventFiles() { - if (isDirectoryValid()) { - final File[] files = directory.listFiles((__, fileName) -> fileName.endsWith(FILE_SUFFIX)); - if (files != null) { - return files; - } - } - return new File[] {}; - } -} diff --git a/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java b/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java rename to sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java index d7b25702f..b4a88db56 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/SessionCache.java +++ b/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java @@ -15,7 +15,6 @@ import io.sentry.core.Session; import io.sentry.core.hints.SessionEnd; import io.sentry.core.hints.SessionStart; -import io.sentry.core.hints.SessionUpdate; import io.sentry.core.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -44,10 +43,10 @@ import org.jetbrains.annotations.Nullable; @ApiStatus.Internal -public final class SessionCache extends CacheStrategy implements IEnvelopeCache { +public final class EnvelopeCache extends CacheStrategy implements IEnvelopeCache { /** File suffix added to all serialized envelopes files. */ - static final String SUFFIX_ENVELOPE_FILE = ".envelope"; + public static final String SUFFIX_ENVELOPE_FILE = ".envelope"; public static final String PREFIX_CURRENT_SESSION_FILE = "session"; static final String SUFFIX_CURRENT_SESSION_FILE = ".json"; @@ -55,8 +54,8 @@ public final class SessionCache extends CacheStrategy implements IEnvelopeCache private final @NotNull Map fileNameMap = new WeakHashMap<>(); - public SessionCache(final @NotNull SentryOptions options) { - super(options, options.getSessionsPath(), options.getSessionsDirSize()); + public EnvelopeCache(final @NotNull SentryOptions options) { + super(options, options.getCacheDirPath(), options.getCacheDirSize()); } @Override @@ -133,12 +132,7 @@ public void store(final @NotNull SentryEnvelope envelope, final @Nullable Object } updateCurrentSession(currentSessionFile, envelope); } - - if (hint instanceof SessionUpdate) { - updateCurrentSession(currentSessionFile, envelope); - return; - } - + // TODO: problem we need to update the current session file final File envelopeFile = getEnvelopeFile(envelope); if (envelopeFile.exists()) { options diff --git a/sentry-core/src/main/java/io/sentry/core/cache/IEventCache.java b/sentry-core/src/main/java/io/sentry/core/cache/IEventCache.java deleted file mode 100644 index 6a29ebe0a..000000000 --- a/sentry-core/src/main/java/io/sentry/core/cache/IEventCache.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.sentry.core.cache; - -import io.sentry.core.SentryEvent; - -/** - * Implementations of this interface are used as a kind of persistent storage for events that wait - * to be sent to the Sentry server. - * - *

Note that this interface doesn't handle the situation of resending the stored events after a - * crash. While that is surely one of the main usecases for the persistent storage of events, the - * re-initialization is out of scope of the event transport logic. - */ -public interface IEventCache extends Iterable { - - /** - * Stores the event so that it can be sent later. - * - * @param event the event to store - */ - void store(SentryEvent event); - - /** - * Discards the event from the storage. This means that the event has been successfully sent. Note - * that this MUST NOT fail on events that haven't been stored before (i.e. this method is called - * even for events that has been sent on the first attempt). - * - * @param event the event to discard from storage - */ - void discard(SentryEvent event); -} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdate.java b/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdate.java deleted file mode 100644 index 85d843ed1..000000000 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdate.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.sentry.core.hints; - -/** Hint that shows this is a session update envelope */ -public interface SessionUpdate {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdateHint.java b/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdateHint.java deleted file mode 100644 index fca36f278..000000000 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionUpdateHint.java +++ /dev/null @@ -1,3 +0,0 @@ -package io.sentry.core.hints; - -public final class SessionUpdateHint implements SessionUpdate {} diff --git a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java b/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java index a351597d8..5e7b484b9 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java @@ -3,16 +3,12 @@ import io.sentry.core.ILogger; import io.sentry.core.SentryEnvelope; import io.sentry.core.SentryEnvelopeItem; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryItemType; import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.cache.IEventCache; import io.sentry.core.hints.Cached; import io.sentry.core.hints.DiskFlushNotification; import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SessionUpdate; import io.sentry.core.hints.SubmissionResult; import io.sentry.core.util.LogUtils; import io.sentry.core.util.Objects; @@ -35,23 +31,20 @@ public final class AsyncConnection implements Closeable, Connection { private final @NotNull ITransport transport; private final @NotNull ITransportGate transportGate; private final @NotNull ExecutorService executor; - private final @NotNull IEventCache eventCache; - private final @NotNull IEnvelopeCache sessionCache; + private final @NotNull IEnvelopeCache envelopeCache; private final @NotNull SentryOptions options; public AsyncConnection( final ITransport transport, final ITransportGate transportGate, - final IEventCache eventCache, - final IEnvelopeCache sessionCache, + final IEnvelopeCache envelopeCache, final int maxQueueSize, final SentryOptions options) { this( transport, transportGate, - eventCache, - sessionCache, - initExecutor(maxQueueSize, eventCache, sessionCache, options.getLogger()), + envelopeCache, + initExecutor(maxQueueSize, envelopeCache, options.getLogger()), options); } @@ -59,44 +52,31 @@ public AsyncConnection( AsyncConnection( final @NotNull ITransport transport, final @NotNull ITransportGate transportGate, - final @NotNull IEventCache eventCache, - final @NotNull IEnvelopeCache sessionCache, + final @NotNull IEnvelopeCache envelopeCache, final @NotNull ExecutorService executorService, final @NotNull SentryOptions options) { this.transport = transport; this.transportGate = transportGate; - this.eventCache = eventCache; - this.sessionCache = sessionCache; + this.envelopeCache = envelopeCache; this.options = options; this.executor = executorService; } private static QueuedThreadPoolExecutor initExecutor( final int maxQueueSize, - final @NotNull IEventCache eventCache, - final @NotNull IEnvelopeCache sessionCache, + final @NotNull IEnvelopeCache envelopeCache, final @NotNull ILogger logger) { final RejectedExecutionHandler storeEvents = (r, executor) -> { - if (r instanceof EventSender) { - final EventSender eventSender = (EventSender) r; + if (r instanceof EnvelopeSender) { + final EnvelopeSender envelopeSender = (EnvelopeSender) r; - if (!(eventSender.hint instanceof Cached)) { - eventCache.store(eventSender.event); + if (!(envelopeSender.hint instanceof Cached)) { + envelopeCache.store(envelopeSender.envelope, envelopeSender.hint); } - markHintWhenSendingFailed(eventSender.hint, true); - logger.log(SentryLevel.WARNING, "Event rejected: %s", eventSender.event.getEventId()); - } - if (r instanceof SessionSender) { - final SessionSender sessionSender = (SessionSender) r; - - if (!(sessionSender.hint instanceof Cached)) { - sessionCache.store(sessionSender.envelope, sessionSender.hint); - } - - markHintWhenSendingFailed(sessionSender.hint, true); + markHintWhenSendingFailed(envelopeSender.hint, true); logger.log(SentryLevel.WARNING, "Envelope rejected"); } }; @@ -120,42 +100,12 @@ private static void markHintWhenSendingFailed(final @Nullable Object hint, final } } - /** - * Tries to send the event to the Sentry server. - * - * @param event the event to send - * @throws IOException on error - */ - @SuppressWarnings("FutureReturnValueIgnored") - @Override - public void send(final @NotNull SentryEvent event, final @Nullable Object hint) - throws IOException { - IEventCache currentEventCache = eventCache; - boolean cached = false; - if (hint instanceof Cached) { - currentEventCache = NoOpEventCache.getInstance(); - cached = true; - options.getLogger().log(SentryLevel.DEBUG, "Captured SentryEvent is already cached"); - } - - // no reason to continue - if (transport.isRetryAfter(SentryItemType.Event.getItemType())) { - if (cached) { - eventCache.discard(event); - } - markHintWhenSendingFailed(hint, false); - return; - } - - executor.submit(new EventSender(event, hint, currentEventCache)); - } - @SuppressWarnings("FutureReturnValueIgnored") @Override public void send(@NotNull SentryEnvelope envelope, final @Nullable Object hint) throws IOException { // For now no caching on envelopes - IEnvelopeCache currentEnvelopeCache = sessionCache; + IEnvelopeCache currentEnvelopeCache = envelopeCache; boolean cached = false; if (hint instanceof Cached) { currentEnvelopeCache = NoOpEnvelopeCache.getInstance(); @@ -192,7 +142,7 @@ public void send(@NotNull SentryEnvelope envelope, final @Nullable Object hint) // no reason to continue if (toSend.isEmpty()) { if (cached) { - sessionCache.discard(envelope); + envelopeCache.discard(envelope); } options.getLogger().log(SentryLevel.INFO, "Envelope discarded due all items rate limited."); @@ -203,7 +153,7 @@ public void send(@NotNull SentryEnvelope envelope, final @Nullable Object hint) envelope = new SentryEnvelope(envelope.getHeader(), toSend); } - executor.submit(new SessionSender(envelope, hint, currentEnvelopeCache)); + executor.submit(new EnvelopeSender(envelope, hint, currentEnvelopeCache)); } @Override @@ -240,103 +190,19 @@ private static final class AsyncConnectionThreadFactory implements ThreadFactory } } - private final class EventSender implements Runnable { - private final SentryEvent event; - private final Object hint; - private final IEventCache eventCache; - private final TransportResult failedResult = TransportResult.error(); - - EventSender( - final @NotNull SentryEvent event, - final @Nullable Object hint, - final @NotNull IEventCache eventCache) { - this.event = event; - this.hint = hint; - this.eventCache = eventCache; - } - - @Override - public void run() { - TransportResult result = this.failedResult; - try { - result = flush(); - } catch (Exception e) { - options - .getLogger() - .log(SentryLevel.ERROR, e, "Event submission failed: %s", event.getEventId()); - throw e; - } finally { - if (hint instanceof SubmissionResult) { - options - .getLogger() - .log(SentryLevel.DEBUG, "Marking event submission result: %s", result.isSuccess()); - ((SubmissionResult) hint).setResult(result.isSuccess()); - } - } - } - - private @NotNull TransportResult flush() { - TransportResult result = this.failedResult; - eventCache.store(event); - - if (hint instanceof DiskFlushNotification) { - ((DiskFlushNotification) hint).markFlushed(); - options - .getLogger() - .log(SentryLevel.DEBUG, "Disk flush event fired: %s", event.getEventId()); - } - - if (transportGate.isConnected()) { - try { - result = - transport.send( - SentryEnvelope.fromEvent( - options.getSerializer(), event, options.getSdkVersion())); - if (result.isSuccess()) { - eventCache.discard(event); - } else { - final String message = - "The transport failed to send the event with response code " - + result.getResponseCode(); - - options.getLogger().log(SentryLevel.ERROR, message); - - throw new IllegalStateException(message); - } - } catch (IOException e) { - // Failure due to IO is allowed to retry the event - if (hint instanceof Retryable) { - ((Retryable) hint).setRetry(true); - } else { - LogUtils.logIfNotRetryable(options.getLogger(), hint); - } - throw new IllegalStateException("Sending the event failed.", e); - } - } else { - // If transportGate is blocking from sending, allowed to retry - if (hint instanceof Retryable) { - ((Retryable) hint).setRetry(true); - } else { - LogUtils.logIfNotRetryable(options.getLogger(), hint); - } - } - return result; - } - } - - private final class SessionSender implements Runnable { + private final class EnvelopeSender implements Runnable { private final @NotNull SentryEnvelope envelope; private final @Nullable Object hint; - private final @NotNull IEnvelopeCache sessionCache; + private final @NotNull IEnvelopeCache envelopeCache; private final TransportResult failedResult = TransportResult.error(); - SessionSender( + EnvelopeSender( final @NotNull SentryEnvelope envelope, final @Nullable Object hint, - final @NotNull IEnvelopeCache sessionCache) { + final @NotNull IEnvelopeCache envelopeCache) { this.envelope = Objects.requireNonNull(envelope, "Envelope is required."); this.hint = hint; - this.sessionCache = Objects.requireNonNull(sessionCache, "SessionCache is required."); + this.envelopeCache = Objects.requireNonNull(envelopeCache, "EnvelopeCache is required."); } @Override @@ -361,21 +227,18 @@ public void run() { private @NotNull TransportResult flush() { TransportResult result = this.failedResult; - sessionCache.store(envelope, hint); + envelopeCache.store(envelope, hint); - // we only flush a session update to the disk, but not to the network - if (hint instanceof SessionUpdate) { - options - .getLogger() - .log(SentryLevel.DEBUG, "SessionUpdate event, leaving after event being cached."); - return TransportResult.success(); + if (hint instanceof DiskFlushNotification) { + ((DiskFlushNotification) hint).markFlushed(); + options.getLogger().log(SentryLevel.DEBUG, "Disk flush envelope fired"); } if (transportGate.isConnected()) { try { result = transport.send(envelope); if (result.isSuccess()) { - sessionCache.discard(envelope); + envelopeCache.discard(envelope); } else { final String message = "The transport failed to send the envelope with response code " diff --git a/sentry-core/src/main/java/io/sentry/core/transport/Connection.java b/sentry-core/src/main/java/io/sentry/core/transport/Connection.java index 02a5da2ae..d925c1b4c 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/Connection.java +++ b/sentry-core/src/main/java/io/sentry/core/transport/Connection.java @@ -1,17 +1,10 @@ package io.sentry.core.transport; import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEvent; import java.io.IOException; import org.jetbrains.annotations.Nullable; public interface Connection { - void send(SentryEvent event, @Nullable Object hint) throws IOException; - - default void send(SentryEvent event) throws IOException { - send(event, null); - } - void send(SentryEnvelope event, @Nullable Object hint) throws IOException; default void send(SentryEnvelope envelope) throws IOException { diff --git a/sentry-core/src/main/java/io/sentry/core/transport/NoOpEventCache.java b/sentry-core/src/main/java/io/sentry/core/transport/NoOpEventCache.java deleted file mode 100644 index 83a5cd265..000000000 --- a/sentry-core/src/main/java/io/sentry/core/transport/NoOpEventCache.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.sentry.core.transport; - -import io.sentry.core.SentryEvent; -import io.sentry.core.cache.IEventCache; -import java.util.ArrayList; -import java.util.Iterator; -import org.jetbrains.annotations.NotNull; - -public final class NoOpEventCache implements IEventCache { - private static final NoOpEventCache instance = new NoOpEventCache(); - - public static NoOpEventCache getInstance() { - return instance; - } - - private NoOpEventCache() {} - - @Override - public void store(SentryEvent event) {} - - @Override - public void discard(SentryEvent event) {} - - @Override - public @NotNull Iterator iterator() { - return new ArrayList(0).iterator(); - } -} diff --git a/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt b/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt index 231180698..8039ca6ae 100644 --- a/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt @@ -32,8 +32,8 @@ class DirectoryProcessorTest { options.setLogger(logger) } - fun getSut(): EnvelopeSender { - return EnvelopeSender(hub, envelopeReader, serializer, logger, 15000) + fun getSut(): OutboxSender { + return OutboxSender(hub, envelopeReader, serializer, logger, 15000) } } @@ -55,11 +55,17 @@ class DirectoryProcessorTest { fun `process directory folder has a non ApplyScopeData hint`() { val path = getTempEnvelope("envelope-event-attachment.txt") assertTrue(File(path).exists()) // sanity check - val session = createSession() - whenever(fixture.envelopeReader.read(any())).thenReturn(SentryEnvelope.fromSession(fixture.serializer, session, null)) - whenever(fixture.serializer.deserializeSession(any())).thenReturn(session) +// val session = createSession() +// whenever(fixture.envelopeReader.read(any())).thenReturn(SentryEnvelope.fromSession(fixture.serializer, session, null)) +// whenever(fixture.serializer.deserializeSession(any())).thenReturn(session) + val event = SentryEvent() + val envelope = SentryEnvelope.fromEvent(fixture.serializer, event, null) + + whenever(fixture.envelopeReader.read(any())).thenReturn(envelope) + whenever(fixture.serializer.deserializeEvent(any())).thenReturn(event) + fixture.getSut().processDirectory(file) - verify(fixture.hub).captureEnvelope(any(), argWhere { it !is ApplyScopeData }) + verify(fixture.hub).captureEvent(any(), argWhere { it !is ApplyScopeData }) } @Test diff --git a/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt b/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt index 7f2817375..7fb998994 100644 --- a/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt @@ -1,187 +1,115 @@ package io.sentry.core import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.argWhere +import com.nhaarman.mockitokotlin2.doThrow import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.cache.SessionCache +import io.sentry.core.cache.EnvelopeCache import io.sentry.core.hints.Retryable -import io.sentry.core.protocol.SentryId -import io.sentry.core.protocol.User +import io.sentry.core.util.NoFlushTimeout import java.io.File -import java.io.FileNotFoundException import java.nio.file.Files -import java.nio.file.Paths -import java.util.Date -import java.util.UUID +import java.nio.file.Path +import kotlin.test.AfterTest +import kotlin.test.BeforeTest import kotlin.test.Test -import kotlin.test.assertFailsWith import kotlin.test.assertFalse -import kotlin.test.assertTrue class EnvelopeSenderTest { private class Fixture { - - var hub: IHub = mock() - var envelopeReader: IEnvelopeReader = mock() - var serializer: ISerializer = mock() - var logger: ILogger = mock() - var options: SentryOptions + var hub: IHub? = mock() + var logger: ILogger? = mock() + var serializer: ISerializer? = mock() + var options = SentryOptions().NoFlushTimeout() init { - options = SentryOptions() options.isDebug = true options.setLogger(logger) } fun getSut(): EnvelopeSender { - return EnvelopeSender(hub, envelopeReader, serializer, logger, 15000) + return EnvelopeSender(hub!!, serializer!!, logger!!, options.flushTimeoutMillis) } } + private lateinit var tempDirectory: Path private val fixture = Fixture() - private fun getTempEnvelope(fileName: String): String { - val testFile = this::class.java.classLoader.getResource(fileName) - val testFileBytes = testFile!!.readBytes() - val targetFile = File.createTempFile("temp-envelope", ".tmp") - Files.write(Paths.get(targetFile.toURI()), testFileBytes) - return targetFile.absolutePath + @BeforeTest + fun `before send`() { + tempDirectory = Files.createTempDirectory("send-cached-event-test") } - @Test - fun `when envelopeReader returns null, file is deleted `() { - whenever(fixture.envelopeReader.read(any())).thenReturn(null) - val sut = fixture.getSut() - val path = getTempEnvelope("envelope-event-attachment.txt") - assertTrue(File(path).exists()) // sanity check - sut.processEnvelopeFile(path, mock()) - assertFalse(File(path).exists()) - // Additionally make sure we have a error logged - verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) + @AfterTest + fun `after send`() { + File(tempDirectory.toUri()).delete() } @Test - fun `when parser is EnvelopeReader and serializer returns SentryEvent, event captured, file is deleted `() { - fixture.envelopeReader = EnvelopeReader() - val expected = SentryEvent(SentryId(UUID.fromString("9ec79c33-ec99-42ab-8353-589fcb2e04dc")), Date()) - whenever(fixture.serializer.deserializeEvent(any())).thenReturn(expected) + fun `when directory doesn't exist, processDirectory logs and returns`() { val sut = fixture.getSut() - val path = getTempEnvelope("envelope-event-attachment.txt") - assertTrue(File(path).exists()) // sanity check - sut.processEnvelopeFile(path, mock()) - - verify(fixture.hub).captureEvent(eq(expected), any()) - assertFalse(File(path).exists()) - // Additionally make sure we have no errors logged - verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) - verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + sut.processDirectory(File("i don't exist")) + verify(fixture.logger)!!.log(eq(SentryLevel.WARNING), eq("Directory '%s' doesn't exist. No cached events to send."), any()) + verifyNoMoreInteractions(fixture.hub) } @Test - fun `when parser is EnvelopeReader and serializer returns SentryEnvelope, event captured, file is deleted `() { - fixture.envelopeReader = EnvelopeReader() - val session = Session("123", User(), "env", "release") - val expected = SentryEnvelope(SentryId("3067d54967f84f20a2adfab5119156ce"), null, setOf()) - whenever(fixture.serializer.deserializeEnvelope(any())).thenReturn(expected) - whenever(fixture.serializer.deserializeSession(any())).thenReturn(session) + fun `when directory is actually a file, processDirectory logs and returns`() { val sut = fixture.getSut() - val path = getTempEnvelope("envelope-session-start.txt") - assertTrue(File(path).exists()) // sanity check - sut.processEnvelopeFile(path, mock()) - - verify(fixture.hub).captureEnvelope(any(), any()) - assertFalse(File(path).exists()) - // Additionally make sure we have no errors logged - verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) - verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + val testFile = File(Files.createTempFile("send-cached-event-test", EnvelopeCache.SUFFIX_ENVELOPE_FILE).toUri()) + testFile.deleteOnExit() + sut.processDirectory(testFile) + verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq("Cache dir %s is not a directory."), any()) + verifyNoMoreInteractions(fixture.hub) } @Test - fun `when parser is EnvelopeReader and serializer returns a null event, file error logged, no event captured `() { - fixture.envelopeReader = EnvelopeReader() - whenever(fixture.serializer.deserializeEvent(any())).thenReturn(null) + fun `when directory has non event files, processDirectory logs that`() { val sut = fixture.getSut() - val path = getTempEnvelope("envelope-event-attachment.txt") - assertTrue(File(path).exists()) // sanity check - sut.processEnvelopeFile(path, mock()) - - // Additionally make sure we have no errors logged - verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) - verify(fixture.hub, never()).captureEvent(any()) - assertFalse(File(path).exists()) + val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", ".not-right-suffix").toUri()) + sut.processDirectory(File(tempDirectory.toUri())) + testFile.deleteOnExit() + verify(fixture.logger)!!.log(eq(SentryLevel.DEBUG), eq("File '%s' doesn't match extension expected."), any()) + verifyNoMoreInteractions(fixture.hub) } @Test - fun `when parser is EnvelopeReader and serializer returns a null envelope, file error logged, no event captured `() { - fixture.envelopeReader = EnvelopeReader() - whenever(fixture.serializer.deserializeEnvelope(any())).thenReturn(null) - whenever(fixture.serializer.deserializeSession(any())).thenReturn(null) + fun `when directory has event files, processDirectory captures with hub`() { + val event = SentryEvent() + val envelope = SentryEnvelope.fromEvent(fixture.serializer!!, event, null) + whenever(fixture.serializer!!.deserializeEnvelope(any())).thenReturn(envelope) val sut = fixture.getSut() - val path = getTempEnvelope("envelope-session-start.txt") - assertTrue(File(path).exists()) // sanity check - sut.processEnvelopeFile(path, mock()) - - // Additionally make sure we have no errors logged - verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) - verify(fixture.hub, never()).captureEvent(any()) - assertFalse(File(path).exists()) + val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", EnvelopeCache.SUFFIX_ENVELOPE_FILE).toUri()) + testFile.deleteOnExit() + sut.processDirectory(File(tempDirectory.toUri())) + verify(fixture.hub)!!.captureEnvelope(eq(envelope), any()) } @Test - fun `when processEnvelopeFile is called with a invalid path, logs error`() { + fun `when serializer throws, error is logged, file deleted`() { + val expected = RuntimeException() + whenever(fixture.serializer!!.deserializeEnvelope(any())).doThrow(expected) val sut = fixture.getSut() - sut.processEnvelopeFile(File.separator + "i-hope-it-doesnt-exist" + File.separator + "file.txt", mock()) - verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), argWhere { it is FileNotFoundException }) - } - - @Test - fun `when hub is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.EnvelopeSender") - val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) - val params = arrayOf(null, mock(), mock(), mock(), null) - assertFailsWith { ctor.newInstance(params) } - } - - @Test - fun `when envelopeReader is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.EnvelopeSender") - val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) - val params = arrayOf(mock(), null, mock(), mock(), 15000) - assertFailsWith { ctor.newInstance(params) } + val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", EnvelopeCache.SUFFIX_ENVELOPE_FILE).toUri()) + testFile.deleteOnExit() + sut.processFile(testFile, mock()) + verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq(expected), eq("Failed to capture cached envelope %s"), eq(testFile.absolutePath)) + verifyNoMoreInteractions(fixture.hub) + assertFalse(testFile.exists()) } @Test - fun `when serializer is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.EnvelopeSender") - val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) - val params = arrayOf(mock(), mock(), null, mock(), 15000) - assertFailsWith { ctor.newInstance(params) } - } - - @Test - fun `when logger is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.EnvelopeSender") - val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) - val params = arrayOf(mock(), mock(), mock(), null, 15000) - assertFailsWith { ctor.newInstance(params) } - } - - @Test - fun `when file name is null, should not be relevant`() { - assertFalse(fixture.getSut().isRelevantFileName(null)) - } - - @Test - fun `when file name is current prefix, should be ignored`() { - assertFalse(fixture.getSut().isRelevantFileName(SessionCache.PREFIX_CURRENT_SESSION_FILE)) - } - - @Test - fun `when file name is relevant, should return true`() { - assertTrue(fixture.getSut().isRelevantFileName("123.envelope")) + fun `when hub throws, file gets deleted`() { + val expected = RuntimeException() + whenever(fixture.serializer!!.deserializeEnvelope(any())).doThrow(expected) + val sut = fixture.getSut() + val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", EnvelopeCache.SUFFIX_ENVELOPE_FILE).toUri()) + testFile.deleteOnExit() + sut.processFile(testFile, any()) + verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq(expected), eq("Failed to capture cached envelope %s"), eq(testFile.absolutePath)) + verifyNoMoreInteractions(fixture.hub) } } diff --git a/sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt b/sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt new file mode 100644 index 000000000..56e91f914 --- /dev/null +++ b/sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt @@ -0,0 +1,187 @@ +package io.sentry.core + +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argWhere +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.core.cache.EnvelopeCache +import io.sentry.core.hints.Retryable +import io.sentry.core.protocol.SentryId +import java.io.File +import java.io.FileNotFoundException +import java.nio.file.Files +import java.nio.file.Paths +import java.util.Date +import java.util.UUID +import kotlin.test.Test +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class OutboxSenderTest { + private class Fixture { + + var hub: IHub = mock() + var envelopeReader: IEnvelopeReader = mock() + var serializer: ISerializer = mock() + var logger: ILogger = mock() + var options: SentryOptions + + init { + options = SentryOptions() + options.isDebug = true + options.setLogger(logger) + } + + fun getSut(): OutboxSender { + return OutboxSender(hub, envelopeReader, serializer, logger, 15000) + } + } + + private val fixture = Fixture() + + private fun getTempEnvelope(fileName: String): String { + val testFile = this::class.java.classLoader.getResource(fileName) + val testFileBytes = testFile!!.readBytes() + val targetFile = File.createTempFile("temp-envelope", ".tmp") + Files.write(Paths.get(targetFile.toURI()), testFileBytes) + return targetFile.absolutePath + } + + @Test + fun `when envelopeReader returns null, file is deleted `() { + whenever(fixture.envelopeReader.read(any())).thenReturn(null) + val sut = fixture.getSut() + val path = getTempEnvelope("envelope-event-attachment.txt") + assertTrue(File(path).exists()) // sanity check + sut.processEnvelopeFile(path, mock()) + assertFalse(File(path).exists()) + // Additionally make sure we have a error logged + verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) + } + + @Test + fun `when parser is EnvelopeReader and serializer returns SentryEvent, event captured, file is deleted `() { + fixture.envelopeReader = EnvelopeReader() + val expected = SentryEvent(SentryId(UUID.fromString("9ec79c33-ec99-42ab-8353-589fcb2e04dc")), Date()) + whenever(fixture.serializer.deserializeEvent(any())).thenReturn(expected) + val sut = fixture.getSut() + val path = getTempEnvelope("envelope-event-attachment.txt") + assertTrue(File(path).exists()) // sanity check + sut.processEnvelopeFile(path, mock()) + + verify(fixture.hub).captureEvent(eq(expected), any()) + assertFalse(File(path).exists()) + // Additionally make sure we have no errors logged + verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + } + + @Test + fun `when parser is EnvelopeReader and serializer returns SentryEnvelope, event captured, file is deleted `() { + fixture.envelopeReader = EnvelopeReader() + + val event = SentryEvent(SentryId("9ec79c33ec9942ab8353589fcb2e04dc"), Date()) + val expected = SentryEnvelope(SentryId("9ec79c33ec9942ab8353589fcb2e04dc"), null, setOf()) + whenever(fixture.serializer.deserializeEnvelope(any())).thenReturn(expected) + whenever(fixture.serializer.deserializeEvent(any())).thenReturn(event) + val sut = fixture.getSut() + val path = getTempEnvelope("envelope-event-attachment.txt") + assertTrue(File(path).exists()) // sanity check + sut.processEnvelopeFile(path, mock()) + + verify(fixture.hub).captureEvent(any(), any()) + assertFalse(File(path).exists()) + // Additionally make sure we have no errors logged + verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + verify(fixture.logger, never()).log(eq(SentryLevel.ERROR), any(), any()) + } + + @Test + fun `when parser is EnvelopeReader and serializer returns a null event, file error logged, no event captured `() { + fixture.envelopeReader = EnvelopeReader() + whenever(fixture.serializer.deserializeEvent(any())).thenReturn(null) + val sut = fixture.getSut() + val path = getTempEnvelope("envelope-event-attachment.txt") + assertTrue(File(path).exists()) // sanity check + sut.processEnvelopeFile(path, mock()) + + // Additionally make sure we have no errors logged + verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) + verify(fixture.hub, never()).captureEvent(any()) + assertFalse(File(path).exists()) + } + + @Test + fun `when parser is EnvelopeReader and serializer returns a null envelope, file error logged, no event captured `() { + fixture.envelopeReader = EnvelopeReader() + whenever(fixture.serializer.deserializeEnvelope(any())).thenReturn(null) + whenever(fixture.serializer.deserializeEvent(any())).thenReturn(null) + val sut = fixture.getSut() + val path = getTempEnvelope("envelope-event-attachment.txt") + assertTrue(File(path).exists()) // sanity check + sut.processEnvelopeFile(path, mock()) + + // Additionally make sure we have no errors logged + verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) + verify(fixture.hub, never()).captureEvent(any()) + assertFalse(File(path).exists()) + } + + @Test + fun `when processEnvelopeFile is called with a invalid path, logs error`() { + val sut = fixture.getSut() + sut.processEnvelopeFile(File.separator + "i-hope-it-doesnt-exist" + File.separator + "file.txt", mock()) + verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), argWhere { it is FileNotFoundException }) + } + + @Test + fun `when hub is null, ctor throws`() { + val clazz = Class.forName("io.sentry.core.OutboxSender") + val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) + val params = arrayOf(null, mock(), mock(), mock(), null) + assertFailsWith { ctor.newInstance(params) } + } + + @Test + fun `when envelopeReader is null, ctor throws`() { + val clazz = Class.forName("io.sentry.core.OutboxSender") + val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) + val params = arrayOf(mock(), null, mock(), mock(), 15000) + assertFailsWith { ctor.newInstance(params) } + } + + @Test + fun `when serializer is null, ctor throws`() { + val clazz = Class.forName("io.sentry.core.OutboxSender") + val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) + val params = arrayOf(mock(), mock(), null, mock(), 15000) + assertFailsWith { ctor.newInstance(params) } + } + + @Test + fun `when logger is null, ctor throws`() { + val clazz = Class.forName("io.sentry.core.OutboxSender") + val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) + val params = arrayOf(mock(), mock(), mock(), null, 15000) + assertFailsWith { ctor.newInstance(params) } + } + + @Test + fun `when file name is null, should not be relevant`() { + assertFalse(fixture.getSut().isRelevantFileName(null)) + } + + @Test + fun `when file name is current prefix, should be ignored`() { + assertFalse(fixture.getSut().isRelevantFileName(EnvelopeCache.PREFIX_CURRENT_SESSION_FILE)) + } + + @Test + fun `when file name is relevant, should return true`() { + assertTrue(fixture.getSut().isRelevantFileName("123.envelope")) + } +} diff --git a/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt b/sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt similarity index 77% rename from sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt rename to sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt index 9c242ff75..fb32a8e08 100644 --- a/sentry-core/src/test/java/io/sentry/core/SendCachedEventFireAndForgetIntegrationTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt @@ -7,20 +7,20 @@ import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import kotlin.test.Test import kotlin.test.assertFalse -class SendCachedEventFireAndForgetIntegrationTest { +class SendCachedEnvelopeFireAndForgetIntegrationTest { private class Fixture { var hub: IHub = mock() var logger: ILogger = mock() var options = SentryOptions() - var callback = mock() + var callback = mock() init { options.isDebug = true options.setLogger(logger) } - fun getSut(): SendCachedEventFireAndForgetIntegration { - return SendCachedEventFireAndForgetIntegration(callback) + fun getSut(): SendCachedEnvelopeFireAndForgetIntegration { + return SendCachedEnvelopeFireAndForgetIntegration(callback) } } @@ -55,15 +55,15 @@ class SendCachedEventFireAndForgetIntegrationTest { @Test fun `when Factory returns null, register logs and exit`() { - val sut = SendCachedEventFireAndForgetIntegration(CustomFactory()) + val sut = SendCachedEnvelopeFireAndForgetIntegration(CustomFactory()) fixture.options.cacheDirPath = "abc" sut.register(fixture.hub, fixture.options) verify(fixture.logger).log(eq(SentryLevel.ERROR), eq("SendFireAndForget factory is null.")) verifyNoMoreInteractions(fixture.hub) } - private class CustomFactory : SendCachedEventFireAndForgetIntegration.SendFireAndForgetFactory { - override fun create(hub: IHub?, options: SentryOptions?): SendCachedEventFireAndForgetIntegration.SendFireAndForget? { + private class CustomFactory : SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetFactory { + override fun create(hub: IHub?, options: SentryOptions?): SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget? { return null } } diff --git a/sentry-core/src/test/java/io/sentry/core/SendCachedEventTest.kt b/sentry-core/src/test/java/io/sentry/core/SendCachedEventTest.kt deleted file mode 100644 index 0d8453dd4..000000000 --- a/sentry-core/src/test/java/io/sentry/core/SendCachedEventTest.kt +++ /dev/null @@ -1,115 +0,0 @@ -package io.sentry.core - -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions -import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.cache.DiskCache -import io.sentry.core.hints.Retryable -import io.sentry.core.util.NoFlushTimeout -import java.io.File -import java.nio.file.Files -import java.nio.file.Path -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertFalse - -class SendCachedEventTest { - private class Fixture { - var hub: IHub? = mock() - var logger: ILogger? = mock() - var serializer: ISerializer? = mock() - var options = SentryOptions().NoFlushTimeout() - - init { - options.isDebug = true - options.setLogger(logger) - } - - fun getSut(): SendCachedEvent { - return SendCachedEvent(serializer!!, hub!!, logger!!, options.flushTimeoutMillis) - } - } - - private lateinit var tempDirectory: Path - private val fixture = Fixture() - - @BeforeTest - fun `before send`() { - tempDirectory = Files.createTempDirectory("send-cached-event-test") - } - - @AfterTest - fun `after send`() { - File(tempDirectory.toUri()).delete() - } - - @Test - fun `when directory doesn't exist, processDirectory logs and returns`() { - val sut = fixture.getSut() - sut.processDirectory(File("i don't exist")) - verify(fixture.logger)!!.log(eq(SentryLevel.WARNING), eq("Directory '%s' doesn't exist. No cached events to send."), any()) - verifyNoMoreInteractions(fixture.hub) - } - - @Test - fun `when directory is actually a file, processDirectory logs and returns`() { - val sut = fixture.getSut() - val testFile = File(Files.createTempFile("send-cached-event-test", DiskCache.FILE_SUFFIX).toUri()) - testFile.deleteOnExit() - sut.processDirectory(testFile) - verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq("Cache dir %s is not a directory."), any()) - verifyNoMoreInteractions(fixture.hub) - } - - @Test - fun `when directory has non event files, processDirectory logs that`() { - val sut = fixture.getSut() - val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", ".not-right-suffix").toUri()) - sut.processDirectory(File(tempDirectory.toUri())) - testFile.deleteOnExit() - verify(fixture.logger)!!.log(eq(SentryLevel.DEBUG), eq("File '%s' doesn't match extension expected."), any()) - verifyNoMoreInteractions(fixture.hub) - } - - @Test - fun `when directory has event files, processDirectory captures with hub`() { - val expected = SentryEvent() - whenever(fixture.serializer!!.deserializeEvent(any())).thenReturn(expected) - val sut = fixture.getSut() - val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", DiskCache.FILE_SUFFIX).toUri()) - testFile.deleteOnExit() - sut.processDirectory(File(tempDirectory.toUri())) - verify(fixture.hub)!!.captureEvent(eq(expected), any()) - } - - @Test - fun `when serializer throws, error is logged, file deleted`() { - val expected = RuntimeException() - whenever(fixture.serializer!!.deserializeEvent(any())).doThrow(expected) - val sut = fixture.getSut() - val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", DiskCache.FILE_SUFFIX).toUri()) - testFile.deleteOnExit() - sut.processFile(testFile, mock()) - verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq(expected), eq("Failed to capture cached event %s"), eq(testFile.absolutePath)) - verifyNoMoreInteractions(fixture.hub) - assertFalse(testFile.exists()) - } - - @Test - fun `when hub throws, file gets deleted`() { - whenever(fixture.serializer!!.deserializeEvent(any())).thenReturn(SentryEvent()) - val expected = RuntimeException() - whenever(fixture.serializer!!.deserializeEvent(any())).doThrow(expected) - val sut = fixture.getSut() - val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", DiskCache.FILE_SUFFIX).toUri()) - testFile.deleteOnExit() - sut.processFile(testFile, any()) - verify(fixture.logger)!!.log(eq(SentryLevel.ERROR), eq(expected), eq("Failed to capture cached event %s"), eq(testFile.absolutePath)) - verifyNoMoreInteractions(fixture.hub) - } -} diff --git a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt index 471e22246..227bfb1a8 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt @@ -2,10 +2,8 @@ package io.sentry.core import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.anyOrNull -import com.nhaarman.mockitokotlin2.argWhere import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.isNull import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.mockingDetails import com.nhaarman.mockitokotlin2.never @@ -15,8 +13,6 @@ import com.nhaarman.mockitokotlin2.whenever import io.sentry.core.hints.ApplyScopeData import io.sentry.core.hints.Cached import io.sentry.core.hints.DiskFlushNotification -import io.sentry.core.hints.SessionEndHint -import io.sentry.core.hints.SessionUpdateHint import io.sentry.core.protocol.Mechanism import io.sentry.core.protocol.Request import io.sentry.core.protocol.SdkVersion @@ -26,7 +22,9 @@ import io.sentry.core.protocol.User import io.sentry.core.transport.AsyncConnection import io.sentry.core.transport.HttpTransport import io.sentry.core.transport.ITransportGate +import java.io.ByteArrayInputStream import java.io.IOException +import java.io.InputStreamReader import java.net.URL import java.util.UUID import kotlin.test.Ignore @@ -48,8 +46,10 @@ class SentryClientTest { name = "test" version = "1.2.3" } + setSerializer(GsonSerializer(mock(), envelopeReader)) } var connection: AsyncConnection = mock() + fun getSut() = SentryClient(sentryOptions, connection) } @@ -120,17 +120,22 @@ class SentryClientTest { val sut = fixture.getSut() val event = SentryEvent() sut.captureEvent(event) - verify(fixture.connection, never()).send(event) + verify(fixture.connection, never()).send(any()) } @Test fun `when beforeSend is returns new instance, new instance is sent`() { - val expected = SentryEvent() + val expected = SentryEvent().apply { + setTag("test", "test") + } fixture.sentryOptions.setBeforeSend { _, _ -> expected } val sut = fixture.getSut() val actual = SentryEvent() sut.captureEvent(actual) - verify(fixture.connection).send(eq(expected), isNull()) + verify(fixture.connection).send(check { + val event = getEventFromData(it.items.first().data) + assertEquals("test", event.tags["test"]) + }, anyOrNull()) verifyNoMoreInteractions(fixture.connection) } @@ -157,7 +162,7 @@ class SentryClientTest { val sut = fixture.getSut() val expectedHint = Object() sut.captureEvent(event, expectedHint) - verify(fixture.connection).send(event, expectedHint) + verify(fixture.connection).send(any(), eq(expectedHint)) } @Test @@ -422,6 +427,7 @@ class SentryClientTest { val event = SentryEvent() val scope = createScope() val processor = mock() + whenever(processor.process(any(), anyOrNull())).thenReturn(event) scope.addEventProcessor(processor) val sut = fixture.getSut() @@ -577,39 +583,6 @@ class SentryClientTest { } } - @Test - fun `When event comes from uncaughtException, captureSession should use SessionEndHint`() { - fixture.sentryOptions.release = "a@1+1" - val sut = fixture.getSut() - - val event = SentryEvent().apply { - exceptions = createNonHandledException() - } - val scope = Scope(fixture.sentryOptions) - scope.startSession() - val hint = mock() - sut.captureEvent(event, scope, hint) - verify(fixture.connection).send(any(), argWhere { - it is SessionEndHint - }) - } - - @Test - fun `When event is not from uncaughtException, captureSession should use SessionUpdateHint`() { - fixture.sentryOptions.release = "a@1+1" - val sut = fixture.getSut() - - val event = SentryEvent().apply { - exceptions = createNonHandledException() - } - val scope = Scope(fixture.sentryOptions) - scope.startSession() - sut.captureEvent(event, scope) - verify(fixture.connection).send(any(), argWhere { - it is SessionUpdateHint - }) - } - @Test fun `when captureEvent with sampling, session is still updated`() { fixture.sentryOptions.sampleRate = 1.0 @@ -631,13 +604,13 @@ class SentryClientTest { fun `when context property is missing on the event, property from scope contexts is applied`() { val sut = fixture.getSut() - val event = SentryEvent() val scope = Scope(fixture.sentryOptions) scope.setContexts("key", "value") scope.startSession().current - sut.captureEvent(event, scope, null) - verify(fixture.connection).send(check() { - assertEquals("value", it.contexts["key"]) + sut.captureEvent(SentryEvent(), scope, null) + verify(fixture.connection).send(check { + val event = getEventFromData(it.items.first().data) + assertEquals("value", event.contexts["key"]) }, anyOrNull()) } @@ -651,8 +624,9 @@ class SentryClientTest { scope.setContexts("key", "scope value") scope.startSession().current sut.captureEvent(event, scope, null) - verify(fixture.connection).send(check() { - assertEquals("event value", it.contexts["key"]) + verify(fixture.connection).send(check { + val eventFromData = getEventFromData(it.items.first().data) + assertEquals("event value", eventFromData.contexts["key"]) }, anyOrNull()) } @@ -705,6 +679,11 @@ class SentryClientTest { return listOf(exception) } + private fun getEventFromData(data: ByteArray): SentryEvent { + val inputStream = InputStreamReader(ByteArrayInputStream(data)) + return fixture.sentryOptions.serializer.deserializeEvent(inputStream) + } + internal class CustomCachedApplyScopeDataHint : Cached, ApplyScopeData internal class DiskFlushNotificationHint : DiskFlushNotification { diff --git a/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt index 5068179e0..89732b673 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt @@ -106,19 +106,6 @@ class SentryOptionsTest { assertEquals("${File.separator}test${File.separator}outbox", options.outboxPath) } - @Test - fun `when there's no cacheDirPath, sessionPath returns null`() { - val options = SentryOptions() - assertNull(options.sessionsPath) - } - - @Test - fun `when cacheDirPath is set, sessionPath concatenate sessions path`() { - val options = SentryOptions() - options.cacheDirPath = "${File.separator}test" - assertEquals("${File.separator}test${File.separator}sessions", options.sessionsPath) - } - @Test fun `SentryOptions creates SentryExecutorService on ctor`() { val options = SentryOptions() diff --git a/sentry-core/src/test/java/io/sentry/core/SentryTest.kt b/sentry-core/src/test/java/io/sentry/core/SentryTest.kt index 348946fa9..61b579c6f 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/SentryTest.kt @@ -46,20 +46,6 @@ class SentryTest { file.deleteOnExit() } - @Test - fun `sessionDir should be created at initialization`() { - var sentryOptions: SentryOptions? = null - Sentry.init { - it.dsn = "http://key@localhost/proj" - it.cacheDirPath = getTempPath() - sentryOptions = it - } - - val file = File(sentryOptions!!.sessionsPath!!) - assertTrue(file.exists()) - file.deleteOnExit() - } - @Test fun `Init sets SystemOutLogger if logger is NoOp and debug is enabled`() { var sentryOptions: SentryOptions? = null diff --git a/sentry-core/src/test/java/io/sentry/core/cache/DiskCacheTest.kt b/sentry-core/src/test/java/io/sentry/core/cache/DiskCacheTest.kt deleted file mode 100644 index d79e47b2a..000000000 --- a/sentry-core/src/test/java/io/sentry/core/cache/DiskCacheTest.kt +++ /dev/null @@ -1,114 +0,0 @@ -package io.sentry.core.cache - -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.ISerializer -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions -import io.sentry.core.protocol.SentryId -import java.io.Reader -import java.io.Writer -import java.nio.file.Files -import java.nio.file.Path -import kotlin.test.AfterTest -import kotlin.test.Test -import kotlin.test.assertEquals - -class DiskCacheTest { - private class Fixture { - val maxSize = 5 - val dir: Path = Files.createTempDirectory("sentry-disk-cache-test") - - fun getSUT(): DiskCache { - val options = SentryOptions() - options.cacheDirSize = maxSize - options.cacheDirPath = dir.toAbsolutePath().toFile().absolutePath - - val serializer = mock() - doAnswer { - val event = it.arguments[0] as SentryEvent - val writer = it.arguments[1] as Writer - - writer.write(event.eventId.toString()) - }.whenever(serializer).serialize(any(), any()) - - whenever(serializer.deserializeEvent(any())).thenAnswer { - val reader = it.arguments[0] as Reader - - val ret = SentryEvent() - val text = reader.readText() - ret.eventId = SentryId(text) - ret - } - - options.setSerializer(serializer) - - return DiskCache(options) - } - } - - private val fixture = Fixture() - - @AfterTest - fun cleanUp() { - fixture.dir.toFile().listFiles()?.forEach { it.delete() } - Files.delete(fixture.dir) - } - - @Test - fun `stores events`() { - val cache = fixture.getSUT() - - val nofFiles = { fixture.dir.toFile().list()?.size } - - assertEquals(0, nofFiles()) - - cache.store(SentryEvent()) - - assertEquals(1, nofFiles()) - } - - @Test - fun `limits the number of stored events`() { - val cache = fixture.getSUT() - - val nofFiles = { fixture.dir.toFile().list()?.size } - - assertEquals(0, nofFiles()) - - (1..fixture.maxSize + 1).forEach { _ -> - cache.store(SentryEvent(Exception())) - } - - assertEquals(fixture.maxSize, nofFiles()) - } - - @Test - fun `tolerates discarding unknown event`() { - val cache = fixture.getSUT() - - cache.discard(SentryEvent()) - - // no exception thrown - } - - @Test - fun `reads the event back`() { - - val cache = fixture.getSUT() - - val event = SentryEvent() - - cache.store(event) - - val readEvents = cache.toList() - - assertEquals(1, readEvents.size) - - val readEvent = readEvents[0] - - assertEquals(event.eventId.toString(), readEvent.eventId.toString()) - } -} diff --git a/sentry-core/src/test/java/io/sentry/core/cache/SessionCacheTest.kt b/sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt similarity index 69% rename from sentry-core/src/test/java/io/sentry/core/cache/SessionCacheTest.kt rename to sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt index b4d2e1586..fdfc1cf86 100644 --- a/sentry-core/src/test/java/io/sentry/core/cache/SessionCacheTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt @@ -11,12 +11,10 @@ import io.sentry.core.SentryEnvelope import io.sentry.core.SentryLevel import io.sentry.core.SentryOptions import io.sentry.core.Session -import io.sentry.core.cache.SessionCache.PREFIX_CURRENT_SESSION_FILE -import io.sentry.core.cache.SessionCache.SUFFIX_CURRENT_SESSION_FILE -import io.sentry.core.cache.SessionCache.SUFFIX_ENVELOPE_FILE +import io.sentry.core.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE +import io.sentry.core.cache.EnvelopeCache.SUFFIX_CURRENT_SESSION_FILE import io.sentry.core.hints.SessionEndHint import io.sentry.core.hints.SessionStartHint -import io.sentry.core.hints.SessionUpdateHint import io.sentry.core.protocol.User import java.io.File import java.nio.file.Files @@ -27,7 +25,7 @@ import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertTrue -class SessionCacheTest { +class EnvelopeCacheTest { private class Fixture { val maxSize = 5 val dir: Path = Files.createTempDirectory("sentry-session-cache-test") @@ -36,9 +34,7 @@ class SessionCacheTest { val logger = mock() fun getSUT(): IEnvelopeCache { - options.sessionsDirSize = maxSize options.cacheDirPath = dir.toAbsolutePath().toFile().absolutePath - File(options.sessionsPath!!).mkdirs() whenever(serializer.deserializeSession(any())).thenAnswer { Session("dis", User(), "env", "rel") @@ -48,7 +44,7 @@ class SessionCacheTest { options.setSerializer(serializer) options.isDebug = true - return SessionCache(options) + return EnvelopeCache(options) } } @@ -58,7 +54,7 @@ class SessionCacheTest { fun `stores envelopes`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) + val file = File(fixture.options.cacheDirPath!!) val nofFiles = { file.list()?.size } assertEquals(0, nofFiles()) @@ -70,24 +66,6 @@ class SessionCacheTest { file.deleteRecursively() } - @Test - fun `limits the number of stored envelopes`() { - val cache = fixture.getSUT() - - val file = File(fixture.options.sessionsPath!!) - val nofFiles = { file.list()?.size } - - assertEquals(0, nofFiles()) - - (1..fixture.maxSize + 1).forEach { _ -> - cache.store(SentryEnvelope.fromSession(fixture.serializer, createSession(), null)) - } - - assertEquals(fixture.maxSize, nofFiles()) - - file.deleteRecursively() - } - @Test fun `tolerates discarding unknown envelope`() { val cache = fixture.getSUT() @@ -101,12 +79,12 @@ class SessionCacheTest { fun `creates current file on session start`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) + val file = File(fixture.options.cacheDirPath!!) val envelope = SentryEnvelope.fromSession(fixture.serializer, createSession(), null) cache.store(envelope, SessionStartHint()) - val currentFile = File(fixture.options.sessionsPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") + val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) file.deleteRecursively() @@ -116,12 +94,12 @@ class SessionCacheTest { fun `deletes current file on session end`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) + val file = File(fixture.options.cacheDirPath!!) val envelope = SentryEnvelope.fromSession(fixture.serializer, createSession(), null) cache.store(envelope, SessionStartHint()) - val currentFile = File(fixture.options.sessionsPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") + val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) cache.store(envelope, SessionEndHint()) @@ -130,39 +108,16 @@ class SessionCacheTest { file.deleteRecursively() } - @Test - fun `updates current file on session update, but do not create a new envelope`() { - val cache = fixture.getSUT() - - val file = File(fixture.options.sessionsPath!!) - - val envelope = SentryEnvelope.fromSession(fixture.serializer, createSession(), null) - cache.store(envelope, SessionStartHint()) - - val currentFile = File(fixture.options.sessionsPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") - assertTrue(currentFile.exists()) - - val newEnvelope = SentryEnvelope.fromSession(fixture.serializer, createSession(), null) - - cache.store(newEnvelope, SessionUpdateHint()) - assertTrue(currentFile.exists()) - - val newFile = File(file.absolutePath, "${newEnvelope.header.eventId}$SUFFIX_ENVELOPE_FILE") - assertFalse(newFile.exists()) - - file.deleteRecursively() - } - @Test fun `updates current file on session update and read it back`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) + val file = File(fixture.options.cacheDirPath!!) val envelope = SentryEnvelope.fromSession(fixture.serializer, createSession(), null) cache.store(envelope, SessionStartHint()) - val currentFile = File(fixture.options.sessionsPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") + val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) val session = fixture.serializer.deserializeSession(currentFile.bufferedReader(Charsets.UTF_8)) @@ -190,8 +145,8 @@ class SessionCacheTest { fun `when session start, current file already exist and crash marker file exist, end session and delete marker file`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) - val markerFile = File(fixture.options.cacheDirPath!!, SessionCache.CRASH_MARKER_FILE) + val file = File(fixture.options.cacheDirPath!!) + val markerFile = File(fixture.options.cacheDirPath!!, EnvelopeCache.CRASH_MARKER_FILE) markerFile.mkdirs() assertTrue(markerFile.exists()) @@ -209,8 +164,8 @@ class SessionCacheTest { @Test fun `when session start, current file already exist and crash marker file exist, end session with given timestamp`() { val cache = fixture.getSUT() - val file = File(fixture.options.sessionsPath!!) - val markerFile = File(fixture.options.cacheDirPath!!, SessionCache.CRASH_MARKER_FILE) + val file = File(fixture.options.cacheDirPath!!) + val markerFile = File(fixture.options.cacheDirPath!!, EnvelopeCache.CRASH_MARKER_FILE) File(fixture.options.cacheDirPath!!, ".sentry-native").mkdirs() markerFile.createNewFile() val date = "2020-02-07T14:16:00.000Z" diff --git a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt b/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt index 2b7b8dc05..0e54785eb 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt @@ -17,7 +17,6 @@ import io.sentry.core.SentryEvent import io.sentry.core.SentryOptions import io.sentry.core.Session import io.sentry.core.cache.IEnvelopeCache -import io.sentry.core.cache.IEventCache import io.sentry.core.dsnString import io.sentry.core.protocol.User import java.io.IOException @@ -30,8 +29,7 @@ class AsyncConnectionTest { private class Fixture { var transport = mock() var transportGate = mock() - var eventCache = mock() - var sessionCache = mock() + var envelopeCache = mock() var executor = mock() var sentryOptions: SentryOptions = SentryOptions().apply { dsn = dsnString @@ -46,70 +44,34 @@ class AsyncConnectionTest { } fun getSUT(): AsyncConnection { - return AsyncConnection(transport, transportGate, eventCache, sessionCache, executor, sentryOptions) + return AsyncConnection(transport, transportGate, envelopeCache, executor, sentryOptions) } } private val fixture = Fixture() @Test - fun `successful send discards the event from cache`() { - // given - val ev = mock() - whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.success()) - - // when - fixture.getSUT().send(ev) - - // then - val order = inOrder(fixture.transport, fixture.eventCache) - - // because storeBeforeSend is enabled by default - order.verify(fixture.eventCache).store(eq(ev)) - - order.verify(fixture.transport).send(check { - assertEquals(ev.eventId, it.header.eventId) - }) - order.verify(fixture.eventCache).discard(eq(ev)) - } - - @Test - fun `successful send discards the session from cache`() { + fun `successful send discards the envelope from cache`() { // given val envelope = SentryEnvelope.fromSession(fixture.sentryOptions.serializer, createSession(), null) whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.success()) + whenever(fixture.transport.send(any())).thenReturn(TransportResult.success()) // when fixture.getSUT().send(envelope) // then - val order = inOrder(fixture.transport, fixture.sessionCache) + val order = inOrder(fixture.transport, fixture.envelopeCache) // because storeBeforeSend is enabled by default - order.verify(fixture.sessionCache).store(eq(envelope), anyOrNull()) + order.verify(fixture.envelopeCache).store(eq(envelope), anyOrNull()) order.verify(fixture.transport).send(eq(envelope)) - order.verify(fixture.sessionCache).discard(eq(envelope)) + order.verify(fixture.envelopeCache).discard(eq(envelope)) } @Test - fun `stores event in cache if sending is not allowed`() { - // given - val ev = mock() - whenever(fixture.transportGate.isConnected).thenReturn(false) - - // when - fixture.getSUT().send(ev) - - // then - verify(fixture.eventCache).store(eq(ev)) - verify(fixture.transport).isRetryAfter(any()) - } - - @Test - fun `stores session in cache if sending is not allowed`() { + fun `stores envelope in cache if sending is not allowed`() { // given val envelope = SentryEnvelope.fromSession(fixture.sentryOptions.serializer, createSession(), null) whenever(fixture.transportGate.isConnected).thenReturn(false) @@ -118,42 +80,16 @@ class AsyncConnectionTest { fixture.getSUT().send(envelope) // then - verify(fixture.sessionCache).store(eq(envelope), anyOrNull()) + verify(fixture.envelopeCache).store(eq(envelope), anyOrNull()) verify(fixture.transport).isRetryAfter(any()) } @Test - fun `stores event after unsuccessful send`() { - // given - val ev = mock() - whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.error(500)) - - // when - try { - fixture.getSUT().send(ev) - } catch (e: IllegalStateException) { - // expected - this is how the AsyncConnection signals failure to the executor for it to retry - } - - // then - val order = inOrder(fixture.transport, fixture.eventCache) - - // because storeBeforeSend is enabled by default - order.verify(fixture.eventCache).store(eq(ev)) - - order.verify(fixture.transport).send(check { - assertEquals(ev.eventId, it.header.eventId) - }) - verify(fixture.eventCache, never()).discard(any()) - } - - @Test - fun `stores session after unsuccessful send`() { + fun `stores envelope after unsuccessful send`() { // given val envelope = SentryEnvelope.fromSession(fixture.sentryOptions.serializer, createSession(), null) whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenReturn(TransportResult.error(500)) + whenever(fixture.transport.send(any())).thenReturn(TransportResult.error(500)) // when try { @@ -163,43 +99,21 @@ class AsyncConnectionTest { } // then - val order = inOrder(fixture.transport, fixture.sessionCache) + val order = inOrder(fixture.transport, fixture.envelopeCache) // because storeBeforeSend is enabled by default - order.verify(fixture.sessionCache).store(eq(envelope), anyOrNull()) + order.verify(fixture.envelopeCache).store(eq(envelope), anyOrNull()) order.verify(fixture.transport).send(eq(envelope)) - verify(fixture.eventCache, never()).discard(any()) - } - - @Test - fun `stores event after send failure`() { - // given - val ev = mock() - whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenThrow(IOException()) - - // when - try { - fixture.getSUT().send(ev) - } catch (e: IllegalStateException) { - // expected - this is how the AsyncConnection signals failure to the executor for it to retry - } - - // then - val order = inOrder(fixture.transport, fixture.eventCache) - order.verify(fixture.transport).send(check { - assertEquals(ev.eventId, it.header.eventId) - }) - verify(fixture.eventCache, never()).discard(any()) + verify(fixture.envelopeCache, never()).discard(any()) } @Test - fun `stores session after send failure`() { + fun `stores envelope after send failure`() { // given val envelope = SentryEnvelope.fromSession(fixture.sentryOptions.serializer, createSession(), null) whenever(fixture.transportGate.isConnected).thenReturn(true) - whenever(fixture.transport.send(any())).thenThrow(IOException()) + whenever(fixture.transport.send(any())).thenThrow(IOException()) // when try { @@ -209,9 +123,9 @@ class AsyncConnectionTest { } // then - val order = inOrder(fixture.transport, fixture.sessionCache) + val order = inOrder(fixture.transport, fixture.envelopeCache) order.verify(fixture.transport).send(eq(envelope)) - verify(fixture.sessionCache, never()).discard(any()) + verify(fixture.envelopeCache, never()).discard(any()) } @Test @@ -219,9 +133,10 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transport.isRetryAfter(any())).thenReturn(true) + val envelope = SentryEnvelope.fromEvent(fixture.sentryOptions.serializer, ev, null) // when - fixture.getSUT().send(ev) + fixture.getSUT().send(envelope) // then verify(fixture.executor, never()).submit(any()) @@ -232,9 +147,10 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transport.isRetryAfter(any())).thenReturn(false) + val envelope = SentryEnvelope.fromEvent(fixture.sentryOptions.serializer, ev, null) // when - fixture.getSUT().send(ev) + fixture.getSUT().send(envelope) // then verify(fixture.executor).submit(any()) @@ -263,7 +179,7 @@ class AsyncConnectionTest { fixture.getSUT().send(envelope, CachedEvent()) // then - verify(fixture.sessionCache).discard(any()) + verify(fixture.envelopeCache).discard(any()) } @Test @@ -276,7 +192,7 @@ class AsyncConnectionTest { fixture.getSUT().send(envelope) // then - verify(fixture.sessionCache, never()).discard(any()) + verify(fixture.envelopeCache, never()).discard(any()) } @Test @@ -313,12 +229,13 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transport.isRetryAfter(any())).thenReturn(true) + val envelope = SentryEnvelope.fromEvent(fixture.sentryOptions.serializer, ev, null) // when - fixture.getSUT().send(ev, CachedEvent()) + fixture.getSUT().send(envelope, CachedEvent()) // then - verify(fixture.eventCache).discard(any()) + verify(fixture.envelopeCache).discard(any()) } @Test @@ -326,12 +243,13 @@ class AsyncConnectionTest { // given val ev = mock() whenever(fixture.transport.isRetryAfter(any())).thenReturn(true) + val envelope = SentryEnvelope.fromEvent(fixture.sentryOptions.serializer, ev, null) // when - fixture.getSUT().send(ev) + fixture.getSUT().send(envelope) // then - verify(fixture.eventCache, never()).discard(any()) + verify(fixture.envelopeCache, never()).discard(any()) } private fun createSession(): Session { From 3915ca4154642f38bc9850ab951053f9364e5388 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:41:00 +0200 Subject: [PATCH 17/28] fix: enable session tracking by default on sample (#538) --- sentry-samples/sentry-samples-android/build.gradle.kts | 6 ++++-- .../sentry-samples-android/src/main/AndroidManifest.xml | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sentry-samples/sentry-samples-android/build.gradle.kts b/sentry-samples/sentry-samples-android/build.gradle.kts index 5c293457a..fd3b53bae 100644 --- a/sentry-samples/sentry-samples-android/build.gradle.kts +++ b/sentry-samples/sentry-samples-android/build.gradle.kts @@ -66,7 +66,8 @@ android { buildTypes { getByName("debug") { manifestPlaceholders = mapOf( - "sentryDebug" to true + "sentryDebug" to true, + "sentryEnvironment" to "debug" ) } getByName("release") { @@ -76,7 +77,8 @@ android { isShrinkResources = true manifestPlaceholders = mapOf( - "sentryDebug" to false + "sentryDebug" to false, + "sentryEnvironment" to "release" ) } } diff --git a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml index dc9962982..6caf842bb 100644 --- a/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml +++ b/sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml @@ -57,13 +57,13 @@ - + - + - + From 9aad2cbe7b39a6ed26433e6fc43257a93c8045e9 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 3 Sep 2020 16:06:36 +0200 Subject: [PATCH 18/28] chore 3.0.0-alpha.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5ee4f9c38..05166c13b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ android.useAndroidX=true # Release information buildVersionCode=20038 -versionName=3.0.0-alpha.1-SNAPSHOT +versionName=3.0.0-alpha.1 # disable renderscript, it's enabled by default android.defaults.buildfeatures.renderscript=false From e767af6215fc459339059c444afe3d4d2e6591f2 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 3 Sep 2020 16:07:21 +0200 Subject: [PATCH 19/28] prepare: 3.0.0-alpha.2 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 05166c13b..cce174a00 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,8 +8,8 @@ org.gradle.caching=true android.useAndroidX=true # Release information -buildVersionCode=20038 -versionName=3.0.0-alpha.1 +buildVersionCode=20039 +versionName=3.0.0-alpha.2-SNAPSHOT # disable renderscript, it's enabled by default android.defaults.buildfeatures.renderscript=false From b754303a95e1e59d0262acdf51302441404f844a Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 3 Sep 2020 16:14:02 +0200 Subject: [PATCH 20/28] Bump Gradle to 6.6.1 --- gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 21 +++------------------ 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 6656 zcmY+Ibx_pN*Z*PZ4(U#j1qtbvrOTyO8fghZ8kYJfEe%U|$dV!@ASKczEZq$fg48M@ z;LnHO_j#Uq?%bL4dY^md%$$4Y+&@nKC|1uHR&59YNhubGh72|a#ylPdh9V+akp|I; zPk^W-a00GrFMkz_NSADdv2G2-i6rb=cB_@WnG(**4ZO$=96R=t|NZ@|0_z&q3GwO^ ziUFcuj$a9QaZ3j?xt`5#q`sT-ufrtBP0nt3IA&dr*+VCsBzBVW?vZ6eZr0oD%t33z zm~-5IVsjy(F>;S~Pm@bxX85>Z*@(QL6i3JQc?1ryQFcC@X^2^mZWhFv|v? z49>l|nA&XNQ6#OvccUTyBMB*WO#NA;FW5|eE_K6dtVYP2G?uUZ09!`Iq1IF2gA(aS zLu@G^cQJmh=x?-YsYa@E6QnE5+1@ds&0f#OQRDl^GnIT_m84G5XY%W z;Ck6bk^Oeu*Ma-XmxI5GjqzWNbJMsQF4)WfMZEA{oxW0E32e)*JfG}3otPishIQBw zkBe6N#4pKPN>q1R6G1@5&(u#5yPEToMBB6_oEK|q z@(i5j!?;NNCv~=HvW%zF&1yWBq(nJa_#``G&SRmQvE|jePUPs{J!$TacM|e}Fsceb zx+76|mDp6@w>)^DIl{8?)6XYNRU|2plG8Jy&7(^9SdOWNKKJK&>0!z6XiN4J*Jkao z=E1y5x-XDC==Ub+8fLb#OW&{2ww{h^xlJFYAMOUd)}Xg@j?ak{7Kno6?9S~F?|6Df zHo|ijXX~`Sp;Vf!nR;m%vUhq>zvlRXsL0u*Tt?F#yR}3tF0#of{(UjitqST|!{aBA zicWh+URU}Jnc*sg9iMkf0pggpd?3TI*C-q$2QOdCC7rV+CHBmjS3O%a3VeZ$ZSs5ubJuJp%e%$LHgrj0niYjX;4kt z&2~j%@q3MO)-QGCA{>o%eZu){ou^MgC6~Z8Y=tc!qF=|TOlG3wJXbaLYr-;$Ch=2J z_UcE59Xzq&h0LsjLrcZrQSa}#=0~Lk|4?e4M z6d;v->NCC1oMti)RRc`Ys0?JXQjsZ@VdCy%Z)TptCrI>0Tte$pR!@yJesoU2dtyuW z7iFsE8)CkbiJP+OP28;(%?!9WddQZcAid@R@`*e%3W65$g9ee`zvwb(VPO+uVBq6p z{QDR%CR(2z@?&9Obm3xPi2lzvfip`7q`_7UDD|lRS}4=bsl3xQIOi0@GSvMuDQX}* z4B^(DI<${qUhcLqO`itJU;e<%%iS+R3I^_xIV1O%sp*x~;-dn` zt$8>RnSUh#rU3{-47067W^WNwTdq-t$-U>Hj%r!GD!gLa;kV zW5g6pCqV+!q8LgrI49(}fIc5K_`FLV4_E#XZ6{<>w8wzc%V9k!!Byg5-0WY+J?1*z%9~Aj4WQr1Jsn2(G!U8fFpi(wsy@JLg^d+IB0kl89 z0@Ssqf!L9JjYKK$J=978+NO*5^C)GPH2a%4hm$HROjM|N3g9ch9kDLh*nlwqy{mVM z`P(l#>3NnK%#O8tSb(VmZrG+`dRD#=Cc1P%(y5S?*Hj5E{vg&Eiw!YV>S#7_WRDVoFxT5m=gFi4)}y5V%KT8!xbsH_rmR& zsmM?%J}K$1l8d?2+m(}2c}-G`x>CY%Y&QBJRC$sKM}zN<9{IlF@yJEG<^0={$+`Hc zDodJ)gCADJ_bD#am(c2ojXKb|j+ENJ#58PAA&pZXufrFzBwnuuo+khfMgd!DMlU#v z9|JelQO~E2;d^w!RZJbt%IANIudpKSP)cssoWhq)>({nvcfCr0=9=FAIMuZm8Eo=} z|DND}8_PB5HqG(QwDvaM@orYBZ9kCkHV*rxKTy>q7n~0emErUwLbhq;VN<2nKT&*a2Ajz z;lKBzU2i8KLV`d)Y&ae)!HcGk$dO}Or%8KF@kE@jU1h@zwpw{6p4ME|uC$Za-ERR2 ztQvL&uOZLe(k{w_+J^ng+l}~N8MP>F1Z$fLu}D-WWaeu#XduP@#8JpmH(X>rIL)k3 zyXNyTIB1(IH%S&pQ{rWaTVfB$~-;RnlY z^(y7mR>@=brI>!TrA)BQsQ={b*6$=1Eqbuu6IdhJ&$YD$08AwtNr9*J?%-WT<;O1< zPl1<@yeqfZ>@s4azqTf<=I4(kU^+^Qkstm%WM-0_VLm({jFc8`5Df2Q1Y9zMZu0^! zsO_yh2Sz9K>Jq6fkYbBZocEJ6C!SdEzYDkiEtNJs{?!tA#e|oiN+VaaAobwKef_kUup&4scD?1+}Q8)DaekkMYn-FOS{J%NY za^mmJ^n`t*1p@hF*gl#L+5wr40*(ub4J#L|@oCl~@|4UvCjHBYDQv&S zhyGMAkRO^tF_dyi&XM)4mQ;k>kj?RgRo@-?==oD+ns*>bf@&fPXF|4U0&ib2 zo~1ZdmCPWf!W9#sGP@9X$;Rc`tjbz^&JY}z{}j9bl?;VC{x)TfQH$D^WowKL&4Zx@ zdSn+QV7H(e0xRfN6aBfH)Q=@weoD?dvu6^ZS)zqb>GwMmIuS8zJfaMUQx9>%k~w34 z3}_B2Jj~u=SnJ~vZPj*)UoDi_FtT=UAb#J^b4B%R6z3H%cj-1OCjU5F$ky>By1zsg z>2A0ccp29(Y<;my|J_g-r{1I@+*O$>!R3`_sFNP4e}LD1e1mM&SA`;;TR0I`_hESV zh4U*9ecK$0=lYk`{SR_cm$}iS*?yQR(}T-5ub?Wn^#RTe*^1~ya%`!xWq-F*WH@%nnZTNREA z3eUX2uM9b_w!Zo$nVTotEtzuL(88N)H~v_G=89|(@IFz~Wq6ME);z(!2^PkR2B&kE zxR)xV8PE|Hszyjp#jNf=ZIQ7JR~4Ls#Vd@mPF(7R5VO$akUq8JM+sn>ZVg(lJZ)5qjqdw(*7tuwjY#0tx+|!sTz9yV~%HOdrb#!5w9>*0LrCS z%wF$Yc6~hqVQZzoC^D<(-h0aOtk}kn<<*xF61HQr<5}efY{zXXA+PaJG7vT&{Oz(@Uu!V#Fp9%Ht!~@;6AcD z$lvlPu&yd(YnAHfpN51*)JN0aYw9gGk{NE7!Oqu4rBp}F30669;{zcH-a7w9KSpDQPIE_f9T zit? zJSjTKWbe{f{9BmSDAFO1(K0oqB4578tU0(oRBE^28X>xDA!1C&VJEiYak4_ZTM*7M`hv_ zw3;2ndv3X$zT!wa7TrId{gNE`Vxf}j5wsyX+;Kn<^$EJT`NzznjyYx=pYMkZjizEU zb;Gg8Pl_pqxg)9P)C)Hxh_-mQ;u-I_Ol>d^>q08zFF!>Z3j1-HmuME_TGZ*Ev;O0O z%e(edJfV<6t3&FKwtInnj9EeQhq9;o5oLJoiKwWF5bP2~Feh#P4oN()JT0pdq!9x* ze3D-1%AV#{G=Op$6q?*Z>s{qFn}cl@9#m@DK_Bs@fdwSN`Qe18_WnveRB583mdMG- z?<3pJC!YljOnO8=M=|Cg)jw;4>4sna`uI>Kh&F20jNOk9HX&}Ry|mHJ+?emHnbYLJ zwfkx@slh31+3nq-9G5FVDQBHWWY}&hJ-fpDf!lQdmw8dlTt#=)20X74S>c&kR(?PT zBg)Y%)q&|hW1K;`nJPAGF*c3{3`FvrhD9=Ld{3M*K&5$jRhXNsq$0CLXINax1AmXX ziF39vkNtcK6i^+G^AEY!WalGazOQ$_#tx?BQ{YY$&V&42sICVl8@AI6yv;sGnT;@f zL=}rZcJqNwrEEA=GDdEe8Z=f9>^?($oS8xGdFf1eUWTYtZF<3tu2V%noPBnd=thZ+ zO&xoc?jvXG7Xt!RTw#5VN50UjgqSntw9Y35*~pxz=8OzkXg{@S2J%+{l3Q>B_qbnl z20Deb7JM&ZSp`%X>xWpb>FF8q7Nq&4#a1}A-(-!aMDmVbz05D!NpUzVe{~72h%cOh zwQFNai2a$K|hFgDk(oPF_tuf{BV!=m0*xqSzGAJ(~XUh8rk#{YOg0ReK>4eJl z;-~u5v$}DM)#vER>F)-}y(X6rGkp<{AkiPM7rFgAV^)FUX8XmCKKaWlS4;MSEagj$ z#pvH`vLX1q{&eOm>htnk4hmv=_)ao!MCp}9ql5yfre&Py!~hBAGNBa}PH&J8K=~<% z&?!J-QaH|0bq_uo6rt*r-M>d7jm1cbW^T>s)S?L{n8v`^?VIPA+qi^6e@cM|5boqEO!p1e|_{7U3Yl6K?0xMN1bbjf0@$TE-T))w> zFe?E?g$PUT-)AJ(PS^By^D^Ed!K5iv$*_eW~VA(I3~UMy*ZcgVu0$XZC*_0PgDmUL)qTCn927LD~p$yXR_GCJ&iQ; z4*`%l-dC5pALH!y*nmhdHRh02QjW1vZL4ySucz*w3f|#`=u@@YvMV1?i!&DIa2+S< z8z!gvN3FV4I;%fl;ruFeV{jKjI~?GlgkmGBuJ<7vY|l3xMOc?S@Q#C(zo*m&JLrjT2rU9PYOniB8O~yO5<1CCcQz# z17B2m1Z{R!Y)UO#CU-Y&mOlv4*Gz%rC_YkRcO)jTUEWHDvv!GWmEihE>OKPx1J?Av z8J{-#7NsT>>R#*7**=QL)1@IR77G9JGZZiVt!=jD+i(oRV;I`JkiTSZkAXuHm-VG1 z+2-LD!!2dNEk@1@Rp|C$MD9mH^)H*G*wI(i*Rc6Vvdik+BDycYQ*=0JA3dxxha|Zg zCIW1Ye-DdpMGTEwbA^6hVC<(@0FL4dkDOYcxxC5c%MJQ^)zpA%>>~Q|Y=@)XW!px; z_Fx+xOo7>sz4QX|Ef~igE+uFnzFWP<-#||*V0`0p7E*+n5+awuOWmvR{-M*chIXgo zYiZvQMond#{F8+4Zh_;>MsaZUuhp=onH@P!7W>sq|CWv|u}Wg0vo&f4UtmLzhCwwu zJaR=IO;sQxS}h(K>9VZjnED+>9rGgB3ks+AwTy_EYH{oc)mo`451n&YH%A1@WC{;1 z=fB6n zIYp46_&u`COM&Di?$P}pPAlAF*Ss<)2Xc?=@_2|EMO?(A1u!Vc=-%bDAP#zDiYQvJ z0}+}3GaLxsMIlh6?f=iRs0K=RyvMOcWl*xqe-IBLv?K{S^hP)@K|$I+h_)pdD9r~! zxhw2u66+F(E`&6hY}B_qe>wil|#*0R0B;<@E?L zVrhXKfwRg0l8r>LuNs1QqW&39ME0sOXe8zycivGVqUOjEWpU)h|9fwp@d(8=M-WxY zeazSz6x5e`k821fgylLIbdqx~Kdh^Oj`Q!4vc*Km)^Tr-qRxPHozdvvU^#xNsKVr6aw8={70&S4y*5xeoF@Q^y596*09`XF56-N z1=Rm5?-An178o?$ix}y7gizQ9gEmGHF5AW+92DYaOcwEHnjAr~!vI>CK%h`E_tO8L Yte!%o?r4GTrVtxD61Ym!|5fq-1K$0e!T1w z1SC8j)_dObefzK9b=~*c&wBRW>;B{VGKiBofK!FMN5oJBE0V;;!kWUz!jc1W?5KdY zyZ3mCBHprpchz-9{ASiJJh&&h1|4rdw6wxD2+9= z#6#}Uq8&^1F3wgvGFoNDo?bIeEQXpcuAR0-+w$JWoK-@yUal1M&~W_O)r+Rx;{@hWH5n^oQWR36GMYBDDZyPK4L@WVjRrF+XlSzi4X4!_!U%Uujl6LHQ#|l(sUU%{ zefYd8jnVYP91K}Qn-OmmSLYFK1h~_}RPS~>+Xdz%dpvpJ{ll!IKX=JN99qowqslbO zV3DmqPZ}6>KB!9>jEObpi$u5oGPfO3O5!o3N2Mn`ozpje<}1I1H)m2rJDcB7AwXc6 z6j)tnPiql7#)r+b+p9?MVahp&=qJ^$oG+a^C*);FoJ!+V*^W+|2Olx5{*&$bXth)U zejc7mU6cBp?^Rj|dd{GL-0eHRTBi6_yJ&GLP5kIncv^z{?=0AVy^5{S8_n=rtua!J zFGY=A(yV^ZhB}1J_y(F`3QTu+zkHlw;1GiFeP&pw0N1k%NShHlO(4W+(!wy5phcg4 zA-|}(lE_1@@e6y`veg;v7m;q%(PFG&K3#}eRhJioXUU0jg_8{kn$;KVwf;zpL2X_( zC*_R#5*PaBaY73(x*oZ}oE#HPLJQRQ7brNK=v!lsu==lSG1(&q>F)`adBT~d*lMS| z%!%7(p~<7kWNmpZ5-N31*e=8`kih|g5lVrI%2wnLF-2D+G4k6@FrYsJ_80AJ}KMRi>) z-kIeHp{maorNWkF81v0FKgB==_6blyaF$5GaW)B!i4v*jNk6r)vU6?G$0pV8(Y+UK z5lgRVt%;N_gWp)^osv=h+^07UY6+$4^#t=M3>0i0`{`aEkFLL#a)93uXhYO+aKTtu zckg2T9S&GKNtZmdAS^8PzvDva-%-K&g9eqPXQ4$dM^inr@6Zl z{!Cq&C_+V;g*{>!0cZP}?ogDb$#ZS=n@NHE{>k@84lOkl&$Bt2NF)W%GClViJq14_ zQIfa^q+0aq){}CO8j%g%R9|;G0uJuND*HO$2i&U_uW_a5xJ33~(Vy?;%6_(2_Cuq1 zLhThN@xH7-BaNtkKTn^taQHrs$<<)euc6z(dhps>SM;^Wx=7;O&IfNVJq3wk4<1VS z-`*7W4DR_i^W4=dRh>AXi~J$K>`UqP>CKVVH&+T(ODhRJZO7DScU$F7D)di-%^8?O z6)Ux`zdrVOe1GNkPo0FgrrxSu1AGQkJe@pqu}8LkBDm+V!N_1l}`tjLW8${rgDLv3m@E*#zappt-Mm zSC<$o+6UO~w0C=(0$&*y**@nKe_Q{|eAuD!(0YL0_a{z%+sdfSyP={Nyd$re6Rzbp zvsgTY7~VflX0^Vf7qqomYZ_$ryrFVV2$sFyzw2r%Q8*uYDA+)iQdfKms_5(>!s#!( z!P5S(N0i9CKQKaqg(U%Gk#V3*?)lO6dLv`8KB~F<-%VhbtL8Rl>mEz+PN=qx&t*|= zQHV=qG)YKlPk4iCyWIUGjC?kpeA>hIBK*A?B0)rB=RqAal#D%1C9yVQwBcz${#Jb5 zR{TRmMrOrJsLc&6x9qDo@FJ^=do_Y?3oU0G^nV5_EU&+DS+VA7Tp{^TAF>yZbyM3c zf*1CqHY9T|aL_lyY7c)i!_MtGPA!sdy3|mrsKVj1mi&>dms@-ozSa}OZ?2I*tAndg z@S7er$t^d^-;!wLQbG60nWd@1pQVD7tw-G_B#OscoYyremiZ_hj8*sXqQdchuD^!R zpXGuSj5psk+jR>3rWu3^`17>j&*^9^rWbszP=Mf@5KIEj%b=z98v=Ymp%$FYt>%Ld zm8})EDbNOJu9n)gwhz_RS``#Ag)fr)3<*?(!9O~mTQWeh;8c;0@o=iBLQNqx3d_2#W7S9#FXzr6VXfs>4 z;QXw}-STvK9_-7H=uqgal2{GkbjVLN+=D5ddd)4^WvX;(NYA*X*(JxTdiUzqVJopd zQg#~psX4o<)cF>r=rxP`(Xsf<+HG-pf&7aFPL8z|-&B*P?Vmsu5d>Nlg^2$WRY!S@#`g2{81;(1w#o5HsvN}5pFZi});>|VK^kL{Zkx~wgn ztlZp;HW`H8(GdRfIwc~?#N6}o#h158ohI*GIsK%56I_9sf2k_K@4vD!l{(dX9E7PJ;w>$|Y;-VBJSO4@){07bo-89^LZ9g<<%;dOl zyIq{s8`8Ltp*GDwu(l_Z$6sA2nam$BM$Q~6TpZg)w2TtW?G5whV(lRwaf$6EU86is zBP9Rs&vS_~sk?Nn_b}^HkM8LiO@>J}=g(T4hLmvH@5Jj#2aHa~K)lD9VB0k>$V2BP zgh;(=y9Op(KQ=H5vj+%qs>?s4tYN~-Q|fyQePA)s?HrF~;l!+@t8VMzqUpqMLudFT z)=o~s!MM4XkgbetIsODwtQ=FF$IcIp&!pjh6Q6{tL+l*7GQ%8Wsg(tC#qU3oW$~n) zL=>XIxI}Hi7HS0F_mmi+(c%1HDuKiWm>|6Xa}nW7ei55ggru9)xjBvC#JcEIN*#cp zv*ACvr=HTC?dX9NNo9Yhulu_gX5Z~}QQ2&QZ&C77{(>Y3_ z6j5Z1Uc5FtPEpS_31HsgmSLHZijGb_p$WlRJ1p^_1!ZLP8kr6OtCEK7Qh267o$H>e zf<4cNGQRk{g5h$XfvTFQ@`qm@iju83-~}ebAYpZryARHVR$AEt3229U{y@Fp4 z-8FBBtGG&(hTyUdx5ZOfiz`c=<0F%+w|Fl=rWk{K7>70k04SN?RU(^mrKSeKDqA!K^Hsv8C?#ioj4@WUL zC*?{hTai6q0%_oBTqDHygp_Kl;({sAScYQIwMDM1U>{x0ww zve?_}E;DG?+|zsUrsph5X_G7l#Y~vqkq3@NNDabbw7|`eJBmn`Qrlr%?`va=mm$Mc{+FBbQbogAZ6{MuzT|P%QZZotd21eb1hfj|;GYAX&>bx#D5EB+=XMj2XJkpnyMUykaVo) zj3ZLqEl1&)Rturc8m@+uUuD^vaNaSxGwP4dq0-OSb~62lPv8E_K4usLvG{Qg zdR%z8dd2H!{JaT|X_bfm{##*W$YM;_J8Y8&Z)*ImOAf4+| zEyi)qK%Ld1bHuqD+}-WiCnjszDeC-%8g+8JRpG1bOc!xUGB?@?6f~FTrI%U#5R~YF z%t5(S2Q>?0`(XNHa8xKdTEZ~Z4SJOheit#ldfdg63}#W6j8kO;SjQD`vftxS+#x1B zYu|5szEvkyz|}|B3x|DNlyi$;+n+cW$Hu+?)=X1!sa%{H-^;oBO9XACZJ}wkQ!sTa zQ#J3h|HX{{&WwIG3h7d6aWktuJaO)ie6&=KJBoX@w(rBWfin`*a6OmCC5M0HzL(gv zY<*e4hmW>SWVhxk-`UGOAbD%Hk+uu<^7zJ_ytVXamfqCd0$g+W08>?QAB}Cv{b}eM z@X}ILg+uT%>-6`A25p@uhS3%;u>ccSq}8|H_^o&`nBT5S0y z;2H0I^(4MO*S+(4l$gULc4KSeKvidto5Nl0P|%9CqQ*ikY!w_GUlo}sb9HYB=L^oFpJ zfTQskXW!LFVnUo4(OHPDaZSf3zB|3{RGu1>ueE$(+dr?tT zp!SGlqDU8vu{5xLWSvj+j$arHglg54#Lx&TvuO3LIIU>hF9Uoj&=-b*Q?uYr`#V?xz?2 zhirZrv^eA{k%{hFh%9LYVXEYWd5#PuUd1QqaqB*J!CMXEM>fEB$@#1>mtB`Bfil}t zhhTIObqh5HRvT+4q_Do$Q*Jika?qV=Np-DtPkU z(KoXyWLfPwr@UY1)hBAvR3nCBZgd|CevTG?H~HqDF}dzy%2sd2`f{^CBbTk*^K~RO zN~O0+2EjAJlywF%SjgYz810l&G5AqzI<=Ber{912^PpSPRJl3dm8W@dKHL}7_@k3)Y!SXYkyxQy>Q4I2o zr`ev7fLF$1t96h|sH<-#*YzGD-b^3$_!#wsh(Yw;)b@udLz9mm`mFYh z1Zz24KIQJ(*_-E0(3&1InqG;U?wF)GYd>DFo(em`#|UaaYmkA9;GTX7b?0@C@QkTVpGD#mf$dQoRNV=n{^Zi_W*ps;3?^$s`0;ER7;==~OmQ~9 zS5P=FjxE5%|;xq6h4@!_h?@|aK&FYI2IT(OHXv2%1 zWEo-v!L7x^YT(xLVHlpJttcwaF@1Y;-S*q3CRa!g7xdzl|Jan>2#dI0`LKl!T1GMk zRKe4|bQO&ET}Z^Aiym*HII>cSxIzl|F~JEUGxz;+DB=8fxXhnBI4R12q6ews$lA`Jfi}r@A@-)6TOAUMNYFYJ zZ-Zd?lxFTyjN3mXnL!%#>Z%$0gJ4*9g;e;@zSmQ{eGGDaRRNM3s@6!;hYuVc=c+3B z=qzNNS~n^EsJU4aOGE|mdy={C^lPKEfPL-IJAsTpQsDgZ@~s+eHZYmp9yb=YW_4r?lqQaYZQ`nau){W`LY#P)>i zq^wHEuOYs#FlPZeMuT@Etb@~A6feCebq`miJE3w+gAL%bVF_s*5e*@)?xmKSo%I3? zLELHVdWia$}~s6 zr!^LfxSSB4Td&9iTXrzQpl5ZDo#SdmNr;23QsPHQ!x!UT9xtb!Ycz^JF8x)%cFOXK z^EXw%dRz_VD}7?RU^4{)1+xFO=z!EI8IUa3U*rag=1BpHX$Xi<__kSbS{y_xa*MJv z_`thq0Z^sPzjAk48ssDQj}!$N8Q$XC84(bU$t_Bm69Jf+C!h_}ep zwzpQj9sRA94<{x3{~z&ix-DwX;RAzka)4-#6ZHJqKh|SVuO|>Yrv+m30+!|sK<-|E z=)5E->#y<_1V|T1f%Af!ZYqXg}`O zI$qKOWdnclF`%_Z`WGOe{`A`l-#a?s=Q1a#@BOWmExH2;Wl`OB!B-%lq3nO{4=WO& z#k_x|N&(qzm*6S{G*|GCegF2N2ulC+(58z2DG~yUs}i8zvRf&$CJCaexJ6Xu!`qz( z)*v8*kAE#D0KCo*s{8^Rbg=`*E2MzeIt0|x55%n-gO&yX#$l=3W7-_~&(G8j1E(XB hw}tl`5K!1C(72%nnjQrp<7@!WCh47rWB+@R{{wClNUHz< diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6c9a22477..12d38de6a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c5158..4f906e0c8 100755 --- a/gradlew +++ b/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index a9f778a7a..ac1b06f93 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 60af521d15ddf06757e43746d67c7b11ee1c0d2e Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 4 Sep 2020 12:09:57 +0200 Subject: [PATCH 21/28] Extract minimum required coverage by Jacoco plugin. (#541) --- buildSrc/src/main/java/Config.kt | 6 ++++++ sentry-core/build.gradle.kts | 5 ++--- sentry-log4j2/build.gradle.kts | 4 ++-- sentry-logback/build.gradle.kts | 4 ++-- sentry-spring-boot-starter/build.gradle.kts | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 9246dbb3d..5b2d0f833 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,3 +1,5 @@ +import java.math.BigDecimal + object Config { val kotlinVersion = "1.3.72" val kotlinStdLib = "stdlib-jdk8" @@ -72,6 +74,10 @@ object Config { } object QualityPlugins { + object Jacoco { + val version = "0.8.5" + val minimumCoverage = BigDecimal.valueOf(0.6) + } val jacocoVersion = "0.8.5" val spotless = "com.diffplug.spotless" val spotlessVersion = "5.1.0" diff --git a/sentry-core/build.gradle.kts b/sentry-core/build.gradle.kts index 58bb6468a..389a41d48 100644 --- a/sentry-core/build.gradle.kts +++ b/sentry-core/build.gradle.kts @@ -43,7 +43,7 @@ configure { } jacoco { - toolVersion = Config.QualityPlugins.jacocoVersion + toolVersion = Config.QualityPlugins.Jacoco.version } tasks.jacocoTestReport { @@ -56,8 +56,7 @@ tasks.jacocoTestReport { tasks { jacocoTestCoverageVerification { violationRules { - // TODO: Raise the minimum to a sensible value. - rule { limit { minimum = BigDecimal.valueOf(0.1) } } + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } } } check { diff --git a/sentry-log4j2/build.gradle.kts b/sentry-log4j2/build.gradle.kts index f2c4408c7..65f45d222 100644 --- a/sentry-log4j2/build.gradle.kts +++ b/sentry-log4j2/build.gradle.kts @@ -44,7 +44,7 @@ configure { } jacoco { - toolVersion = Config.QualityPlugins.jacocoVersion + toolVersion = Config.QualityPlugins.Jacoco.version } tasks.jacocoTestReport { @@ -57,7 +57,7 @@ tasks.jacocoTestReport { tasks { jacocoTestCoverageVerification { violationRules { - rule { limit { minimum = BigDecimal.valueOf(0.6) } } + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } } } check { diff --git a/sentry-logback/build.gradle.kts b/sentry-logback/build.gradle.kts index 7b42bdd29..92e6c6926 100644 --- a/sentry-logback/build.gradle.kts +++ b/sentry-logback/build.gradle.kts @@ -43,7 +43,7 @@ configure { } jacoco { - toolVersion = Config.QualityPlugins.jacocoVersion + toolVersion = Config.QualityPlugins.Jacoco.version } tasks.jacocoTestReport { @@ -56,7 +56,7 @@ tasks.jacocoTestReport { tasks { jacocoTestCoverageVerification { violationRules { - rule { limit { minimum = BigDecimal.valueOf(0.6) } } + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } } } check { diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts index 100ea7aee..24e556c71 100644 --- a/sentry-spring-boot-starter/build.gradle.kts +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -63,7 +63,7 @@ configure { } jacoco { - toolVersion = Config.QualityPlugins.jacocoVersion + toolVersion = Config.QualityPlugins.Jacoco.version } tasks.jacocoTestReport { @@ -76,7 +76,7 @@ tasks.jacocoTestReport { tasks { jacocoTestCoverageVerification { violationRules { - rule { limit { minimum = BigDecimal.valueOf(0.6) } } + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } } } check { From 923f9fc175c0548b13f210c51322672be3cce4ba Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 8 Sep 2020 20:49:10 +0200 Subject: [PATCH 22/28] Add Spring Integration. (#539) --- buildSrc/src/main/java/Config.kt | 8 +- .../main/java/io/sentry/core/Breadcrumb.java | 16 ++ ...DuplicateEventDetectionEventProcessor.java | 75 ++++++++ .../java/io/sentry/core/SentryOptions.java | 1 + .../java/io/sentry/core/BreadcrumbTest.kt | 9 + ...plicateEventDetectionEventProcessorTest.kt | 70 ++++++++ .../build.gradle.kts | 11 +- .../spring/boot/CustomEventProcessor.java | 35 ++++ .../io/sentry/samples/spring/boot/Person.java | 24 +++ .../samples/spring/boot/PersonController.java | 28 +++ .../spring/boot/SecurityConfiguration.java | 60 +++++++ .../{ => boot}/SentryDemoApplication.java | 3 +- .../src/main/resources/application.properties | 2 + .../src/main/resources/logback.xml | 4 +- .../sentry-samples-spring/build.gradle.kts | 41 +++++ .../java/io/sentry/samples/spring/Person.java | 0 .../samples/spring/PersonController.java | 1 + .../samples/spring/SecurityConfiguration.java | 2 +- .../samples/spring/SentryDemoApplication.java | 17 ++ .../src/main/resources/logback.xml | 14 ++ sentry-spring-boot-starter/build.gradle.kts | 7 +- .../spring/boot/SentryAutoConfiguration.java | 26 +-- .../boot/SentrySpringIntegrationTest.kt | 27 ++- sentry-spring/build.gradle.kts | 118 +++++++++++++ .../java/io/sentry/spring/EnableSentry.java | 32 ++++ .../spring/SentryExceptionResolver.java | 55 ++++++ .../io/sentry/spring/SentryHubRegistrar.java | 73 ++++++++ .../spring/SentryInitBeanPostProcessor.java | 21 +++ .../sentry/spring}/SentryRequestFilter.java | 17 +- ...tryRequestHttpServletRequestProcessor.java | 7 +- .../sentry/spring}/SentrySecurityFilter.java | 7 +- ...SentryUserHttpServletRequestProcessor.java | 2 +- .../sentry/spring/SentryWebConfiguration.java | 25 +++ .../io/sentry/spring/EnableSentryTest.kt | 78 +++++++++ ...yRequestHttpServletRequestProcessorTest.kt | 2 +- .../spring/SentrySpringIntegrationTest.kt | 163 ++++++++++++++++++ ...ntryUserHttpServletRequestProcessorTest.kt | 2 +- settings.gradle.kts | 2 + 38 files changed, 1036 insertions(+), 49 deletions(-) create mode 100644 sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java create mode 100644 sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/Person.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/PersonController.java create mode 100644 sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java rename sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/{ => boot}/SentryDemoApplication.java (88%) create mode 100644 sentry-samples/sentry-samples-spring/build.gradle.kts rename sentry-samples/{sentry-samples-spring-boot => sentry-samples-spring}/src/main/java/io/sentry/samples/spring/Person.java (100%) rename sentry-samples/{sentry-samples-spring-boot => sentry-samples-spring}/src/main/java/io/sentry/samples/spring/PersonController.java (94%) rename sentry-samples/{sentry-samples-spring-boot => sentry-samples-spring}/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java (97%) create mode 100644 sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java create mode 100644 sentry-samples/sentry-samples-spring/src/main/resources/logback.xml create mode 100644 sentry-spring/build.gradle.kts create mode 100644 sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java rename {sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot => sentry-spring/src/main/java/io/sentry/spring}/SentryRequestFilter.java (68%) rename {sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot => sentry-spring/src/main/java/io/sentry/spring}/SentryRequestHttpServletRequestProcessor.java (92%) rename {sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot => sentry-spring/src/main/java/io/sentry/spring}/SentrySecurityFilter.java (90%) rename {sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot => sentry-spring/src/main/java/io/sentry/spring}/SentryUserHttpServletRequestProcessor.java (97%) create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java create mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt rename {sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot => sentry-spring/src/test/kotlin/io/sentry/spring}/SentryRequestHttpServletRequestProcessorTest.kt (99%) create mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt rename {sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot => sentry-spring/src/test/kotlin/io/sentry/spring}/SentryUserHttpServletRequestProcessorTest.kt (98%) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 5b2d0f833..766b91e89 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -48,6 +48,9 @@ object Config { val log4j2Core = "org.apache.logging.log4j:log4j-core:$log4j2Version" val springBootStarter = "org.springframework.boot:spring-boot-starter:$springBootVersion" + val springBootStarterTest = "org.springframework.boot:spring-boot-starter-test:$springBootVersion" + val springBootStarterWeb = "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + val springBootStarterSecurity = "org.springframework.boot:spring-boot-starter-security:$springBootVersion" val springWeb = "org.springframework:spring-webmvc" val servletApi = "javax.servlet:javax.servlet-api" @@ -68,9 +71,6 @@ object Config { val robolectric = "org.robolectric:robolectric:4.3.1" val mockitoKotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" val awaitility = "org.awaitility:awaitility-kotlin:4.0.3" - val springBootStarterTest = "org.springframework.boot:spring-boot-starter-test:$springBootVersion" - val springBootStarterWeb = "org.springframework.boot:spring-boot-starter-web:$springBootVersion" - val springBootStarterSecurity = "org.springframework.boot:spring-boot-starter-security:$springBootVersion" } object QualityPlugins { @@ -78,7 +78,6 @@ object Config { val version = "0.8.5" val minimumCoverage = BigDecimal.valueOf(0.6) } - val jacocoVersion = "0.8.5" val spotless = "com.diffplug.spotless" val spotlessVersion = "5.1.0" val errorProne = "net.ltgt.errorprone" @@ -95,6 +94,7 @@ object Config { val SENTRY_ANDROID_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.android" val SENTRY_LOGBACK_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.logback" val SENTRY_LOG4J2_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.log4j2" + val SENTRY_SPRING_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring" val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot" val group = "io.sentry" val description = "SDK for sentry.io" diff --git a/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java b/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java index cfe7c8f35..d990e4daf 100644 --- a/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java +++ b/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java @@ -43,6 +43,22 @@ public final class Breadcrumb implements Cloneable, IUnknownPropertiesConsumer { this.timestamp = timestamp; } + /** + * Creates HTTP breadcrumb. + * + * @param url - the request URL + * @param method - the request method + * @return the breadcrumb + */ + public static @NotNull Breadcrumb http(final @NotNull String url, final @NotNull String method) { + final Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setType("http"); + breadcrumb.setCategory("http"); + breadcrumb.setData("url", url); + breadcrumb.setData("method", method.toUpperCase(Locale.getDefault())); + return breadcrumb; + } + /** Breadcrumb ctor */ public Breadcrumb() { this(DateUtils.getCurrentDateTimeOrNull()); diff --git a/sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java b/sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java new file mode 100644 index 000000000..e62824128 --- /dev/null +++ b/sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java @@ -0,0 +1,75 @@ +package io.sentry.core; + +import io.sentry.core.exception.ExceptionMechanismException; +import io.sentry.core.util.Objects; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Deduplicates events containing throwable that has been already processed. */ +public final class DuplicateEventDetectionEventProcessor implements EventProcessor { + private final WeakHashMap capturedObjects = new WeakHashMap<>(); + private final SentryOptions options; + + public DuplicateEventDetectionEventProcessor(final @NotNull SentryOptions options) { + this.options = Objects.requireNonNull(options, "options are required"); + } + + @Override + public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) { + final Throwable throwable = event.getThrowable(); + if (throwable != null) { + if (throwable instanceof ExceptionMechanismException) { + final ExceptionMechanismException ex = (ExceptionMechanismException) throwable; + if (capturedObjects.containsKey(ex.getThrowable())) { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Duplicate Exception detected. Event %s will be discarded.", + event.getEventId()); + return null; + } else { + capturedObjects.put(ex.getThrowable(), null); + } + } else { + if (capturedObjects.containsKey(throwable) + || containsAnyKey(capturedObjects, allCauses(throwable))) { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Duplicate Exception detected. Event %s will be discarded.", + event.getEventId()); + return null; + } else { + capturedObjects.put(throwable, null); + } + } + } + return event; + } + + private static boolean containsAnyKey( + final @NotNull Map map, final @NotNull List list) { + for (T entry : list) { + if (map.containsKey(entry)) { + return true; + } + } + return false; + } + + private static @NotNull List allCauses(final @NotNull Throwable throwable) { + final List causes = new ArrayList<>(); + Throwable ex = throwable; + while (ex.getCause() != null) { + causes.add(ex.getCause()); + ex = ex.getCause(); + } + return causes; + } +} diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java index 7c10b1702..21cbb10b5 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryOptions.java @@ -1047,6 +1047,7 @@ public SentryOptions() { integrations.add(new ShutdownHookIntegration()); eventProcessors.add(new MainEventProcessor(this)); + eventProcessors.add(new DuplicateEventDetectionEventProcessor(this)); setSentryClientName(BuildConfig.SENTRY_JAVA_SDK_NAME + "/" + BuildConfig.VERSION_NAME); setSdkVersion(createSdkVersion()); diff --git a/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt b/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt index d38ef8966..f7a2a9258 100644 --- a/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt @@ -98,4 +98,13 @@ class BreadcrumbTest { val breadcrumb = Breadcrumb("this is a test") assertEquals("this is a test", breadcrumb.message) } + + @Test + fun `creates HTTP breadcrumb`() { + val breadcrumb = Breadcrumb.http("http://example.com", "POST") + assertEquals("http://example.com", breadcrumb.data["url"]) + assertEquals("POST", breadcrumb.data["method"]) + assertEquals("http", breadcrumb.type) + assertEquals("http", breadcrumb.category) + } } diff --git a/sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt b/sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt new file mode 100644 index 000000000..3867fd5f5 --- /dev/null +++ b/sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt @@ -0,0 +1,70 @@ +package io.sentry.core + +import io.sentry.core.exception.ExceptionMechanismException +import io.sentry.core.protocol.Mechanism +import java.lang.RuntimeException +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class DuplicateEventDetectionEventProcessorTest { + + val processor = DuplicateEventDetectionEventProcessor(SentryOptions()) + + @Test + fun `does not drop event if no previous event with same exception was processed`() { + processor.process(SentryEvent(), null) + + val result = processor.process(SentryEvent(RuntimeException()), null) + + assertNotNull(result) + } + + @Test + fun `drops event with the same exception`() { + val event = SentryEvent(RuntimeException()) + processor.process(event, null) + + val result = processor.process(event, null) + assertNull(result) + } + + @Test + fun `drops event with mechanism exception having an exception that has already been processed`() { + val event = SentryEvent(RuntimeException()) + processor.process(event, null) + + val result = processor.process(SentryEvent(ExceptionMechanismException(Mechanism(), event.throwable, null)), null) + assertNull(result) + } + + @Test + fun `drops event with exception that has already been processed with event with mechanism exception`() { + val sentryEvent = SentryEvent(ExceptionMechanismException(Mechanism(), RuntimeException(), null)) + processor.process(sentryEvent, null) + + val result = processor.process(SentryEvent((sentryEvent.throwable as ExceptionMechanismException).throwable), null) + + assertNull(result) + } + + @Test + fun `drops event with the cause equal to exception in already processed event`() { + val event = SentryEvent(RuntimeException()) + processor.process(event, null) + + val result = processor.process(SentryEvent(RuntimeException(event.throwable)), null) + + assertNull(result) + } + + @Test + fun `drops event with any of the causes has been already processed`() { + val event = SentryEvent(RuntimeException()) + processor.process(event, null) + + val result = processor.process(SentryEvent(RuntimeException(RuntimeException(event.throwable))), null) + + assertNull(result) + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts index 9676cdb87..e342bf150 100644 --- a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -16,14 +17,14 @@ repositories { } dependencies { - implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter") + implementation(Config.Libs.springBootStarterSecurity) + implementation(Config.Libs.springBootStarterWeb) + implementation(Config.Libs.springBootStarter) implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation(kotlin(Config.kotlinStdLib, KotlinCompilerVersion.VERSION)) implementation(project(":sentry-spring-boot-starter")) implementation(project(":sentry-logback")) - testImplementation("org.springframework.boot:spring-boot-starter-test") { + testImplementation(Config.Libs.springBootStarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } } diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java new file mode 100644 index 000000000..40d17a1c6 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java @@ -0,0 +1,35 @@ +package io.sentry.samples.spring.boot; + +import io.sentry.core.EventProcessor; +import io.sentry.core.SentryEvent; +import io.sentry.core.protocol.SentryRuntime; +import org.jetbrains.annotations.Nullable; +import org.springframework.stereotype.Component; + +/** + * Custom {@link EventProcessor} implementation lets modifying {@link SentryEvent}s before they are + * sent to Sentry. + */ +@Component +public class CustomEventProcessor implements EventProcessor { + private final String javaVersion; + private final String javaVendor; + + public CustomEventProcessor(String javaVersion, String javaVendor) { + this.javaVersion = javaVersion; + this.javaVendor = javaVendor; + } + + public CustomEventProcessor() { + this(System.getProperty("java.version"), System.getProperty("java.vendor")); + } + + @Override + public SentryEvent process(SentryEvent event, @Nullable Object hint) { + final SentryRuntime runtime = new SentryRuntime(); + runtime.setVersion(javaVersion); + runtime.setName(javaVendor); + event.getContexts().setRuntime(runtime); + return event; + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/Person.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/Person.java new file mode 100644 index 000000000..2a2177d46 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/Person.java @@ -0,0 +1,24 @@ +package io.sentry.samples.spring.boot; + +public class Person { + private final String firstName; + private final String lastName; + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + @Override + public String toString() { + return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/PersonController.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/PersonController.java new file mode 100644 index 000000000..7ee2e4604 --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/PersonController.java @@ -0,0 +1,28 @@ +package io.sentry.samples.spring.boot; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/person/") +public class PersonController { + private static final Logger LOGGER = LoggerFactory.getLogger(PersonController.class); + + @GetMapping("{id}") + Person person(@PathVariable Long id) { + LOGGER.info("Loading person with id={}", id); + throw new IllegalArgumentException("Something went wrong [id=" + id + "]"); + } + + @PostMapping + Person create(@RequestBody Person person) { + LOGGER.warn("Creating person: {}", person); + return person; + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java new file mode 100644 index 000000000..417f0541d --- /dev/null +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java @@ -0,0 +1,60 @@ +package io.sentry.samples.spring.boot; + +import io.sentry.core.IHub; +import io.sentry.core.SentryOptions; +import io.sentry.spring.SentrySecurityFilter; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final @NotNull IHub hub; + private final @NotNull SentryOptions options; + + public SecurityConfiguration(final @NotNull IHub hub, final @NotNull SentryOptions options) { + this.hub = hub; + this.options = options; + } + + // this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed. + @Override + @SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]") + protected void configure(final @NotNull HttpSecurity http) throws Exception { + // register SentrySecurityFilter to attach user information to SentryEvents + http.addFilterAfter(new SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter.class) + .csrf() + .disable() + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + } + + @Bean + @Override + public @NotNull UserDetailsService userDetailsService() { + final PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); + + final UserDetails user = + User.builder() + .passwordEncoder(encoder::encode) + .username("user") + .password("password") + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SentryDemoApplication.java similarity index 88% rename from sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java rename to sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SentryDemoApplication.java index 43882fe6c..14e57e0cc 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SentryDemoApplication.java @@ -1,11 +1,10 @@ -package io.sentry.samples.spring; +package io.sentry.samples.spring.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SentryDemoApplication { - public static void main(String[] args) { SpringApplication.run(SentryDemoApplication.class, args); } diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties index 9f28892b0..84b7ca93c 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties +++ b/sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties @@ -1,3 +1,5 @@ # NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry project/dashboard sentry.dsn=https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954 sentry.send-default-pii=true +# Sentry Spring Boot integration allows more fine-grained SentryOptions configuration +sentry.max-breadcrumbs=150 diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml b/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml index fe050c21c..26c88f349 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml +++ b/sentry-samples/sentry-samples-spring-boot/src/main/resources/logback.xml @@ -4,9 +4,7 @@ - - WARN - + WARN diff --git a/sentry-samples/sentry-samples-spring/build.gradle.kts b/sentry-samples/sentry-samples-spring/build.gradle.kts new file mode 100644 index 000000000..dce35dcd2 --- /dev/null +++ b/sentry-samples/sentry-samples-spring/build.gradle.kts @@ -0,0 +1,41 @@ +import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id(Config.BuildPlugins.springBoot) version Config.springBootVersion + id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion + kotlin("jvm") + kotlin("plugin.spring") version Config.kotlinVersion +} + +group = "io.sentry.sample.spring" +version = "0.0.1-SNAPSHOT" +java.sourceCompatibility = JavaVersion.VERSION_1_8 + +repositories { + mavenCentral() +} + +dependencies { + implementation(Config.Libs.springBootStarterSecurity) + implementation(Config.Libs.springBootStarterWeb) + implementation(Config.Libs.springBootStarter) + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation(kotlin(Config.kotlinStdLib, KotlinCompilerVersion.VERSION)) + implementation(project(":sentry-spring")) + implementation(project(":sentry-logback")) + testImplementation(Config.Libs.springBootStarterTest) { + exclude(group = "org.junit.vintage", module = "junit-vintage-engine") + } +} + +tasks.withType { + useJUnitPlatform() +} + +tasks.withType { + kotlinOptions { + freeCompilerArgs = listOf("-Xjsr305=strict") + jvmTarget = JavaVersion.VERSION_1_8.toString() + } +} diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/Person.java similarity index 100% rename from sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/Person.java rename to sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/Person.java diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/PersonController.java similarity index 94% rename from sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java rename to sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/PersonController.java index 9a2d97316..98aa10c0e 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/PersonController.java +++ b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/PersonController.java @@ -16,6 +16,7 @@ public class PersonController { @GetMapping("{id}") Person person(@PathVariable Long id) { + LOGGER.info("Loading person with id={}", id); throw new IllegalArgumentException("Something went wrong [id=" + id + "]"); } diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java similarity index 97% rename from sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java rename to sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java index 5d8173881..7c3c87acf 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java +++ b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java @@ -2,7 +2,7 @@ import io.sentry.core.IHub; import io.sentry.core.SentryOptions; -import io.sentry.spring.boot.SentrySecurityFilter; +import io.sentry.spring.SentrySecurityFilter; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java new file mode 100644 index 000000000..cf87d72aa --- /dev/null +++ b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SentryDemoApplication.java @@ -0,0 +1,17 @@ +package io.sentry.samples.spring; + +import io.sentry.spring.EnableSentry; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry +// project/dashboard +@EnableSentry( + dsn = "https://f7f320d5c3a54709be7b28e0f2ca7081@sentry.io/1808954", + sendDefaultPii = true) +public class SentryDemoApplication { + public static void main(String[] args) { + SpringApplication.run(SentryDemoApplication.class, args); + } +} diff --git a/sentry-samples/sentry-samples-spring/src/main/resources/logback.xml b/sentry-samples/sentry-samples-spring/src/main/resources/logback.xml new file mode 100644 index 000000000..26c88f349 --- /dev/null +++ b/sentry-samples/sentry-samples-spring/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + + WARN + + + + + + + diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts index 24e556c71..145b21a81 100644 --- a/sentry-spring-boot-starter/build.gradle.kts +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -33,6 +33,7 @@ tasks.withType().configureEach { dependencies { api(project(":sentry-core")) + api(project(":sentry-spring")) implementation(Config.Libs.springBootStarter) implementation(Config.Libs.springWeb) implementation(Config.Libs.servletApi) @@ -50,9 +51,9 @@ dependencies { testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation(Config.TestLibs.mockitoKotlin) - testImplementation(Config.TestLibs.springBootStarterTest) - testImplementation(Config.TestLibs.springBootStarterWeb) - testImplementation(Config.TestLibs.springBootStarterSecurity) + testImplementation(Config.Libs.springBootStarterTest) + testImplementation(Config.Libs.springBootStarterWeb) + testImplementation(Config.Libs.springBootStarterSecurity) testImplementation(Config.TestLibs.awaitility) } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index 4f768765d..67eacc224 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -10,6 +10,8 @@ import io.sentry.core.protocol.SdkVersion; import io.sentry.core.transport.ITransport; import io.sentry.core.transport.ITransportGate; +import io.sentry.spring.SentryWebConfiguration; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -17,10 +19,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.info.GitProperties; -import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; +import org.springframework.context.annotation.Import; @Configuration @ConditionalOnProperty(name = "sentry.dsn") @@ -39,15 +40,15 @@ static class HubConfiguration { final @NotNull ObjectProvider beforeSendCallback, final @NotNull ObjectProvider beforeBreadcrumbCallback, - final @NotNull ObjectProvider eventProcessors, - final @NotNull ObjectProvider integrations, + final @NotNull List eventProcessors, + final @NotNull List integrations, final @NotNull ObjectProvider transportGate, final @NotNull ObjectProvider transport) { return options -> { beforeSendCallback.ifAvailable(options::setBeforeSend); beforeBreadcrumbCallback.ifAvailable(options::setBeforeBreadcrumb); - eventProcessors.stream().forEach(options::addEventProcessor); - integrations.stream().forEach(options::addIntegration); + eventProcessors.forEach(options::addEventProcessor); + integrations.forEach(options::addIntegration); transportGate.ifAvailable(options::setTransportGate); transport.ifAvailable(options::setTransport); }; @@ -75,18 +76,9 @@ static class HubConfiguration { /** Registers beans specific to Spring MVC. */ @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) + @Import(SentryWebConfiguration.class) @Open - static class SentryWebMvcConfiguration { - - @Bean - public @NotNull FilterRegistrationBean sentryRequestFilter( - final @NotNull IHub sentryHub, final @NotNull SentryOptions sentryOptions) { - FilterRegistrationBean filterRegistrationBean = - new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub, sentryOptions)); - filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); - return filterRegistrationBean; - } - } + static class SentryWebMvcConfiguration {} private static @NotNull SdkVersion createSdkVersion( final @NotNull SentryOptions sentryOptions) { diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt index e5d0cd1ee..eb1fc3340 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -6,7 +6,10 @@ import io.sentry.core.IHub import io.sentry.core.Sentry import io.sentry.core.SentryEvent import io.sentry.core.SentryOptions +import io.sentry.core.exception.ExceptionMechanismException import io.sentry.core.transport.ITransport +import io.sentry.spring.SentrySecurityFilter +import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await import org.junit.Test @@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController @RunWith(SpringRunner::class) @SpringBootTest( classes = [App::class], - webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["sentry.dsn=http://key@localhost/proj", "sentry.send-default-pii=true"] ) class SentrySpringIntegrationTest { @@ -83,6 +86,23 @@ class SentrySpringIntegrationTest { }) } } + + @Test + fun `sends events for unhandled exceptions`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + + restTemplate.getForEntity("http://localhost:$port/throws", String::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.throwable).isNotNull() + assertThat(event.throwable).isInstanceOf(ExceptionMechanismException::class.java) + val ex = event.throwable as ExceptionMechanismException + assertThat(ex.throwable.message).isEqualTo("something went wrong") + assertThat(ex.exceptionMechanism.isHandled).isFalse() + }) + } + } } @SpringBootApplication @@ -95,6 +115,11 @@ class HelloController { fun hello() { Sentry.captureMessage("hello") } + + @GetMapping("/throws") + fun throws() { + throw RuntimeException("something went wrong") + } } @Configuration diff --git a/sentry-spring/build.gradle.kts b/sentry-spring/build.gradle.kts new file mode 100644 index 000000000..7ec722c93 --- /dev/null +++ b/sentry-spring/build.gradle.kts @@ -0,0 +1,118 @@ +import com.novoda.gradle.release.PublishExtension +import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.springframework.boot.gradle.plugin.SpringBootPlugin + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.Deploy.novodaBintray) + id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion + id(Config.BuildPlugins.springBoot) version Config.springBootVersion apply false +} + +apply(plugin = Config.BuildPlugins.springDependencyManagement) + +the().apply { + imports { + mavenBom(SpringBootPlugin.BOM_COORDINATES) + } +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + api(project(":sentry-core")) + implementation(Config.Libs.springWeb) + implementation(Config.Libs.servletApi) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + errorproneJavac(Config.CompileOnly.errorProneJavac8) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.Libs.springBootStarterTest) + testImplementation(Config.Libs.springBootStarterWeb) + testImplementation(Config.Libs.springBootStarterSecurity) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.Jacoco.version +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +buildConfig { + useJavaOutput() + packageName("io.sentry.spring") + buildConfigField("String", "SENTRY_SPRING_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} + +val generateBuildConfig by tasks +tasks.withType().configureEach { + dependsOn(generateBuildConfig) +} + +//TODO: move these blocks to parent gradle file, DRY +configure { + userOrg = Config.Sentry.userOrg + groupId = project.group.toString() + publishVersion = project.version.toString() + desc = Config.Sentry.description + website = Config.Sentry.website + repoName = Config.Sentry.repoName + setLicences(Config.Sentry.licence) + setLicenceUrls(Config.Sentry.licenceUrl) + issueTracker = Config.Sentry.issueTracker + repository = Config.Sentry.repository + sign = Config.Deploy.sign + artifactId = project.name + uploadName = "${project.group}:${project.name}" + devId = Config.Sentry.userOrg + devName = Config.Sentry.devName + devEmail = Config.Sentry.devEmail + scmConnection = Config.Sentry.scmConnection + scmDevConnection = Config.Sentry.scmDevConnection + scmUrl = Config.Sentry.scmUrl +} + diff --git a/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java b/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java new file mode 100644 index 000000000..2ab00f6ee --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java @@ -0,0 +1,32 @@ +package io.sentry.spring; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.context.annotation.Import; + +/** + * Enables Sentry error handling capabilities. + * + *

    + *
  • creates bean of type {@link io.sentry.core.SentryOptions} + *
  • registers {@link io.sentry.core.IHub} for sending Sentry events + *
  • registers {@link SentryRequestFilter} for attaching request information to Sentry events + *
  • registers {@link SentryExceptionResolver} to send Sentry event for any uncaught exception + * in Spring MVC flow. + *
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Import({SentryHubRegistrar.class, SentryInitBeanPostProcessor.class, SentryWebConfiguration.class}) +@Target(ElementType.TYPE) +public @interface EnableSentry { + /** + * The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will + * just not send any events. + */ + String dsn() default ""; + + /** Whether to send personal identifiable information along with events. */ + boolean sendDefaultPii() default false; +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java b/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java new file mode 100644 index 000000000..eba7bfbf4 --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java @@ -0,0 +1,55 @@ +package io.sentry.spring; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.IHub; +import io.sentry.core.SentryEvent; +import io.sentry.core.SentryLevel; +import io.sentry.core.exception.ExceptionMechanismException; +import io.sentry.core.protocol.Mechanism; +import io.sentry.core.util.Objects; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.core.Ordered; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +/** + * {@link HandlerExceptionResolver} implementation that will record any exception that a Spring + * {@link org.springframework.web.servlet.mvc.Controller} throws to Sentry. It then returns null, + * which will let the other (default or custom) exception resolvers handle the actual error. + */ +@Open +public class SentryExceptionResolver implements HandlerExceptionResolver, Ordered { + private final @NotNull IHub hub; + + public SentryExceptionResolver(final @NotNull IHub hub) { + this.hub = Objects.requireNonNull(hub, "hub is required"); + } + + @Override + public @Nullable ModelAndView resolveException( + final @NotNull HttpServletRequest request, + final @NotNull HttpServletResponse response, + final @Nullable Object handler, + final @NotNull Exception ex) { + + final Mechanism mechanism = new Mechanism(); + mechanism.setHandled(false); + final Throwable throwable = + new ExceptionMechanismException(mechanism, ex, Thread.currentThread()); + final SentryEvent event = new SentryEvent(throwable); + event.setLevel(SentryLevel.FATAL); + hub.captureEvent(event); + + // null = run other HandlerExceptionResolvers to actually handle the exception + return null; + } + + @Override + public int getOrder() { + // ensure this resolver runs first so that all exceptions are reported + return Integer.MIN_VALUE; + } +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java new file mode 100644 index 000000000..3b85dae5c --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java @@ -0,0 +1,73 @@ +package io.sentry.spring; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.HubAdapter; +import io.sentry.core.SentryOptions; +import io.sentry.core.protocol.SdkVersion; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotationMetadata; + +/** Registers beans required to use Sentry core features. */ +@Configuration +@Open +public class SentryHubRegistrar implements ImportBeanDefinitionRegistrar { + + @Override + public void registerBeanDefinitions( + AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + final AnnotationAttributes annotationAttributes = + AnnotationAttributes.fromMap( + importingClassMetadata.getAnnotationAttributes(EnableSentry.class.getName())); + if (annotationAttributes != null && annotationAttributes.containsKey("dsn")) { + registerSentryOptions(registry, annotationAttributes); + registerSentryHubBean(registry); + } + } + + private void registerSentryOptions( + BeanDefinitionRegistry registry, AnnotationAttributes annotationAttributes) { + final BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(SentryOptions.class); + + if (registry.containsBeanDefinition("mockTransport")) { + builder.addPropertyReference("transport", "mockTransport"); + } + builder.addPropertyValue("dsn", annotationAttributes.getString("dsn")); + builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_SDK_NAME); + builder.addPropertyValue("sdkVersion", createSdkVersion()); + if (annotationAttributes.containsKey("sendDefaultPii")) { + builder.addPropertyValue("sendDefaultPii", annotationAttributes.getBoolean("sendDefaultPii")); + } + + registry.registerBeanDefinition("sentryOptions", builder.getBeanDefinition()); + } + + private void registerSentryHubBean(BeanDefinitionRegistry registry) { + final BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(HubAdapter.class); + builder.setInitMethodName("getInstance"); + + registry.registerBeanDefinition("sentryHub", builder.getBeanDefinition()); + } + + private static @NotNull SdkVersion createSdkVersion() { + final SentryOptions defaultOptions = new SentryOptions(); + SdkVersion sdkVersion = defaultOptions.getSdkVersion(); + + if (sdkVersion == null) { + sdkVersion = new SdkVersion(); + } + + sdkVersion.setName(BuildConfig.SENTRY_SPRING_SDK_NAME); + final String version = BuildConfig.VERSION_NAME; + sdkVersion.setVersion(version); + sdkVersion.addPackage("maven:sentry-spring", version); + + return sdkVersion; + } +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java new file mode 100644 index 000000000..ddc350a3e --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java @@ -0,0 +1,21 @@ +package io.sentry.spring; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.Sentry; +import io.sentry.core.SentryOptions; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** Initializes Sentry after all beans are registered. */ +@Open +public class SentryInitBeanPostProcessor implements BeanPostProcessor { + @Override + public Object postProcessAfterInitialization( + final @NotNull Object bean, @NotNull final String beanName) throws BeansException { + if (bean instanceof SentryOptions) { + Sentry.init((SentryOptions) bean); + } + return bean; + } +} diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java similarity index 68% rename from sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java rename to sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java index fe0fb81aa..d9f22adc2 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java @@ -1,25 +1,28 @@ -package io.sentry.spring.boot; +package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.Breadcrumb; import io.sentry.core.IHub; import io.sentry.core.SentryOptions; +import io.sentry.core.util.Objects; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; +import org.springframework.core.Ordered; import org.springframework.web.filter.OncePerRequestFilter; /** Pushes new {@link io.sentry.core.Scope} on each incoming HTTP request. */ @Open -public class SentryRequestFilter extends OncePerRequestFilter { +public class SentryRequestFilter extends OncePerRequestFilter implements Ordered { private final @NotNull IHub hub; private final @NotNull SentryOptions options; public SentryRequestFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) { - this.hub = hub; - this.options = options; + this.hub = Objects.requireNonNull(hub, "hub is required"); + this.options = Objects.requireNonNull(options, "options are required"); } @Override @@ -29,6 +32,7 @@ protected void doFilterInternal( final @NotNull FilterChain filterChain) throws ServletException, IOException { hub.pushScope(); + hub.addBreadcrumb(Breadcrumb.http(request.getRequestURI(), request.getMethod())); hub.configureScope( scope -> { @@ -36,4 +40,9 @@ protected void doFilterInternal( }); filterChain.doFilter(request, response); } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } } diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java similarity index 92% rename from sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java rename to sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java index 7b718377f..ffcb5e2d0 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java @@ -1,10 +1,11 @@ -package io.sentry.spring.boot; +package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; import io.sentry.core.EventProcessor; import io.sentry.core.SentryEvent; import io.sentry.core.SentryOptions; import io.sentry.core.protocol.Request; +import io.sentry.core.util.Objects; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; @@ -26,8 +27,8 @@ public class SentryRequestHttpServletRequestProcessor implements EventProcessor public SentryRequestHttpServletRequestProcessor( final @NotNull HttpServletRequest request, final @NotNull SentryOptions options) { - this.request = request; - this.options = options; + this.request = Objects.requireNonNull(request, "request is required"); + this.options = Objects.requireNonNull(options, "options are required"); } @Override diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java b/sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java similarity index 90% rename from sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java rename to sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java index 546e8dd79..3d0d8d7ea 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentrySecurityFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java @@ -1,8 +1,9 @@ -package io.sentry.spring.boot; +package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; import io.sentry.core.IHub; import io.sentry.core.SentryOptions; +import io.sentry.core.util.Objects; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -21,8 +22,8 @@ public class SentrySecurityFilter extends OncePerRequestFilter { private final @NotNull SentryOptions options; public SentrySecurityFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) { - this.hub = hub; - this.options = options; + this.hub = Objects.requireNonNull(hub, "hub is required"); + this.options = Objects.requireNonNull(options, "options are required"); } @Override diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java similarity index 97% rename from sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java rename to sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java index c9bfff93e..1e5fbf72b 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryUserHttpServletRequestProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java @@ -1,4 +1,4 @@ -package io.sentry.spring.boot; +package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; import io.sentry.core.EventProcessor; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java new file mode 100644 index 000000000..47e8731c5 --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java @@ -0,0 +1,25 @@ +package io.sentry.spring; + +import com.jakewharton.nopen.annotation.Open; +import io.sentry.core.IHub; +import io.sentry.core.SentryOptions; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** Registers Spring Web specific Sentry beans. */ +@Configuration +@Open +public class SentryWebConfiguration { + + @Bean + public @NotNull SentryRequestFilter sentryRequestFilter( + final @NotNull IHub sentryHub, final @NotNull SentryOptions sentryOptions) { + return new SentryRequestFilter(sentryHub, sentryOptions); + } + + @Bean + public @NotNull SentryExceptionResolver sentryExceptionResolver(final @NotNull IHub sentryHub) { + return new SentryExceptionResolver(sentryHub); + } +} diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt new file mode 100644 index 000000000..1255f96a9 --- /dev/null +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt @@ -0,0 +1,78 @@ +package io.sentry.spring + +import io.sentry.core.IHub +import io.sentry.core.SentryOptions +import kotlin.test.Test +import org.assertj.core.api.Assertions.assertThat +import org.springframework.boot.context.annotation.UserConfigurations +import org.springframework.boot.test.context.runner.ApplicationContextRunner + +class EnableSentryTest { + private val contextRunner = ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfig::class.java)) + + @Test + fun `sets properties from environment on SentryOptions`() { + ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfigWithDefaultSendPii::class.java)) + .run { + assertThat(it).hasSingleBean(SentryOptions::class.java) + val options = it.getBean(SentryOptions::class.java) + assertThat(options.dsn).isEqualTo("http://key@localhost/proj") + assertThat(options.isSendDefaultPii).isTrue() + } + + ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfigWithEmptyDsn::class.java)) + .run { + assertThat(it).hasSingleBean(SentryOptions::class.java) + val options = it.getBean(SentryOptions::class.java) + assertThat(options.dsn).isEmpty() + assertThat(options.isSendDefaultPii).isFalse() + } + } + + @Test + fun `sets client name and SDK version`() { + contextRunner.run { + assertThat(it).hasSingleBean(SentryOptions::class.java) + val options = it.getBean(SentryOptions::class.java) + assertThat(options.sentryClientName).isEqualTo("sentry.java.spring") + assertThat(options.sdkVersion).isNotNull + assertThat(options.sdkVersion!!.name).isEqualTo("sentry.java.spring") + assertThat(options.sdkVersion!!.version).isEqualTo(BuildConfig.VERSION_NAME) + assertThat(options.sdkVersion!!.packages).isNotNull + assertThat(options.sdkVersion!!.packages!!.map { pkg -> pkg.name }).contains("maven:sentry-spring") + } + } + + @Test + fun `creates Sentry Hub`() { + contextRunner.run { + assertThat(it).hasSingleBean(IHub::class.java) + } + } + + @Test + fun `creates SentryRequestFilter`() { + contextRunner.run { + assertThat(it).hasSingleBean(SentryRequestFilter::class.java) + } + } + + @Test + fun `creates SentryExceptionResolver`() { + contextRunner.run { + assertThat(it).hasSingleBean(SentryExceptionResolver::class.java) + } + } + + @EnableSentry(dsn = "http://key@localhost/proj") + class AppConfig + + @EnableSentry(dsn = "") + class AppConfigWithEmptyDsn + + @EnableSentry(dsn = "http://key@localhost/proj", sendDefaultPii = true) + class AppConfigWithDefaultSendPii +} diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt similarity index 99% rename from sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt rename to sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt index ba709d6c9..ca33e331d 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt @@ -1,4 +1,4 @@ -package io.sentry.spring.boot +package io.sentry.spring import io.sentry.core.SentryEvent import io.sentry.core.SentryOptions diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt new file mode 100644 index 000000000..f5aabbda2 --- /dev/null +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt @@ -0,0 +1,163 @@ +package io.sentry.spring + +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.reset +import com.nhaarman.mockitokotlin2.verify +import io.sentry.core.IHub +import io.sentry.core.Sentry +import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions +import io.sentry.core.exception.ExceptionMechanismException +import io.sentry.core.transport.ITransport +import java.lang.RuntimeException +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.kotlin.await +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.boot.web.server.LocalServerPort +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpMethod +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.crypto.factory.PasswordEncoderFactories +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter +import org.springframework.test.context.junit4.SpringRunner +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@RunWith(SpringRunner::class) +@SpringBootTest( + classes = [App::class], + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +class SentrySpringIntegrationTest { + + @Autowired + lateinit var transport: ITransport + + @LocalServerPort + lateinit var port: Integer + + @Before + fun `reset mocks`() { + reset(transport) + } + + @Test + fun `attaches request and user information to SentryEvents`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + val headers = HttpHeaders() + headers["X-FORWARDED-FOR"] = listOf("169.128.0.1") + val entity = HttpEntity(headers) + + restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.request).isNotNull() + assertThat(event.request.url).isEqualTo("http://localhost:$port/hello") + assertThat(event.user).isNotNull() + assertThat(event.user.username).isEqualTo("user") + assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") + }) + } + } + + @Test + fun `attaches first ip address if multiple addresses exist in a header`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + val headers = HttpHeaders() + headers["X-FORWARDED-FOR"] = listOf("169.128.0.1, 192.168.0.1") + val entity = HttpEntity(headers) + + restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") + }) + } + } + + @Test + fun `sends events for unhandled exceptions`() { + val restTemplate = TestRestTemplate().withBasicAuth("user", "password") + + restTemplate.getForEntity("http://localhost:$port/throws", String::class.java) + + await.untilAsserted { + verify(transport).send(check { event: SentryEvent -> + assertThat(event.throwable).isNotNull() + assertThat(event.throwable).isInstanceOf(ExceptionMechanismException::class.java) + val ex = event.throwable as ExceptionMechanismException + assertThat(ex.throwable.message).isEqualTo("something went wrong") + assertThat(ex.exceptionMechanism.isHandled).isFalse() + }) + } + } +} + +@SpringBootApplication +@EnableSentry(dsn = "http://key@localhost/proj", sendDefaultPii = true) +open class App { + + @Bean + open fun mockTransport() = mock() +} + +@RestController +class HelloController { + + @GetMapping("/hello") + fun hello() { + Sentry.captureMessage("hello") + } + + @GetMapping("/throws") + fun throws() { + throw RuntimeException("something went wrong") + } +} + +@Configuration +open class SecurityConfiguration( + private val hub: IHub, + private val options: SentryOptions +) : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http + .addFilterAfter(SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter::class.java) + .csrf().disable() + .authorizeRequests().anyRequest().authenticated() + .and() + .httpBasic() + } + + @Bean + override fun userDetailsService(): UserDetailsService { + val encoder: PasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder() + val user: UserDetails = User + .builder() + .passwordEncoder { rawPassword -> encoder.encode(rawPassword) } + .username("user") + .password("password") + .roles("USER") + .build() + return InMemoryUserDetailsManager(user) + } +} diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt similarity index 98% rename from sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt rename to sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt index 9fa3fe46e..6a8e2598b 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryUserHttpServletRequestProcessorTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt @@ -1,4 +1,4 @@ -package io.sentry.spring.boot +package io.sentry.spring import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a05fde78..efd3fce0f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,10 +7,12 @@ include("sentry-android", "sentry-core", "sentry-log4j2", "sentry-logback", + "sentry-spring", "sentry-spring-boot-starter", "sentry-android-timber", "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", "sentry-samples:sentry-samples-log4j2", "sentry-samples:sentry-samples-logback", + "sentry-samples:sentry-samples-spring", "sentry-samples:sentry-samples-spring-boot") From 33766f404dec923c36a1b6ad2680f694df62cdc1 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Wed, 9 Sep 2020 11:28:37 +0200 Subject: [PATCH 23/28] ref: move init flag (#542) --- .../src/main/java/io/sentry/core/Session.java | 7 + .../io/sentry/core/cache/CacheStrategy.java | 214 +++++++++++++++++- .../io/sentry/core/cache/EnvelopeCache.java | 5 +- .../io/sentry/core/cache/CacheStrategyTest.kt | 101 ++++++++- 4 files changed, 323 insertions(+), 4 deletions(-) diff --git a/sentry-core/src/main/java/io/sentry/core/Session.java b/sentry-core/src/main/java/io/sentry/core/Session.java index 25038666c..c5dd5a08a 100644 --- a/sentry-core/src/main/java/io/sentry/core/Session.java +++ b/sentry-core/src/main/java/io/sentry/core/Session.java @@ -4,6 +4,7 @@ import java.util.Date; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -142,6 +143,12 @@ public Session( return init; } + /** Used for migrating the init flag when an session is gonna be deleted. */ + @ApiStatus.Internal + public void setInitAsTrue() { + this.init = true; + } + public int errorCount() { return errorCount.get(); } diff --git a/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java b/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java index e175d7712..61e224e5d 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java +++ b/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java @@ -3,13 +3,35 @@ import static io.sentry.core.SentryLevel.ERROR; import io.sentry.core.ISerializer; +import io.sentry.core.SentryEnvelope; +import io.sentry.core.SentryEnvelopeItem; +import io.sentry.core.SentryItemType; import io.sentry.core.SentryLevel; import io.sentry.core.SentryOptions; +import io.sentry.core.Session; import io.sentry.core.util.Objects; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; abstract class CacheStrategy { @@ -79,10 +101,15 @@ protected void rotateCacheIfNeeded(final @NotNull File[] files) { sortFilesOldestToNewest(files); + final File[] notDeletedFiles = Arrays.copyOfRange(files, totalToBeDeleted, length); + // delete files from the top of the Array as its sorted by the oldest to the newest for (int i = 0; i < totalToBeDeleted; i++) { final File file = files[i]; - // sanity check if the file actually exists. + + // move init flag if necessary + moveInitFlagIfNecessary(file, notDeletedFiles); + if (!file.delete()) { options .getLogger() @@ -91,4 +118,189 @@ protected void rotateCacheIfNeeded(final @NotNull File[] files) { } } } + + private void moveInitFlagIfNecessary( + final @NotNull File currentFile, final @NotNull File[] notDeletedFiles) { + final SentryEnvelope currentEnvelope = readEnvelope(currentFile); + + if (!isValidEnvelope(currentEnvelope)) { + return; + } + + final Session currentSession = getFirstSession(currentEnvelope); + + if (!isValidSession(currentSession)) { + return; + } + + // nothing to do if its not true + final Boolean currentSessionInit = currentSession.getInit(); + if (currentSessionInit == null || !currentSessionInit) { + return; + } + + // we need to move the init flag + for (final File notDeletedFile : notDeletedFiles) { + final SentryEnvelope envelope = readEnvelope(notDeletedFile); + + if (!isValidEnvelope(envelope)) { + continue; + } + + SentryEnvelopeItem newSessionItem = null; + final Iterator itemsIterator = envelope.getItems().iterator(); + + while (itemsIterator.hasNext()) { + final SentryEnvelopeItem envelopeItem = itemsIterator.next(); + + if (!isSessionType(envelopeItem)) { + continue; + } + + final Session session = readSession(envelopeItem); + + if (!isValidSession(session)) { + continue; + } + + final Boolean init = session.getInit(); + if (init != null && init) { + options + .getLogger() + .log(ERROR, "Session %s has 2 times the init flag.", currentSession.getSessionId()); + return; + } + + if (currentSession.getSessionId().equals(session.getSessionId())) { + session.setInitAsTrue(); + try { + newSessionItem = SentryEnvelopeItem.fromSession(serializer, session); + // remove item from envelope items so we can replace with the new one that has the + // init flag true + itemsIterator.remove(); + } catch (IOException e) { + options + .getLogger() + .log( + ERROR, + e, + "Failed to create new envelope item for the session %s", + currentSession.getSessionId()); + } + + break; + } + } + + if (newSessionItem != null) { + final SentryEnvelope newEnvelope = buildNewEnvelope(envelope, newSessionItem); + + long notDeletedFileTimestamp = notDeletedFile.lastModified(); + if (!notDeletedFile.delete()) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "File can't be deleted: %s", + notDeletedFile.getAbsolutePath()); + } + + saveNewEnvelope(newEnvelope, notDeletedFile, notDeletedFileTimestamp); + break; + } + } + } + + private @Nullable SentryEnvelope readEnvelope(final @NotNull File file) { + try (final InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { + return serializer.deserializeEnvelope(inputStream); + } catch (IOException e) { + options.getLogger().log(ERROR, "Failed to deserialize the envelope.", e); + } + + return null; + } + + private @Nullable Session getFirstSession(final @NotNull SentryEnvelope envelope) { + for (final SentryEnvelopeItem item : envelope.getItems()) { + if (!isSessionType(item)) { + continue; + } + + // we are assuming that there's only 1 session per envelope for now + return readSession(item); + } + return null; + } + + private boolean isValidSession(final @Nullable Session session) { + if (session == null) { + return false; + } + + if (!session.getStatus().equals(Session.State.Ok)) { + return false; + } + + final UUID sessionId = session.getSessionId(); + + if (sessionId == null) { + return false; + } + return true; + } + + private boolean isSessionType(final @Nullable SentryEnvelopeItem item) { + if (item == null) { + return false; + } + + return item.getHeader().getType().equals(SentryItemType.Session); + } + + private @Nullable Session readSession(final @NotNull SentryEnvelopeItem item) { + try (final Reader reader = + new BufferedReader( + new InputStreamReader(new ByteArrayInputStream(item.getData()), UTF_8))) { + return serializer.deserializeSession(reader); + } catch (Exception e) { + options.getLogger().log(ERROR, "Failed to deserialize the session.", e); + } + return null; + } + + private void saveNewEnvelope( + final @NotNull SentryEnvelope envelope, final @NotNull File file, final long timestamp) { + try (final OutputStream outputStream = new FileOutputStream(file); + final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) { + serializer.serialize(envelope, writer); + // we need to set the same timestamp so the sorting from oldest to newest wont break. + file.setLastModified(timestamp); + } catch (Exception e) { + options.getLogger().log(ERROR, "Failed to serialize the new envelope to the disk.", e); + } + } + + private @NotNull SentryEnvelope buildNewEnvelope( + final @NotNull SentryEnvelope envelope, final @NotNull SentryEnvelopeItem sessionItem) { + final List newEnvelopeItems = new ArrayList<>(); + + for (final SentryEnvelopeItem newEnvelopeItem : envelope.getItems()) { + newEnvelopeItems.add(newEnvelopeItem); + } + newEnvelopeItems.add(sessionItem); + + return new SentryEnvelope(envelope.getHeader(), newEnvelopeItems); + } + + private boolean isValidEnvelope(final @Nullable SentryEnvelope envelope) { + if (envelope == null) { + return false; + } + + if (!envelope.getItems().iterator().hasNext()) { + return false; + } + return true; + } } diff --git a/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java b/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java index b4a88db56..a66cc6602 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java +++ b/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java @@ -132,7 +132,10 @@ public void store(final @NotNull SentryEnvelope envelope, final @Nullable Object } updateCurrentSession(currentSessionFile, envelope); } - // TODO: problem we need to update the current session file + + // TODO: probably we need to update the current session file for session updates to because of + // hardcrash events + final File envelopeFile = getEnvelopeFile(envelope); if (envelopeFile.exists()) { options diff --git a/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt b/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt index 4d7e7c109..7eeae9f99 100644 --- a/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt +++ b/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt @@ -2,24 +2,31 @@ package io.sentry.core.cache import com.nhaarman.mockitokotlin2.mock import io.sentry.core.DateUtils +import io.sentry.core.GsonSerializer +import io.sentry.core.SentryEnvelope import io.sentry.core.SentryOptions +import io.sentry.core.Session +import java.io.ByteArrayInputStream import java.io.File +import java.io.InputStreamReader import java.nio.file.Files +import java.util.UUID import kotlin.test.AfterTest import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNull import kotlin.test.assertTrue class CacheStrategyTest { private class Fixture { val dir = Files.createTempDirectory("sentry-disk-cache-test").toAbsolutePath().toFile() - val options = SentryOptions().apply { + val sentryOptions = SentryOptions().apply { setSerializer(mock()) } - fun getSUT(maxSize: Int = 5): CacheStrategy { + fun getSUT(maxSize: Int = 5, options: SentryOptions = sentryOptions): CacheStrategy { return CustomCache(options, dir.absolutePath, maxSize) } } @@ -65,6 +72,59 @@ class CacheStrategyTest { assertTrue(files[2].exists()) } + @Test + fun `do not move init flag if state is not ok`() { + val options = SentryOptions().apply { + setSerializer(GsonSerializer(mock(), envelopeReader)) + } + val sut = fixture.getSUT(3, getOptionsWithRealSerializer()) + + val files = createTempFilesSortByOldestToNewest() + + saveSessionToFile(files[0], sut, Session.State.Crashed, null) + + saveSessionToFile(files[1], sut, Session.State.Exited, null) + + saveSessionToFile(files[2], sut, Session.State.Exited, null) + + sut.rotateCacheIfNeeded(files) + + // files[0] has been deleted because of rotation + for (i in 1..2) { + val expectedSession = getSessionFromFile(files[i], sut) + + assertNull(expectedSession.init) + } + } + + @Test + fun `move init flag if state is ok`() { + val options = SentryOptions().apply { + setSerializer(GsonSerializer(mock(), envelopeReader)) + } + val sut = fixture.getSUT(3, options) + + val files = createTempFilesSortByOldestToNewest() + + val okSession = createSessionMockData(Session.State.Ok, true) + val okEnvelope = SentryEnvelope.fromSession(sut.serializer, okSession, null) + sut.serializer.serialize(okEnvelope, files[0].writer()) + + val updatedOkSession = okSession.clone() + updatedOkSession.update(null, null, true) + val updatedOkEnvelope = SentryEnvelope.fromSession(sut.serializer, updatedOkSession, null) + sut.serializer.serialize(updatedOkEnvelope, files[1].writer()) + + saveSessionToFile(files[2], sut, Session.State.Exited, null) + + sut.rotateCacheIfNeeded(files) + + // files[1] should be the one with the init flag true + val expectedSession = getSessionFromFile(files[1], sut) + + assertTrue(expectedSession.init!!) + } + @AfterTest fun shutdown() { fixture.dir.listFiles()?.forEach { @@ -86,4 +146,41 @@ class CacheStrategyTest { return arrayOf(f1, f2, f3) } + + private fun createSessionMockData(state: Session.State = Session.State.Ok, init: Boolean? = true): Session = + Session( + state, + DateUtils.getDateTime("2020-02-07T14:16:00.000Z"), + DateUtils.getDateTime("2020-02-07T14:16:00.000Z"), + 2, + "123", + UUID.fromString("c81d4e2e-bcf2-11e6-869b-7df92533d2db"), + init, + 123456.toLong(), + 6000.toDouble(), + "127.0.0.1", + "jamesBond", + "debug", + "io.sentry@1.0+123" + ) + + private fun getSessionFromFile(file: File, sut: CacheStrategy): Session { + val envelope = sut.serializer.deserializeEnvelope(file.inputStream()) + val item = envelope.items.first() + + val reader = InputStreamReader(ByteArrayInputStream(item.data), Charsets.UTF_8) + return sut.serializer.deserializeSession(reader) + } + + private fun saveSessionToFile(file: File, sut: CacheStrategy, state: Session.State = Session.State.Ok, init: Boolean? = true) { + val okSession = createSessionMockData(Session.State.Ok, init) + val okEnvelope = SentryEnvelope.fromSession(sut.serializer, okSession, null) + sut.serializer.serialize(okEnvelope, file.writer()) + } + + private fun getOptionsWithRealSerializer(): SentryOptions { + return SentryOptions().apply { + setSerializer(GsonSerializer(mock(), envelopeReader)) + } + } } From c891d6a5e0eab4cd2b087b19835f2297bca940a7 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 9 Sep 2020 13:54:12 +0200 Subject: [PATCH 24/28] fix: Asserting events on Envelope sent to Transport (#548) Co-authored-by: Bruno Garcia --- README.md | 5 +- .../io/sentry/core/SentryEnvelopeItem.java | 14 +++ sentry-log4j2/build.gradle.kts | 1 + .../io/sentry/log4j2/SentryAppenderTest.kt | 99 ++++++++----------- sentry-logback/build.gradle.kts | 1 + .../io/sentry/logback/SentryAppenderTest.kt | 96 ++++++++---------- sentry-spring-boot-starter/build.gradle.kts | 1 + .../boot/SentryAutoConfigurationTest.kt | 12 ++- .../boot/SentrySpringIntegrationTest.kt | 19 ++-- sentry-spring/build.gradle.kts | 1 + .../spring/SentrySpringIntegrationTest.kt | 19 ++-- sentry-test-support/build.gradle.kts | 39 ++++++++ .../main/kotlin/io/sentry/test/assertions.kt | 21 ++++ settings.gradle.kts | 1 + 14 files changed, 186 insertions(+), 143 deletions(-) create mode 100644 sentry-test-support/build.gradle.kts create mode 100644 sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt diff --git a/README.md b/README.md index 941fa9052..d8369ee3a 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,9 @@ Sentry SDK for Java and Android | sentry-android-core | [![sentry-android-core](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-android-core)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-android-core?tab=overview) | 14 | | sentry-android-ndk | [![sentry-android-ndk](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-android-ndk)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-android-ndk?tab=overview) | 16 | | sentry-android-timber | [![sentry-android-timber](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-android-timber)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-android-timber?tab=overview) | 14 | -| sentry-core | [![sentry-core](https://img.shields.io/bintray/v/getsentry/sentry-android/io.sentry:sentry-core)](https://bintray.com/getsentry/sentry-android/io.sentry:sentry-core?tab=overview) | 14 | -| sentry | [![sentry](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry?tab=overview) | | +| sentry | [![sentry](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry?tab=overview) | 14 | | sentry-spring-boot-starter | [![sentry-spring-boot-starter](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter?tab=overview) | | | sentry-spring | [![sentry-spring](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring?tab=overview) | | -| sentry-spring-boot-starter | [![sentry-spring-boot-starter](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-spring-boot-starter?tab=overview) | | -| sentry-appengine | [![sentry-appengine](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-appengine)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-appengine?tab=overview) | | | sentry-log4j | [![sentry-log4j](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-log4j)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-log4j?tab=overview) | | | sentry-log4j2 | [![sentry-log4j2](https://img.shields.io/bintray/v/getsentry/sentry-java/io.sentry:sentry-log4j2)](https://bintray.com/getsentry/sentry-java/io.sentry:sentry-log4j2?tab=overview) | | diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java b/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java index 74b5d2ea6..46cf879d5 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java +++ b/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java @@ -1,10 +1,14 @@ package io.sentry.core; import io.sentry.core.util.Objects; +import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.io.Reader; import java.io.Writer; import java.nio.charset.Charset; import java.util.concurrent.Callable; @@ -72,6 +76,16 @@ public final class SentryEnvelopeItem { return new SentryEnvelopeItem(itemHeader, () -> cachedItem.getBytes()); } + public @Nullable SentryEvent getEvent(final @NotNull ISerializer serializer) throws Exception { + if (header == null || header.getType() != SentryItemType.Event) { + return null; + } + try (final Reader eventReader = + new BufferedReader(new InputStreamReader(new ByteArrayInputStream(getData()), UTF_8))) { + return serializer.deserializeEvent(eventReader); + } + } + public static @NotNull SentryEnvelopeItem fromEvent( final @NotNull ISerializer serializer, final @NotNull SentryEvent event) throws IOException { Objects.requireNonNull(serializer, "ISerializer is required."); diff --git a/sentry-log4j2/build.gradle.kts b/sentry-log4j2/build.gradle.kts index d2d544129..d5c60ab80 100644 --- a/sentry-log4j2/build.gradle.kts +++ b/sentry-log4j2/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { compileOnly(Config.CompileOnly.jetbrainsAnnotations) // tests + testImplementation(project(":sentry-test-support")) testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation(Config.TestLibs.mockitoKotlin) diff --git a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt index f1c5bd1ce..54ffc7918 100644 --- a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt +++ b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt @@ -1,12 +1,11 @@ package io.sentry.log4j2 -import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import io.sentry.core.HubAdapter -import io.sentry.core.SentryEvent import io.sentry.core.SentryLevel import io.sentry.core.transport.ITransport +import io.sentry.test.checkEvent import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId @@ -74,11 +73,11 @@ class SentryAppenderTest { logger.debug("testing message conversion {}, {}", 1, 2) await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals("testing message conversion 1, 2", it.message.formatted) - assertEquals("testing message conversion {}, {}", it.message.message) - assertEquals(listOf("1", "2"), it.message.params) - assertEquals("io.sentry.log4j2.SentryAppenderTest", it.logger) + verify(fixture.transport).send(checkEvent { event -> + assertEquals("testing message conversion 1, 2", event.message.formatted) + assertEquals("testing message conversion {}, {}", event.message.message) + assertEquals(listOf("1", "2"), event.message.params) + assertEquals("io.sentry.log4j2.SentryAppenderTest", event.logger) }) } } @@ -92,8 +91,8 @@ class SentryAppenderTest { logger.debug("testing event date") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - val eventTime = Instant.ofEpochMilli(it.timestamp.time) + verify(fixture.transport).send(checkEvent { event -> + val eventTime = Instant.ofEpochMilli(event.timestamp.time) .atZone(ZoneId.systemDefault()) .toLocalDateTime() @@ -110,8 +109,8 @@ class SentryAppenderTest { logger.trace("testing trace level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.DEBUG, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.DEBUG, event.level) }) } } @@ -123,8 +122,8 @@ class SentryAppenderTest { logger.debug("testing debug level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.DEBUG, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.DEBUG, event.level) }) } } @@ -136,8 +135,8 @@ class SentryAppenderTest { logger.info("testing info level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.INFO, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.INFO, event.level) }) } } @@ -149,8 +148,8 @@ class SentryAppenderTest { logger.warn("testing warn level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.WARNING, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.WARNING, event.level) }) } } @@ -162,8 +161,8 @@ class SentryAppenderTest { logger.error("testing error level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.ERROR, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.ERROR, event.level) }) } } @@ -175,8 +174,8 @@ class SentryAppenderTest { logger.fatal("testing fatal level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.FATAL, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.FATAL, event.level) }) } } @@ -188,8 +187,8 @@ class SentryAppenderTest { logger.warn("testing thread information") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertNotNull(it.getExtra("thread_name")) + verify(fixture.transport).send(checkEvent { event -> + assertNotNull(event.getExtra("thread_name")) }) } } @@ -202,8 +201,8 @@ class SentryAppenderTest { logger.warn("testing MDC tags") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(mapOf("key" to "value"), it.contexts["Context Data"]) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(mapOf("key" to "value"), event.contexts["Context Data"]) }) } } @@ -215,22 +214,8 @@ class SentryAppenderTest { logger.warn("testing without MDC tags") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertFalse(it.contexts.containsKey("MDC")) - }) - } - } - - @Test - fun `attaches throwable`() { - fixture.minimumEventLevel = Level.WARN - val logger = fixture.getSut() - val throwable = RuntimeException("something went wrong") - logger.warn("testing throwable", throwable) - - await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(throwable, it.throwable) + verify(fixture.transport).send(checkEvent { event -> + assertFalse(event.contexts.containsKey("MDC")) }) } } @@ -242,11 +227,11 @@ class SentryAppenderTest { logger.info("testing sdk version") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(BuildConfig.SENTRY_LOG4J2_SDK_NAME, it.sdk.name) - assertEquals(BuildConfig.VERSION_NAME, it.sdk.version) - assertNotNull(it.sdk.packages) - assertTrue(it.sdk.packages!!.any { pkg -> + verify(fixture.transport).send(checkEvent { event -> + assertEquals(BuildConfig.SENTRY_LOG4J2_SDK_NAME, event.sdk.name) + assertEquals(BuildConfig.VERSION_NAME, event.sdk.version) + assertNotNull(event.sdk.packages) + assertTrue(event.sdk.packages!!.any { pkg -> "maven:sentry-log4j2" == pkg.name && BuildConfig.VERSION_NAME == pkg.version }) @@ -266,10 +251,10 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(2, event.breadcrumbs.size) + val breadcrumb = event.breadcrumbs[0] + val breadcrumbTime = Instant.ofEpochMilli(event.timestamp.time) .atZone(ZoneId.systemDefault()) .toLocalDateTime() assertTrue { breadcrumbTime.plusSeconds(1).isAfter(utcTime) } @@ -292,9 +277,9 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(1, event.breadcrumbs.size) + assertEquals("this should be a breadcrumb", event.breadcrumbs[0].message) }) } } @@ -309,10 +294,10 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(2, event.breadcrumbs.size) + assertEquals("this should be a breadcrumb", event.breadcrumbs[0].message) + assertEquals("this should not be sent as the event but be a breadcrumb", event.breadcrumbs[1].message) }) } } diff --git a/sentry-logback/build.gradle.kts b/sentry-logback/build.gradle.kts index 3740c8c49..942a171ad 100644 --- a/sentry-logback/build.gradle.kts +++ b/sentry-logback/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { compileOnly(Config.CompileOnly.jetbrainsAnnotations) // tests + testImplementation(project(":sentry-test-support")) testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation(Config.TestLibs.mockitoKotlin) 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 0eb02a366..297dce4f7 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -3,15 +3,14 @@ package io.sentry.logback import ch.qos.logback.classic.Level import ch.qos.logback.classic.LoggerContext import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.SentryEvent import io.sentry.core.SentryLevel import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport import io.sentry.core.transport.TransportResult +import io.sentry.test.checkEvent import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId @@ -34,7 +33,7 @@ class SentryAppenderTest { val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext init { - whenever(transport.send(any())).thenReturn(TransportResult.success()) + whenever(transport.send(any())).thenReturn(TransportResult.success()) val appender = SentryAppender() val options = SentryOptions() options.dsn = "http://key@localhost/proj" @@ -69,11 +68,11 @@ class SentryAppenderTest { fixture.logger.debug("testing message conversion {}, {}", 1, 2) await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals("testing message conversion 1, 2", it.message.formatted) - assertEquals("testing message conversion {}, {}", it.message.message) - assertEquals(listOf("1", "2"), it.message.params) - assertEquals("io.sentry.logback.SentryAppenderTest", it.logger) + verify(fixture.transport).send(checkEvent { event -> + assertEquals("testing message conversion 1, 2", event.message.formatted) + assertEquals("testing message conversion {}, {}", event.message.message) + assertEquals(listOf("1", "2"), event.message.params) + assertEquals("io.sentry.logback.SentryAppenderTest", event.logger) }) } } @@ -86,8 +85,8 @@ class SentryAppenderTest { fixture.logger.debug("testing event date") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - val eventTime = Instant.ofEpochMilli(it.timestamp.time) + verify(fixture.transport).send(checkEvent { event -> + val eventTime = Instant.ofEpochMilli(event.timestamp.time) .atZone(ZoneId.systemDefault()) .toLocalDateTime() @@ -103,8 +102,8 @@ class SentryAppenderTest { fixture.logger.trace("testing trace level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.DEBUG, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.DEBUG, event.level) }) } } @@ -115,8 +114,8 @@ class SentryAppenderTest { fixture.logger.debug("testing debug level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.DEBUG, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.DEBUG, event.level) }) } } @@ -127,8 +126,8 @@ class SentryAppenderTest { fixture.logger.info("testing info level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.INFO, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.INFO, event.level) }) } } @@ -139,8 +138,8 @@ class SentryAppenderTest { fixture.logger.warn("testing warn level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.WARNING, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.WARNING, event.level) }) } } @@ -151,8 +150,8 @@ class SentryAppenderTest { fixture.logger.error("testing error level") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(SentryLevel.ERROR, it.level) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(SentryLevel.ERROR, event.level) }) } } @@ -163,8 +162,8 @@ class SentryAppenderTest { fixture.logger.warn("testing thread information") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertNotNull(it.getExtra("thread_name")) + verify(fixture.transport).send(checkEvent { event -> + assertNotNull(event.getExtra("thread_name")) }) } } @@ -176,8 +175,8 @@ class SentryAppenderTest { fixture.logger.warn("testing MDC tags") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(mapOf("key" to "value"), it.contexts["MDC"]) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(mapOf("key" to "value"), event.contexts["MDC"]) }) } } @@ -188,21 +187,8 @@ class SentryAppenderTest { fixture.logger.warn("testing without MDC tags") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertFalse(it.contexts.containsKey("MDC")) - }) - } - } - - @Test - fun `attaches throwable`() { - fixture = Fixture(minimumEventLevel = Level.WARN) - val throwable = RuntimeException("something went wrong") - fixture.logger.warn("testing throwable", throwable) - - await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(throwable, it.throwable) + verify(fixture.transport).send(checkEvent { event -> + assertFalse(event.contexts.containsKey("MDC")) }) } } @@ -213,11 +199,11 @@ class SentryAppenderTest { fixture.logger.info("testing sdk version") await.untilAsserted { - verify(fixture.transport).send(check { it: SentryEvent -> - assertEquals(BuildConfig.SENTRY_LOGBACK_SDK_NAME, it.sdk.name) - assertEquals(BuildConfig.VERSION_NAME, it.sdk.version) - assertNotNull(it.sdk.packages) - assertTrue(it.sdk.packages!!.any { pkg -> + verify(fixture.transport).send(checkEvent { event -> + assertEquals(BuildConfig.SENTRY_LOGBACK_SDK_NAME, event.sdk.name) + assertEquals(BuildConfig.VERSION_NAME, event.sdk.version) + assertNotNull(event.sdk.packages) + assertTrue(event.sdk.packages!!.any { pkg -> "maven:sentry-logback" == pkg.name && BuildConfig.VERSION_NAME == pkg.version }) @@ -235,10 +221,10 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(2, event.breadcrumbs.size) + val breadcrumb = event.breadcrumbs[0] + val breadcrumbTime = Instant.ofEpochMilli(event.timestamp.time) .atZone(ZoneId.systemDefault()) .toLocalDateTime() assertTrue { breadcrumbTime.plusSeconds(1).isAfter(utcTime) } @@ -259,9 +245,9 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(1, event.breadcrumbs.size) + assertEquals("this should be a breadcrumb", event.breadcrumbs[0].message) }) } } @@ -276,10 +262,10 @@ class SentryAppenderTest { 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) + verify(fixture.transport).send(checkEvent { event -> + assertEquals(2, event.breadcrumbs.size) + assertEquals("this should be a breadcrumb", event.breadcrumbs[0].message) + assertEquals("this should not be sent as the event but be a breadcrumb", event.breadcrumbs[1].message) }) } } diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts index d4c6c1c8e..0ca7e13e1 100644 --- a/sentry-spring-boot-starter/build.gradle.kts +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { compileOnly(Config.CompileOnly.jetbrainsAnnotations) // tests + testImplementation(project(":sentry-test-support")) testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation(Config.TestLibs.mockitoKotlin) diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index 43571670a..e78de75df 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -1,6 +1,5 @@ package io.sentry.spring.boot -import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever @@ -14,6 +13,7 @@ import io.sentry.core.SentryLevel import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport import io.sentry.core.transport.ITransportGate +import io.sentry.test.checkEvent import kotlin.test.Test import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration class SentryAutoConfigurationTest { + private val contextRunner = ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(SentryAutoConfiguration::class.java, WebMvcAutoConfiguration::class.java)) @@ -120,11 +121,12 @@ class SentryAutoConfigurationTest { Sentry.captureMessage("Some message") val transport = it.getBean(ITransport::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.sdk.version).isEqualTo(BuildConfig.VERSION_NAME) assertThat(event.sdk.name).isEqualTo(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME) assertThat(event.sdk.packages).anyMatch { pkg -> - pkg.name == "maven:sentry-spring-boot-starter" && pkg.version == BuildConfig.VERSION_NAME } + pkg.name == "maven:sentry-spring-boot-starter" && pkg.version == BuildConfig.VERSION_NAME + } }) } } @@ -183,7 +185,7 @@ class SentryAutoConfigurationTest { Sentry.captureMessage("Some message") val transport = it.getBean(ITransport::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.release).isEqualTo("git-commit-id") }) } @@ -198,7 +200,7 @@ class SentryAutoConfigurationTest { Sentry.captureMessage("Some message") val transport = it.getBean(ITransport::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.release).isEqualTo("my-release") }) } diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt index eb1fc3340..79f9cb6a9 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -1,14 +1,12 @@ package io.sentry.spring.boot -import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.verify import io.sentry.core.IHub import io.sentry.core.Sentry -import io.sentry.core.SentryEvent import io.sentry.core.SentryOptions -import io.sentry.core.exception.ExceptionMechanismException import io.sentry.core.transport.ITransport import io.sentry.spring.SentrySecurityFilter +import io.sentry.test.checkEvent import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await @@ -61,7 +59,7 @@ class SentrySpringIntegrationTest { restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.request).isNotNull() assertThat(event.request.url).isEqualTo("http://localhost:$port/hello") assertThat(event.user).isNotNull() @@ -81,7 +79,7 @@ class SentrySpringIntegrationTest { restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") }) } @@ -94,12 +92,11 @@ class SentrySpringIntegrationTest { restTemplate.getForEntity("http://localhost:$port/throws", String::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> - assertThat(event.throwable).isNotNull() - assertThat(event.throwable).isInstanceOf(ExceptionMechanismException::class.java) - val ex = event.throwable as ExceptionMechanismException - assertThat(ex.throwable.message).isEqualTo("something went wrong") - assertThat(ex.exceptionMechanism.isHandled).isFalse() + verify(transport).send(checkEvent { event -> + assertThat(event.exceptions).isNotEmpty + val ex = event.exceptions.first() + assertThat(ex.value).isEqualTo("something went wrong") + assertThat(ex.mechanism.isHandled).isFalse() }) } } diff --git a/sentry-spring/build.gradle.kts b/sentry-spring/build.gradle.kts index f8cac1d77..d50389923 100644 --- a/sentry-spring/build.gradle.kts +++ b/sentry-spring/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { compileOnly(Config.CompileOnly.jetbrainsAnnotations) // tests + testImplementation(project(":sentry-test-support")) testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation(Config.TestLibs.mockitoKotlin) diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt index f5aabbda2..2a78d4a80 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt @@ -1,15 +1,13 @@ package io.sentry.spring -import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify import io.sentry.core.IHub import io.sentry.core.Sentry -import io.sentry.core.SentryEvent import io.sentry.core.SentryOptions -import io.sentry.core.exception.ExceptionMechanismException import io.sentry.core.transport.ITransport +import io.sentry.test.checkEvent import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await @@ -67,7 +65,7 @@ class SentrySpringIntegrationTest { restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.request).isNotNull() assertThat(event.request.url).isEqualTo("http://localhost:$port/hello") assertThat(event.user).isNotNull() @@ -87,7 +85,7 @@ class SentrySpringIntegrationTest { restTemplate.exchange("http://localhost:$port/hello", HttpMethod.GET, entity, Void::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> + verify(transport).send(checkEvent { event -> assertThat(event.user.ipAddress).isEqualTo("169.128.0.1") }) } @@ -100,12 +98,11 @@ class SentrySpringIntegrationTest { restTemplate.getForEntity("http://localhost:$port/throws", String::class.java) await.untilAsserted { - verify(transport).send(check { event: SentryEvent -> - assertThat(event.throwable).isNotNull() - assertThat(event.throwable).isInstanceOf(ExceptionMechanismException::class.java) - val ex = event.throwable as ExceptionMechanismException - assertThat(ex.throwable.message).isEqualTo("something went wrong") - assertThat(ex.exceptionMechanism.isHandled).isFalse() + verify(transport).send(checkEvent { event -> + assertThat(event.exceptions).isNotEmpty + val ex = event.exceptions.first() + assertThat(ex.value).isEqualTo("something went wrong") + assertThat(ex.mechanism.isHandled).isFalse() }) } } diff --git a/sentry-test-support/build.gradle.kts b/sentry-test-support/build.gradle.kts new file mode 100644 index 000000000..f36a71742 --- /dev/null +++ b/sentry-test-support/build.gradle.kts @@ -0,0 +1,39 @@ +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.QualityPlugins.gradleVersions) +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + api(project(":sentry-core")) + // Envelopes require JSON. Until a parse is done without GSON, we'll depend on it explicitly here + implementation(Config.Libs.gson) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + errorproneJavac(Config.CompileOnly.errorProneJavac8) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + api(kotlin(Config.kotlinStdLib)) + implementation(Config.TestLibs.kotlinTestJunit) + implementation(Config.TestLibs.mockitoKotlin) +} + +configure { + test { + java.srcDir("src/test/java") + } +} diff --git a/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt b/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt new file mode 100644 index 000000000..a1d02db8a --- /dev/null +++ b/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt @@ -0,0 +1,21 @@ +package io.sentry.test + +import com.nhaarman.mockitokotlin2.check +import io.sentry.core.GsonSerializer +import io.sentry.core.NoOpLogger +import io.sentry.core.SentryEnvelope +import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions + +/** + * Verifies is [SentryEnvelope] contains first event matching a predicate. + */ +inline fun checkEvent(noinline predicate: (SentryEvent) -> Unit): SentryEnvelope { + val options = SentryOptions().apply { + setSerializer(GsonSerializer(NoOpLogger.getInstance(), envelopeReader)) + } + return check { + val event = it.items.first().getEvent(options.serializer)!! + predicate(event) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index efd3fce0f..1a0c91aa6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,7 @@ include("sentry-android", "sentry-android-ndk", "sentry-android-core", "sentry-core", + "sentry-test-support", "sentry-log4j2", "sentry-logback", "sentry-spring", From ae0219da369bb605c264b79c74f6741275ad083a Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 9 Sep 2020 17:42:40 +0200 Subject: [PATCH 25/28] Add option to set user information via `SentryUserProvider` (#549) --- .../spring/boot/SecurityConfiguration.java | 22 +-- .../samples/spring/SecurityConfiguration.java | 22 +-- .../spring/boot/SentryAutoConfiguration.java | 7 + .../boot/SentrySpringIntegrationTest.kt | 13 +- .../HttpServletRequestSentryUserProvider.java | 55 ++++++++ .../spring/SentryInitBeanPostProcessor.java | 25 +++- .../sentry/spring/SentrySecurityFilter.java | 54 -------- ...SentryUserHttpServletRequestProcessor.java | 45 ------ .../io/sentry/spring/SentryUserProvider.java | 17 +++ .../SentryUserProviderEventProcessor.java | 48 +++++++ .../sentry/spring/SentryWebConfiguration.java | 8 ++ ...ttpServletRequestSentryUserProviderTest.kt | 64 +++++++++ .../spring/SentrySpringIntegrationTest.kt | 12 +- ...ntryUserHttpServletRequestProcessorTest.kt | 55 -------- ...erProviderEventProcessorIntegrationTest.kt | 93 +++++++++++++ .../SentryUserProviderEventProcessorTest.kt | 130 ++++++++++++++++++ 16 files changed, 451 insertions(+), 219 deletions(-) create mode 100644 sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java delete mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java delete mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java create mode 100644 sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java create mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt delete mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt create mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt create mode 100644 sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java index 417f0541d..bc1c312b0 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SecurityConfiguration.java @@ -1,8 +1,5 @@ package io.sentry.samples.spring.boot; -import io.sentry.core.IHub; -import io.sentry.core.SentryOptions; -import io.sentry.spring.SentrySecurityFilter; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,32 +11,15 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - private final @NotNull IHub hub; - private final @NotNull SentryOptions options; - - public SecurityConfiguration(final @NotNull IHub hub, final @NotNull SentryOptions options) { - this.hub = hub; - this.options = options; - } - // this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed. @Override @SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]") protected void configure(final @NotNull HttpSecurity http) throws Exception { - // register SentrySecurityFilter to attach user information to SentryEvents - http.addFilterAfter(new SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter.class) - .csrf() - .disable() - .authorizeRequests() - .anyRequest() - .authenticated() - .and() - .httpBasic(); + http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic(); } @Bean diff --git a/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java index 7c3c87acf..7f6f6fe31 100644 --- a/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java +++ b/sentry-samples/sentry-samples-spring/src/main/java/io/sentry/samples/spring/SecurityConfiguration.java @@ -1,8 +1,5 @@ package io.sentry.samples.spring; -import io.sentry.core.IHub; -import io.sentry.core.SentryOptions; -import io.sentry.spring.SentrySecurityFilter; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,32 +11,15 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - private final @NotNull IHub hub; - private final @NotNull SentryOptions options; - - public SecurityConfiguration(final @NotNull IHub hub, final @NotNull SentryOptions options) { - this.hub = hub; - this.options = options; - } - // this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed. @Override @SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]") protected void configure(final @NotNull HttpSecurity http) throws Exception { - // register SentrySecurityFilter to attach user information to SentryEvents - http.addFilterAfter(new SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter.class) - .csrf() - .disable() - .authorizeRequests() - .anyRequest() - .authenticated() - .and() - .httpBasic(); + http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic(); } @Bean diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index 67eacc224..f47cf467c 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -10,6 +10,8 @@ import io.sentry.core.protocol.SdkVersion; import io.sentry.core.transport.ITransport; import io.sentry.core.transport.ITransportGate; +import io.sentry.spring.SentryUserProvider; +import io.sentry.spring.SentryUserProviderEventProcessor; import io.sentry.spring.SentryWebConfiguration; import java.util.List; import org.jetbrains.annotations.NotNull; @@ -43,12 +45,17 @@ static class HubConfiguration { final @NotNull List eventProcessors, final @NotNull List integrations, final @NotNull ObjectProvider transportGate, + final @NotNull ObjectProvider sentryUserProviders, final @NotNull ObjectProvider transport) { return options -> { beforeSendCallback.ifAvailable(options::setBeforeSend); beforeBreadcrumbCallback.ifAvailable(options::setBeforeBreadcrumb); eventProcessors.forEach(options::addEventProcessor); integrations.forEach(options::addIntegration); + sentryUserProviders.forEach( + sentryUserProvider -> + options.addEventProcessor( + new SentryUserProviderEventProcessor(sentryUserProvider))); transportGate.ifAvailable(options::setTransportGate); transport.ifAvailable(options::setTransport); }; diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt index 79f9cb6a9..36aef8f0d 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -1,11 +1,8 @@ package io.sentry.spring.boot import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.IHub import io.sentry.core.Sentry -import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport -import io.sentry.spring.SentrySecurityFilter import io.sentry.test.checkEvent import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat @@ -30,7 +27,6 @@ import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.crypto.factory.PasswordEncoderFactories import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.provisioning.InMemoryUserDetailsManager -import org.springframework.security.web.authentication.AnonymousAuthenticationFilter import org.springframework.test.context.junit4.SpringRunner import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @@ -120,15 +116,10 @@ class HelloController { } @Configuration -open class SecurityConfiguration( - private val hub: IHub, - private val options: SentryOptions -) : WebSecurityConfigurerAdapter() { +open class SecurityConfiguration : WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { - http - .addFilterAfter(SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter::class.java) - .csrf().disable() + http.csrf().disable() .authorizeRequests().anyRequest().authenticated() .and() .httpBasic() diff --git a/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java b/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java new file mode 100644 index 000000000..55776b82a --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java @@ -0,0 +1,55 @@ +package io.sentry.spring; + +import io.sentry.core.SentryOptions; +import io.sentry.core.protocol.User; +import io.sentry.core.util.Objects; +import javax.servlet.http.HttpServletRequest; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * Resolves user information from {@link HttpServletRequest} obtained via {@link + * RequestContextHolder}. + */ +public final class HttpServletRequestSentryUserProvider implements SentryUserProvider { + private final @NotNull SentryOptions options; + + public HttpServletRequestSentryUserProvider(final @NotNull SentryOptions options) { + this.options = Objects.requireNonNull(options, "options are required"); + } + + @Override + public @Nullable User provideUser() { + if (options.isSendDefaultPii()) { + final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes instanceof ServletRequestAttributes) { + final ServletRequestAttributes servletRequestAttributes = + (ServletRequestAttributes) requestAttributes; + final HttpServletRequest request = servletRequestAttributes.getRequest(); + + final User user = new User(); + user.setIpAddress(toIpAddress(request)); + if (request.getUserPrincipal() != null) { + user.setUsername(request.getUserPrincipal().getName()); + } + return user; + } + } + return null; + } + + // it is advised to not use `String#split` method but since we do not have 3rd party libraries + // this is our only option. + @SuppressWarnings("StringSplitter") + private static @NotNull String toIpAddress(final @NotNull HttpServletRequest request) { + final String ipAddress = request.getHeader("X-FORWARDED-FOR"); + if (ipAddress != null) { + return ipAddress.contains(",") ? ipAddress.split(",")[0].trim() : ipAddress; + } else { + return request.getRemoteAddr(); + } + } +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java index ddc350a3e..3bae29feb 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java @@ -4,18 +4,39 @@ import io.sentry.core.Sentry; import io.sentry.core.SentryOptions; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; /** Initializes Sentry after all beans are registered. */ @Open -public class SentryInitBeanPostProcessor implements BeanPostProcessor { +public class SentryInitBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware { + private @Nullable ApplicationContext applicationContext; + @Override public Object postProcessAfterInitialization( final @NotNull Object bean, @NotNull final String beanName) throws BeansException { if (bean instanceof SentryOptions) { - Sentry.init((SentryOptions) bean); + final SentryOptions options = (SentryOptions) bean; + + if (applicationContext != null) { + applicationContext + .getBeanProvider(SentryUserProvider.class) + .forEach( + sentryUserProvider -> + options.addEventProcessor( + new SentryUserProviderEventProcessor(sentryUserProvider))); + } + Sentry.init(options); } return bean; } + + @Override + public void setApplicationContext(final @NotNull ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java b/sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java deleted file mode 100644 index 3d0d8d7ea..000000000 --- a/sentry-spring/src/main/java/io/sentry/spring/SentrySecurityFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.sentry.spring; - -import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.IHub; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.jetbrains.annotations.NotNull; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * Adds {@link SentryUserHttpServletRequestProcessor} to the scope in order to decorate {@link - * io.sentry.core.SentryEvent} with principal name and user ip address. - */ -@Open -public class SentrySecurityFilter extends OncePerRequestFilter { - private final @NotNull IHub hub; - private final @NotNull SentryOptions options; - - public SentrySecurityFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) { - this.hub = Objects.requireNonNull(hub, "hub is required"); - this.options = Objects.requireNonNull(options, "options are required"); - } - - @Override - protected void doFilterInternal( - final @NotNull HttpServletRequest request, - final @NotNull HttpServletResponse response, - final @NotNull FilterChain filterChain) - throws ServletException, IOException { - hub.configureScope( - scope -> - scope.addEventProcessor( - new SentryUserHttpServletRequestProcessor( - request.getUserPrincipal(), toIpAddress(request), options))); - filterChain.doFilter(request, response); - } - - // it is advised to not use `String#split` method but since we do not have 3rd party libraries - // this is our only option. - @SuppressWarnings("StringSplitter") - private static @NotNull String toIpAddress(final @NotNull HttpServletRequest request) { - final String ipAddress = request.getHeader("X-FORWARDED-FOR"); - if (ipAddress != null) { - return ipAddress.contains(",") ? ipAddress.split(",")[0].trim() : ipAddress; - } else { - return request.getRemoteAddr(); - } - } -} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java deleted file mode 100644 index 1e5fbf72b..000000000 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryUserHttpServletRequestProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.sentry.spring; - -import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.EventProcessor; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.User; -import java.security.Principal; -import java.util.Optional; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** Attaches user information to the {@link SentryEvent}. */ -@Open -public class SentryUserHttpServletRequestProcessor implements EventProcessor { - private final @Nullable Principal principal; - private final @Nullable String ipAddress; - private final @NotNull SentryOptions options; - - public SentryUserHttpServletRequestProcessor( - final @Nullable Principal principal, - final @Nullable String ipAddress, - final @NotNull SentryOptions options) { - this.principal = principal; - this.ipAddress = ipAddress; - this.options = options; - } - - @Override - public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) { - if (options.isSendDefaultPii()) { - final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new); - - if (ipAddress != null) { - user.setIpAddress(ipAddress); - } - if (principal != null) { - user.setUsername(principal.getName()); - } - - event.setUser(user); - } - return event; - } -} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java new file mode 100644 index 000000000..724e5676a --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java @@ -0,0 +1,17 @@ +package io.sentry.spring; + +import io.sentry.core.protocol.User; +import org.jetbrains.annotations.Nullable; + +/** + * Provides user information that's set on {@link io.sentry.core.SentryEvent} using {@link + * SentryUserProviderEventProcessor}. + * + *

Out of the box Spring integration configures single {@link SentryUserProvider} - {@link + * HttpServletRequestSentryUserProvider}. + */ +@FunctionalInterface +public interface SentryUserProvider { + @Nullable + User provideUser(); +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java new file mode 100644 index 000000000..687b7b768 --- /dev/null +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java @@ -0,0 +1,48 @@ +package io.sentry.spring; + +import io.sentry.core.EventProcessor; +import io.sentry.core.SentryEvent; +import io.sentry.core.protocol.User; +import io.sentry.core.util.Objects; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class SentryUserProviderEventProcessor implements EventProcessor { + private final @NotNull SentryUserProvider sentryUserProvider; + + public SentryUserProviderEventProcessor(final @NotNull SentryUserProvider sentryUserProvider) { + this.sentryUserProvider = + Objects.requireNonNull(sentryUserProvider, "sentryUserProvider is required"); + } + + @Override + public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) { + final User user = sentryUserProvider.provideUser(); + if (user != null) { + final User existingUser = Optional.ofNullable(event.getUser()).orElseGet(User::new); + + Optional.ofNullable(user.getEmail()).ifPresent(existingUser::setEmail); + Optional.ofNullable(user.getId()).ifPresent(existingUser::setId); + Optional.ofNullable(user.getIpAddress()).ifPresent(existingUser::setIpAddress); + Optional.ofNullable(user.getUsername()).ifPresent(existingUser::setUsername); + if (user.getOthers() != null && !user.getOthers().isEmpty()) { + if (existingUser.getOthers() == null) { + existingUser.setOthers(new ConcurrentHashMap<>()); + } + for (Map.Entry entry : user.getOthers().entrySet()) { + existingUser.getOthers().put(entry.getKey(), entry.getValue()); + } + } + event.setUser(existingUser); + } + return event; + } + + @NotNull + SentryUserProvider getSentryUserProvider() { + return sentryUserProvider; + } +} diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java index 47e8731c5..902f6b449 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java @@ -6,12 +6,20 @@ import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; /** Registers Spring Web specific Sentry beans. */ @Configuration @Open public class SentryWebConfiguration { + @Bean + @Lazy + public @NotNull HttpServletRequestSentryUserProvider httpServletRequestSentryUserProvider( + final @NotNull SentryOptions sentryOptions) { + return new HttpServletRequestSentryUserProvider(sentryOptions); + } + @Bean public @NotNull SentryRequestFilter sentryRequestFilter( final @NotNull IHub sentryHub, final @NotNull SentryOptions sentryOptions) { diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt new file mode 100644 index 000000000..aa9c1529f --- /dev/null +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt @@ -0,0 +1,64 @@ +package io.sentry.spring + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.core.SentryOptions +import java.security.Principal +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.web.context.request.RequestContextHolder +import org.springframework.web.context.request.ServletRequestAttributes + +class HttpServletRequestSentryUserProviderTest { + + @Test + fun `attaches user's IP address to Sentry Event`() { + val request = MockHttpServletRequest() + request.addHeader("X-FORWARDED-FOR", "192.168.0.1,192.168.0.2") + RequestContextHolder.setRequestAttributes(ServletRequestAttributes(request)) + + val options = SentryOptions() + options.isSendDefaultPii = true + val userProvider = HttpServletRequestSentryUserProvider(options) + val result = userProvider.provideUser() + + assertNotNull(result) + assertEquals("192.168.0.1", result.ipAddress) + } + + @Test + fun `attaches username to Sentry Event`() { + val principal = mock() + whenever(principal.name).thenReturn("janesmith") + val request = MockHttpServletRequest() + request.userPrincipal = principal + RequestContextHolder.setRequestAttributes(ServletRequestAttributes(request)) + + val options = SentryOptions() + options.isSendDefaultPii = true + val userProvider = HttpServletRequestSentryUserProvider(options) + val result = userProvider.provideUser() + + assertNotNull(result) + assertEquals("janesmith", result.username) + } + + @Test + fun `when sendDefaultPii is set to false, does not attach user data Sentry Event`() { + val principal = mock() + whenever(principal.name).thenReturn("janesmith") + val request = MockHttpServletRequest() + request.userPrincipal = principal + RequestContextHolder.setRequestAttributes(ServletRequestAttributes(request)) + + val options = SentryOptions() + options.isSendDefaultPii = false + val userProvider = HttpServletRequestSentryUserProvider(options) + val result = userProvider.provideUser() + + assertNull(result) + } +} diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt index 2a78d4a80..6ac380819 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt @@ -3,9 +3,7 @@ package io.sentry.spring import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.IHub import io.sentry.core.Sentry -import io.sentry.core.SentryOptions import io.sentry.core.transport.ITransport import io.sentry.test.checkEvent import java.lang.RuntimeException @@ -32,7 +30,6 @@ import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.crypto.factory.PasswordEncoderFactories import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.provisioning.InMemoryUserDetailsManager -import org.springframework.security.web.authentication.AnonymousAuthenticationFilter import org.springframework.test.context.junit4.SpringRunner import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @@ -131,15 +128,10 @@ class HelloController { } @Configuration -open class SecurityConfiguration( - private val hub: IHub, - private val options: SentryOptions -) : WebSecurityConfigurerAdapter() { +open class SecurityConfiguration : WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { - http - .addFilterAfter(SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter::class.java) - .csrf().disable() + http.csrf().disable() .authorizeRequests().anyRequest().authenticated() .and() .httpBasic() diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt deleted file mode 100644 index 6a8e2598b..000000000 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserHttpServletRequestProcessorTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.sentry.spring - -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions -import java.security.Principal -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class SentryUserHttpServletRequestProcessorTest { - - @Test - fun `attaches user's IP address to Sentry Event`() { - val options = SentryOptions() - options.isSendDefaultPii = true - val eventProcessor = SentryUserHttpServletRequestProcessor(null, "192.168.0.1", options) - val event = SentryEvent() - - eventProcessor.process(event, null) - - assertEquals("192.168.0.1", event.user.ipAddress) - } - - @Test - fun `attaches username to Sentry Event`() { - val principal = mock() - whenever(principal.name).thenReturn("janesmith") - - val options = SentryOptions() - options.isSendDefaultPii = true - val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null, options) - val event = SentryEvent() - - eventProcessor.process(event, null) - - assertEquals("janesmith", event.user.username) - } - - @Test - fun `when sendDefaultPii is set to false, does not attach user data Sentry Event`() { - val principal = mock() - whenever(principal.name).thenReturn("janesmith") - - val options = SentryOptions() - options.isSendDefaultPii = false - val eventProcessor = SentryUserHttpServletRequestProcessor(principal, null, options) - val event = SentryEvent() - - eventProcessor.process(event, null) - - assertNull(event.user) - } -} diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt new file mode 100644 index 000000000..8de2d92eb --- /dev/null +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt @@ -0,0 +1,93 @@ +package io.sentry.spring + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.reset +import com.nhaarman.mockitokotlin2.verify +import io.sentry.core.Sentry +import io.sentry.core.SentryEvent +import io.sentry.core.SentryOptions +import io.sentry.core.protocol.User +import io.sentry.core.transport.ITransport +import io.sentry.test.checkEvent +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.kotlin.await +import org.springframework.boot.context.annotation.UserConfigurations +import org.springframework.boot.test.context.runner.ApplicationContextRunner +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +class SentryUserProviderEventProcessorIntegrationTest { + + @Test + fun `when SentryUserProvider bean is configured, sets user provided user data`() { + ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfig::class.java, SentryUserProviderConfiguration::class.java)) + .run { + val transport = it.getBean(ITransport::class.java) + reset(transport) + + Sentry.captureMessage("test message") + await.untilAsserted { + verify(transport).send(checkEvent { event: SentryEvent -> + assertThat(event.user).isNotNull + assertThat(event.user.username).isEqualTo("john.smith") + }) + } + } + } + + @Test + fun `when SentryUserProvider bean is not configured, user data is not set`() { + ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfig::class.java)) + .run { + val transport = it.getBean(ITransport::class.java) + reset(transport) + + Sentry.captureMessage("test message") + await.untilAsserted { + verify(transport).send(checkEvent { event: SentryEvent -> + assertThat(event.user).isNull() + }) + } + } + } + + @Test + fun `when custom SentryUserProvider bean is configured, it's added after HttpServletRequestSentryUserProvider`() { + ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(AppConfig::class.java, SentryUserProviderConfiguration::class.java)) + .run { + val options = it.getBean(SentryOptions::class.java) + val userProviderEventProcessors = options.eventProcessors.filterIsInstance() + assertEquals(2, userProviderEventProcessors.size) + assertTrue(userProviderEventProcessors[0].sentryUserProvider is HttpServletRequestSentryUserProvider) + assertTrue(userProviderEventProcessors[1].sentryUserProvider is CustomSentryUserProvider) + } + } + + @EnableSentry(dsn = "http://key@localhost/proj") + open class AppConfig { + + @Bean + open fun mockTransport() = mock() + } + + @Configuration + open class SentryUserProviderConfiguration { + + @Bean + open fun userProvider() = CustomSentryUserProvider() + } + + open class CustomSentryUserProvider : SentryUserProvider { + override fun provideUser(): User? { + val user = User() + user.username = "john.smith" + return user + } + } +} diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt new file mode 100644 index 000000000..8f0d4ae84 --- /dev/null +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt @@ -0,0 +1,130 @@ +package io.sentry.spring + +import io.sentry.core.SentryEvent +import io.sentry.core.protocol.User +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class SentryUserProviderEventProcessorTest { + + @Test + fun `when event user is null, provider user data is set`() { + + val processor = SentryUserProviderEventProcessor { + val user = User() + user.username = "john.doe" + user.id = "user-id" + user.ipAddress = "192.168.0.1" + user.email = "john.doe@example.com" + user.others = mapOf("key" to "value") + user + } + + val event = SentryEvent() + val result = processor.process(event, null) + + assertNotNull(result) + assertNotNull(result.user) + assertEquals("john.doe", result.user.username) + assertEquals("user-id", result.user.id) + assertEquals("192.168.0.1", result.user.ipAddress) + assertEquals("john.doe@example.com", result.user.email) + assertEquals(mapOf("key" to "value"), result.user.others) + } + + @Test + fun `when event user is empty, provider user data is set`() { + val processor = SentryUserProviderEventProcessor { + val user = User() + user.username = "john.doe" + user.id = "user-id" + user.ipAddress = "192.168.0.1" + user.email = "john.doe@example.com" + user.others = mapOf("key" to "value") + user + } + + val event = SentryEvent() + event.user = User() + val result = processor.process(event, null) + + assertNotNull(result) + assertNotNull(result.user) + assertEquals("john.doe", result.user.username) + assertEquals("user-id", result.user.id) + assertEquals("192.168.0.1", result.user.ipAddress) + assertEquals("john.doe@example.com", result.user.email) + assertEquals(mapOf("key" to "value"), result.user.others) + } + + @Test + fun `when processor returns empty User, user data is not changed`() { + val processor = SentryUserProviderEventProcessor { + val user = User() + user + } + + val event = SentryEvent() + event.user = User() + event.user.username = "jane.smith" + event.user.id = "jane-smith" + event.user.ipAddress = "192.168.0.3" + event.user.email = "jane.smith@example.com" + event.user.others = mapOf("key" to "value") + + val result = processor.process(event, null) + + assertNotNull(result) + assertNotNull(result.user) + assertEquals("jane.smith", result.user.username) + assertEquals("jane-smith", result.user.id) + assertEquals("192.168.0.3", result.user.ipAddress) + assertEquals("jane.smith@example.com", result.user.email) + assertEquals(mapOf("key" to "value"), result.user.others) + } + + @Test + fun `when processor returns null, user data is not changed`() { + val processor = SentryUserProviderEventProcessor { + null + } + + val event = SentryEvent() + event.user = User() + event.user.username = "jane.smith" + event.user.id = "jane-smith" + event.user.ipAddress = "192.168.0.3" + event.user.email = "jane.smith@example.com" + event.user.others = mapOf("key" to "value") + + val result = processor.process(event, null) + + assertNotNull(result) + assertNotNull(result.user) + assertEquals("jane.smith", result.user.username) + assertEquals("jane-smith", result.user.id) + assertEquals("192.168.0.3", result.user.ipAddress) + assertEquals("jane.smith@example.com", result.user.email) + assertEquals(mapOf("key" to "value"), result.user.others) + } + + @Test + fun `merges user#others with existing user#others set on SentryEvent`() { + val processor = SentryUserProviderEventProcessor { + val user = User() + user.others = mapOf("key" to "value") + user + } + + val event = SentryEvent() + event.user = User() + event.user.others = mapOf("new-key" to "new-value") + + val result = processor.process(event, null) + + assertNotNull(result) + assertNotNull(result.user) + assertEquals(mapOf("key" to "value", "new-key" to "new-value"), result.user.others) + } +} From 6d02f9875a9c6eff54428e29232bd35bf3f11124 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Thu, 10 Sep 2020 19:50:45 +0200 Subject: [PATCH 26/28] upgrade cache id --- .github/workflows/android.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 4919ee6c7..ded8f5615 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -44,13 +44,13 @@ jobs: uses: actions/cache@v1 with: path: ~/.gradle/caches/ - key: cache-gradle-cache-2 + key: cache-gradle-cache-3 - name: Cache Gradle Wrapper uses: actions/cache@v1 with: path: ~/.gradle/wrapper/ - key: cache-gradle-wrapper-2 + key: cache-gradle-wrapper-3 # uses eskatos/gradle-command-action, so we don't care for ./gradlew or gradlew.bat From dd0e7d82da7ddede0d6bd751c5f51d79685392e4 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 10 Sep 2020 21:10:48 +0200 Subject: [PATCH 27/28] Feat/sentry java fix kotlin (#552) --- buildSrc/src/main/java/Config.kt | 2 ++ gradle.properties | 3 +++ sentry-spring-boot-starter/build.gradle.kts | 1 + sentry-spring/build.gradle.kts | 1 + sentry-test-support/build.gradle.kts | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 33d13ac71..3ebc6dd1e 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -5,6 +5,8 @@ object Config { val kotlinStdLib = "stdlib-jdk8" val springBootVersion = "2.3.3.RELEASE" + // Spring is currently not compatible with Kotlin 1.4 + val springKotlinCompatibleLanguageVersion = "1.3" object BuildPlugins { val androidGradle = "com.android.tools.build:gradle:4.0.1" diff --git a/gradle.properties b/gradle.properties index cce174a00..e93deafa5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,6 +23,9 @@ android.defaults.buildfeatures.aidl=false # disable Resource Values generation android.defaults.buildfeatures.resvalues=false +# disable automatically adding Kotlin stdlib to compile dependencies +kotlin.stdlib.default.dependency=false + # TODO: Enable Prefab https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html # android.enablePrefab=true # android.prefabVersion=1.0.0 diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts index 0ca7e13e1..a2adf698b 100644 --- a/sentry-spring-boot-starter/build.gradle.kts +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -29,6 +29,7 @@ configure { tasks.withType().configureEach { kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() + kotlinOptions.languageVersion = Config.springKotlinCompatibleLanguageVersion } dependencies { diff --git a/sentry-spring/build.gradle.kts b/sentry-spring/build.gradle.kts index d50389923..31d69e95a 100644 --- a/sentry-spring/build.gradle.kts +++ b/sentry-spring/build.gradle.kts @@ -29,6 +29,7 @@ configure { tasks.withType().configureEach { kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() + kotlinOptions.languageVersion = Config.springKotlinCompatibleLanguageVersion } dependencies { diff --git a/sentry-test-support/build.gradle.kts b/sentry-test-support/build.gradle.kts index f36a71742..fefac4ef7 100644 --- a/sentry-test-support/build.gradle.kts +++ b/sentry-test-support/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { compileOnly(Config.CompileOnly.jetbrainsAnnotations) // tests - api(kotlin(Config.kotlinStdLib)) + implementation(kotlin(Config.kotlinStdLib)) implementation(Config.TestLibs.kotlinTestJunit) implementation(Config.TestLibs.mockitoKotlin) } From 188ef14f39f0969ff224250cc82130182aef238b Mon Sep 17 00:00:00 2001 From: Bruno Garcia Date: Thu, 10 Sep 2020 18:40:59 -0400 Subject: [PATCH 28/28] ref: sentry-core to sentry (#553) --- sentry-android-core/build.gradle.kts | 2 +- sentry-android-core/proguard-rules.pro | 2 +- .../io/sentry/android/core/ANRWatchDog.java | 4 +-- .../core/ActivityBreadcrumbsIntegration.java | 12 +++---- .../io/sentry/android/core/AndroidLogger.java | 4 +-- .../core/AndroidOptionsInitializer.java | 16 ++++----- .../android/core/AndroidTransportGate.java | 4 +-- .../sentry/android/core/AnrIntegration.java | 16 ++++----- .../AppComponentsBreadcrumbsIntegration.java | 14 ++++---- .../android/core/AppLifecycleIntegration.java | 10 +++--- .../core/ApplicationNotResponding.java | 2 +- .../io/sentry/android/core/ContextUtils.java | 4 +-- .../core/DefaultAndroidEventProcessor.java | 28 +++++++-------- .../android/core/EnvelopeFileObserver.java | 20 +++++------ .../core/EnvelopeFileObserverIntegration.java | 14 ++++---- .../sentry/android/core/LifecycleWatcher.java | 10 +++--- .../android/core/ManifestMetadataReader.java | 6 ++-- .../sentry/android/core/NdkIntegration.java | 10 +++--- .../PhoneStateBreadcrumbsIntegration.java | 12 +++---- .../io/sentry/android/core/SentryAndroid.java | 8 ++--- .../android/core/SentryAndroidOptions.java | 4 +-- .../android/core/SentryInitProvider.java | 4 +-- .../SystemEventsBreadcrumbsIntegration.java | 16 ++++----- .../TempSensorBreadcrumbsIntegration.java | 12 +++---- .../core/util/ConnectivityChecker.java | 4 +-- .../android/core/util/DeviceOrientations.java | 2 +- .../android/core/util/MainThreadChecker.java | 2 +- .../sentry/android/core/util/Permissions.java | 2 +- .../sentry/android/core/util/RootChecker.java | 6 ++-- .../ActivityBreadcrumbsIntegrationTest.kt | 6 ++-- .../core/AndroidOptionsInitializerTest.kt | 10 +++--- .../sentry/android/core/AnrIntegrationTest.kt | 2 +- ...AppComponentsBreadcrumbsIntegrationTest.kt | 6 ++-- .../core/AppLifecycleIntegrationTest.kt | 2 +- .../io/sentry/android/core/CachedEvent.kt | 2 +- .../core/DefaultAndroidEventProcessorTest.kt | 14 ++++---- .../EnvelopeFileObserverIntegrationTest.kt | 6 ++-- .../android/core/EnvelopeFileObserverTest.kt | 8 ++--- .../android/core/LifecycleWatcherTest.kt | 8 ++--- .../core/ManifestMetadataReaderTest.kt | 4 +-- .../sentry/android/core/NdkIntegrationTest.kt | 6 ++-- .../PhoneStateBreadcrumbsIntegrationTest.kt | 6 ++-- .../android/core/SentryAndroidOptionsTest.kt | 2 +- .../sentry/android/core/SentryAndroidTest.kt | 6 ++-- .../android/core/SentryInitProviderTest.kt | 6 ++-- .../java/io/sentry/android/core/SentryNdk.kt | 2 +- .../SystemEventsBreadcrumbsIntegrationTest.kt | 6 ++-- .../TempSensorBreadcrumbsIntegrationTest.kt | 6 ++-- .../core/util/DeviceOrientationsTest.kt | 2 +- .../core/util/MainThreadCheckerTest.kt | 2 +- .../android/core/util/RootCheckerTest.kt | 2 +- sentry-android-ndk/build.gradle.kts | 2 +- .../java/io/sentry/android/ndk/SentryNdk.java | 2 +- .../io/sentry/android/ndk/SentryNdkUtil.java | 2 +- .../sentry/android/ndk/SentryNdkUtilTest.kt | 2 +- sentry-android-timber/build.gradle.kts | 2 +- .../android/timber/SentryTimberIntegration.kt | 12 +++---- .../sentry/android/timber/SentryTimberTree.kt | 10 +++--- .../timber/SentryTimberIntegrationTest.kt | 8 ++--- .../android/timber/SentryTimberTreeTest.kt | 8 ++--- .../java/io/sentry/core/SentryEventKtx.kt | 2 +- .../test/java/io/sentry/core/CachedEvent.kt | 5 --- sentry-log4j2/build.gradle.kts | 2 +- .../java/io/sentry/log4j2/SentryAppender.java | 24 ++++++------- .../io/sentry/log4j2/SentryAppenderTest.kt | 6 ++-- sentry-logback/build.gradle.kts | 2 +- .../io/sentry/logback/SentryAppender.java | 20 +++++------ .../io/sentry/logback/SentryAppenderTest.kt | 8 ++--- .../java/io/sentry/sample/MainActivity.java | 4 +-- .../sentry-samples-console/build.gradle.kts | 2 +- .../java/io/sentry/samples/console/Main.java | 14 ++++---- .../spring/boot/CustomEventProcessor.java | 6 ++-- sentry-spring-boot-starter/build.gradle.kts | 2 +- .../spring/boot/SentryAutoConfiguration.java | 18 +++++----- .../sentry/spring/boot/SentryProperties.java | 2 +- .../boot/SentryAutoConfigurationTest.kt | 20 +++++------ .../boot/SentrySpringIntegrationTest.kt | 4 +-- sentry-spring/build.gradle.kts | 2 +- .../java/io/sentry/spring/EnableSentry.java | 4 +-- .../HttpServletRequestSentryUserProvider.java | 6 ++-- .../spring/SentryExceptionResolver.java | 12 +++---- .../io/sentry/spring/SentryHubRegistrar.java | 6 ++-- .../spring/SentryInitBeanPostProcessor.java | 4 +-- .../io/sentry/spring/SentryRequestFilter.java | 10 +++--- ...tryRequestHttpServletRequestProcessor.java | 10 +++--- .../io/sentry/spring/SentryUserProvider.java | 4 +-- .../SentryUserProviderEventProcessor.java | 8 ++--- .../sentry/spring/SentryWebConfiguration.java | 4 +-- .../io/sentry/spring/EnableSentryTest.kt | 4 +-- ...ttpServletRequestSentryUserProviderTest.kt | 2 +- ...yRequestHttpServletRequestProcessorTest.kt | 4 +-- .../spring/SentrySpringIntegrationTest.kt | 4 +-- ...erProviderEventProcessorIntegrationTest.kt | 10 +++--- .../SentryUserProviderEventProcessorTest.kt | 4 +-- sentry-test-support/build.gradle.kts | 2 +- .../main/kotlin/io/sentry/test/assertions.kt | 10 +++--- {sentry-core => sentry}/build.gradle.kts | 2 +- .../io/sentry}/AsyncConnectionFactory.java | 6 ++-- .../src/main/java/io/sentry}/Breadcrumb.java | 4 +-- .../java/io/sentry}/CircularFifoQueue.java | 2 +- .../CredentialsSettingConfigurator.java | 4 +-- .../src/main/java/io/sentry}/DateUtils.java | 2 +- .../java/io/sentry}/DiagnosticLogger.java | 4 +-- .../java/io/sentry}/DirectoryProcessor.java | 12 +++---- .../src/main/java/io/sentry}/Dsn.java | 2 +- ...DuplicateEventDetectionEventProcessor.java | 6 ++-- .../main/java/io/sentry}/EnvelopeReader.java | 2 +- .../main/java/io/sentry}/EnvelopeSender.java | 12 +++---- .../main/java/io/sentry}/EventProcessor.java | 2 +- .../main/java/io/sentry}/GsonSerializer.java | 34 +++++++++---------- .../java/io/sentry}/HttpTransportFactory.java | 8 ++--- .../src/main/java/io/sentry}/Hub.java | 12 +++---- .../src/main/java/io/sentry}/HubAdapter.java | 6 ++-- .../main/java/io/sentry}/IEnvelopeReader.java | 2 +- .../main/java/io/sentry}/IEnvelopeSender.java | 2 +- .../src/main/java/io/sentry}/IHub.java | 6 ++-- .../src/main/java/io/sentry}/ILogger.java | 2 +- .../main/java/io/sentry}/ISentryClient.java | 6 ++-- .../io/sentry}/ISentryExecutorService.java | 2 +- .../src/main/java/io/sentry}/ISerializer.java | 2 +- .../sentry}/IUnknownPropertiesConsumer.java | 2 +- .../src/main/java/io/sentry}/Integration.java | 2 +- .../java/io/sentry}/InvalidDsnException.java | 2 +- .../java/io/sentry}/MainEventProcessor.java | 8 ++--- .../java/io/sentry}/NoOpEnvelopeReader.java | 2 +- .../src/main/java/io/sentry}/NoOpHub.java | 6 ++-- .../src/main/java/io/sentry}/NoOpLogger.java | 2 +- .../java/io/sentry}/NoOpSentryClient.java | 4 +-- .../main/java/io/sentry}/NoOpSerializer.java | 2 +- .../java/io/sentry}/OptionsContainer.java | 2 +- .../main/java/io/sentry}/OutboxSender.java | 18 +++++----- .../src/main/java/io/sentry}/Scope.java | 6 ++-- .../main/java/io/sentry}/ScopeCallback.java | 2 +- ...achedEnvelopeFireAndForgetIntegration.java | 4 +-- .../SendFireAndForgetEnvelopeSender.java | 4 +-- .../SendFireAndForgetOutboxSender.java | 4 +-- .../src/main/java/io/sentry}/Sentry.java | 8 ++--- .../main/java/io/sentry}/SentryClient.java | 18 +++++----- .../main/java/io/sentry}/SentryEnvelope.java | 8 ++--- .../java/io/sentry}/SentryEnvelopeHeader.java | 6 ++-- .../sentry}/SentryEnvelopeHeaderAdapter.java | 8 ++--- .../java/io/sentry}/SentryEnvelopeItem.java | 4 +-- .../io/sentry}/SentryEnvelopeItemHeader.java | 4 +-- .../SentryEnvelopeItemHeaderAdapter.java | 4 +-- .../src/main/java/io/sentry}/SentryEvent.java | 4 +-- .../io/sentry}/SentryExceptionFactory.java | 12 +++---- .../io/sentry}/SentryExecutorService.java | 2 +- .../main/java/io/sentry}/SentryItemType.java | 2 +- .../src/main/java/io/sentry}/SentryLevel.java | 2 +- .../main/java/io/sentry}/SentryOptions.java | 18 +++++----- .../io/sentry}/SentryStackTraceFactory.java | 4 +-- .../java/io/sentry}/SentryThreadFactory.java | 10 +++--- .../main/java/io/sentry}/SentryValues.java | 2 +- .../src/main/java/io/sentry}/Session.java | 4 +-- .../main/java/io/sentry}/SessionAdapter.java | 6 ++-- .../io/sentry}/ShutdownHookIntegration.java | 4 +-- .../io/sentry}/SynchronizedCollection.java | 2 +- .../java/io/sentry}/SynchronizedQueue.java | 2 +- .../main/java/io/sentry}/SystemOutLogger.java | 2 +- .../io/sentry}/UncaughtExceptionHandler.java | 2 +- .../UncaughtExceptionHandlerIntegration.java | 16 ++++----- .../UnknownPropertiesTypeAdapterFactory.java | 2 +- .../adapters/ContextsDeserializerAdapter.java | 20 +++++------ .../adapters/ContextsSerializerAdapter.java | 8 ++--- .../adapters/DateDeserializerAdapter.java | 8 ++--- .../adapters/DateSerializerAdapter.java | 8 ++--- .../OrientationDeserializerAdapter.java | 8 ++--- .../OrientationSerializerAdapter.java | 8 ++--- .../adapters/SentryIdDeserializerAdapter.java | 8 ++--- .../adapters/SentryIdSerializerAdapter.java | 8 ++--- .../SentryLevelDeserializerAdapter.java | 6 ++-- .../SentryLevelSerializerAdapter.java | 6 ++-- .../adapters/TimeZoneDeserializerAdapter.java | 6 ++-- .../adapters/TimeZoneSerializerAdapter.java | 6 ++-- .../java/io/sentry}/cache/CacheStrategy.java | 24 ++++++------- .../java/io/sentry}/cache/EnvelopeCache.java | 30 ++++++++-------- .../java/io/sentry}/cache/IEnvelopeCache.java | 4 +-- .../ExceptionMechanismException.java | 8 ++--- .../java/io/sentry}/hints/ApplyScopeData.java | 2 +- .../main/java/io/sentry}/hints/Cached.java | 2 +- .../sentry}/hints/DiskFlushNotification.java | 2 +- .../main/java/io/sentry}/hints/Flushable.java | 2 +- .../main/java/io/sentry}/hints/Retryable.java | 2 +- .../java/io/sentry}/hints/SessionEnd.java | 2 +- .../java/io/sentry}/hints/SessionEndHint.java | 2 +- .../java/io/sentry}/hints/SessionStart.java | 2 +- .../io/sentry}/hints/SessionStartHint.java | 2 +- .../io/sentry}/hints/SubmissionResult.java | 2 +- .../main/java/io/sentry}/protocol/App.java | 6 ++-- .../java/io/sentry}/protocol/Browser.java | 6 ++-- .../java/io/sentry}/protocol/Contexts.java | 2 +- .../java/io/sentry}/protocol/DebugImage.java | 4 +-- .../java/io/sentry}/protocol/DebugMeta.java | 4 +-- .../main/java/io/sentry}/protocol/Device.java | 6 ++-- .../main/java/io/sentry}/protocol/Gpu.java | 6 ++-- .../java/io/sentry}/protocol/Mechanism.java | 4 +-- .../java/io/sentry}/protocol/Message.java | 4 +-- .../io/sentry}/protocol/OperatingSystem.java | 6 ++-- .../java/io/sentry}/protocol/Request.java | 4 +-- .../java/io/sentry}/protocol/SdkInfo.java | 4 +-- .../java/io/sentry}/protocol/SdkVersion.java | 4 +-- .../io/sentry}/protocol/SentryException.java | 4 +-- .../java/io/sentry}/protocol/SentryId.java | 2 +- .../io/sentry}/protocol/SentryPackage.java | 4 +-- .../io/sentry}/protocol/SentryRuntime.java | 6 ++-- .../io/sentry}/protocol/SentryStackFrame.java | 4 +-- .../io/sentry}/protocol/SentryStackTrace.java | 4 +-- .../io/sentry}/protocol/SentryThread.java | 4 +-- .../main/java/io/sentry}/protocol/User.java | 6 ++-- .../io/sentry}/transport/AsyncConnection.java | 26 +++++++------- .../java/io/sentry}/transport/Connection.java | 4 +-- .../transport/CurrentDateProvider.java | 2 +- .../io/sentry}/transport/HttpTransport.java | 24 ++++++------- .../transport/IConnectionConfigurator.java | 2 +- .../transport/ICurrentDateProvider.java | 2 +- .../java/io/sentry}/transport/ITransport.java | 4 +-- .../io/sentry}/transport/ITransportGate.java | 2 +- .../sentry}/transport/NoOpEnvelopeCache.java | 6 ++-- .../io/sentry}/transport/NoOpTransport.java | 4 +-- .../sentry}/transport/NoOpTransportGate.java | 2 +- .../transport/QueuedThreadPoolExecutor.java | 6 ++-- .../io/sentry}/transport/StdoutTransport.java | 8 ++--- .../io/sentry}/transport/TransportResult.java | 4 +-- .../java/io/sentry}/util/ApplyScopeUtils.java | 6 ++-- .../java/io/sentry}/util/CollectionUtils.java | 2 +- .../main/java/io/sentry}/util/LogUtils.java | 6 ++-- .../main/java/io/sentry}/util/Objects.java | 2 +- .../java/io/sentry}/util/StringUtils.java | 2 +- .../test/java/io/sentry}/BreadcrumbTest.kt | 2 +- sentry/src/test/java/io/sentry/CachedEvent.kt | 5 +++ .../java/io/sentry}/CustomEventProcessor.kt | 2 +- .../src/test/java/io/sentry}/DateUtilsTest.kt | 2 +- .../java/io/sentry}/DiagnosticLoggerTest.kt | 2 +- .../java/io/sentry}/DirectoryProcessorTest.kt | 8 ++--- .../src/test/java/io/sentry}/DsnTest.kt | 2 +- ...plicateEventDetectionEventProcessorTest.kt | 6 ++-- .../java/io/sentry}/EnvelopeSenderTest.kt | 8 ++--- .../test/java/io/sentry}/FileFromResources.kt | 2 +- .../java/io/sentry}/GsonSerializerTest.kt | 8 ++--- .../io/sentry}/HttpTransportFactoryTest.kt | 2 +- .../src/test/java/io/sentry}/HubTest.kt | 10 +++--- .../java/io/sentry}/MainEventProcessorTest.kt | 8 ++--- .../src/test/java/io/sentry}/NoOpHubTest.kt | 4 +-- .../java/io/sentry}/NoOpSentryClientTest.kt | 4 +-- .../java/io/sentry}/NoOpSerializerTest.kt | 2 +- .../java/io/sentry}/OptionsContainerTest.kt | 2 +- .../test/java/io/sentry}/OutboxSenderTest.kt | 16 ++++----- .../src/test/java/io/sentry}/SampleDsn.kt | 2 +- .../src/test/java/io/sentry}/ScopeTest.kt | 4 +-- ...hedEnvelopeFireAndForgetIntegrationTest.kt | 2 +- .../test/java/io/sentry}/SentryClientTest.kt | 26 +++++++------- .../java/io/sentry}/SentryEnvelopeItemTest.kt | 4 +-- .../java/io/sentry}/SentryEnvelopeTest.kt | 2 +- .../test/java/io/sentry}/SentryEventTest.kt | 8 ++--- .../io/sentry}/SentryExceptionFactoryTest.kt | 6 ++-- .../io/sentry}/SentryExecutorServiceTest.kt | 2 +- .../java/io/sentry}/SentryItemTypeTest.kt | 2 +- .../test/java/io/sentry}/SentryOptionsTest.kt | 4 +-- .../io/sentry}/SentryStackTraceFactoryTest.kt | 2 +- .../src/test/java/io/sentry}/SentryTest.kt | 2 +- .../io/sentry}/SentryThreadFactoryTest.kt | 2 +- .../test/java/io/sentry}/SentryValuesTest.kt | 2 +- .../src/test/java/io/sentry}/SessionTest.kt | 4 +-- .../io/sentry}/ShutdownHookIntegrationTest.kt | 2 +- .../test/java/io/sentry}/StringExtensions.kt | 2 +- ...UncaughtExceptionHandlerIntegrationTest.kt | 8 ++--- .../io/sentry}/cache/CacheStrategyTest.kt | 12 +++---- .../io/sentry}/cache/EnvelopeCacheTest.kt | 24 ++++++------- .../test/java/io/sentry}/protocol/AppTest.kt | 2 +- .../java/io/sentry}/protocol/BrowserTest.kt | 2 +- .../java/io/sentry}/protocol/ContextsTest.kt | 2 +- .../java/io/sentry}/protocol/DeviceTest.kt | 2 +- .../test/java/io/sentry}/protocol/GpuTest.kt | 2 +- .../sentry}/protocol/OperatingSystemTest.kt | 2 +- .../io/sentry}/protocol/SentryRuntimeTest.kt | 2 +- .../test/java/io/sentry}/protocol/UserTest.kt | 2 +- .../sentry}/transport/AsyncConnectionTest.kt | 22 ++++++------ .../io/sentry}/transport/HttpTransportTest.kt | 14 ++++---- .../transport/QueuedThreadPoolExecutorTest.kt | 2 +- .../sentry}/transport/StdoutTransportTest.kt | 8 ++--- .../io/sentry}/util/ApplyScopeUtilsTest.kt | 6 ++-- .../test/java/io/sentry}/util/Extensions.kt | 4 +-- .../java/io/sentry}/util/StringUtilsTest.kt | 2 +- .../resources/envelope-event-attachment.txt | 0 .../test/resources/envelope-session-start.txt | 0 .../src/test/resources/envelope_session.txt | 0 .../resources/envelope_session_sdkversion.txt | 0 .../src/test/resources/event.json | 0 .../test/resources/event_breadcrumb_data.json | 0 .../test/resources/event_with_contexts.json | 0 .../org.mockito.plugins.MockMaker | 0 .../src/test/resources/session.json | 0 settings.gradle.kts | 4 +-- 293 files changed, 860 insertions(+), 860 deletions(-) delete mode 100644 sentry-core/src/test/java/io/sentry/core/CachedEvent.kt rename {sentry-core => sentry}/build.gradle.kts (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/AsyncConnectionFactory.java (81%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Breadcrumb.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/CircularFifoQueue.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/CredentialsSettingConfigurator.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/DateUtils.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/DiagnosticLogger.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/DirectoryProcessor.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Dsn.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/DuplicateEventDetectionEventProcessor.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/EnvelopeReader.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/EnvelopeSender.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/EventProcessor.java (86%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/GsonSerializer.java (88%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/HttpTransportFactory.java (83%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Hub.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/HubAdapter.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/IEnvelopeReader.java (91%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/IEnvelopeSender.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/IHub.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ILogger.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ISentryClient.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ISentryExecutorService.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ISerializer.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/IUnknownPropertiesConsumer.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Integration.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/InvalidDsnException.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/MainEventProcessor.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/NoOpEnvelopeReader.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/NoOpHub.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/NoOpLogger.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/NoOpSentryClient.java (92%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/NoOpSerializer.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/OptionsContainer.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/OutboxSender.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Scope.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ScopeCallback.java (71%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SendCachedEnvelopeFireAndForgetIntegration.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SendFireAndForgetEnvelopeSender.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SendFireAndForgetOutboxSender.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Sentry.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryClient.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelope.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelopeHeader.java (88%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelopeHeaderAdapter.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelopeItem.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelopeItemHeader.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEnvelopeItemHeaderAdapter.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryEvent.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryExceptionFactory.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryExecutorService.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryItemType.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryLevel.java (87%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryOptions.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryStackTraceFactory.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryThreadFactory.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SentryValues.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/Session.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SessionAdapter.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/ShutdownHookIntegration.java (92%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SynchronizedCollection.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SynchronizedQueue.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/SystemOutLogger.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/UncaughtExceptionHandler.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/UncaughtExceptionHandlerIntegration.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/UnknownPropertiesTypeAdapterFactory.java (99%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/ContextsDeserializerAdapter.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/ContextsSerializerAdapter.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/DateDeserializerAdapter.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/DateSerializerAdapter.java (86%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/OrientationDeserializerAdapter.java (88%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/OrientationSerializerAdapter.java (87%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/SentryIdDeserializerAdapter.java (86%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/SentryIdSerializerAdapter.java (85%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/SentryLevelDeserializerAdapter.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/SentryLevelSerializerAdapter.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/TimeZoneDeserializerAdapter.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/adapters/TimeZoneSerializerAdapter.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/cache/CacheStrategy.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/cache/EnvelopeCache.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/cache/IEnvelopeCache.java (81%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/exception/ExceptionMechanismException.java (83%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/ApplyScopeData.java (86%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/Cached.java (76%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/DiskFlushNotification.java (68%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/Flushable.java (79%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/Retryable.java (74%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/SessionEnd.java (74%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/SessionEndHint.java (66%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/SessionStart.java (75%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/SessionStartHint.java (68%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/hints/SubmissionResult.java (76%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/App.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Browser.java (91%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Contexts.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/DebugImage.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/DebugMeta.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Device.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Gpu.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Mechanism.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Message.java (92%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/OperatingSystem.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/Request.java (95%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SdkInfo.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SdkVersion.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryException.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryId.java (98%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryPackage.java (88%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryRuntime.java (92%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryStackFrame.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryStackTrace.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/SentryThread.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/protocol/User.java (96%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/AsyncConnection.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/Connection.java (81%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/CurrentDateProvider.java (92%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/HttpTransport.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/IConnectionConfigurator.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/ICurrentDateProvider.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/ITransport.java (79%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/ITransportGate.java (94%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/NoOpEnvelopeCache.java (84%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/NoOpTransport.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/NoOpTransportGate.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/QueuedThreadPoolExecutor.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/StdoutTransport.java (89%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/transport/TransportResult.java (93%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/util/ApplyScopeUtils.java (85%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/util/CollectionUtils.java (97%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/util/LogUtils.java (87%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/util/Objects.java (90%) rename {sentry-core/src/main/java/io/sentry/core => sentry/src/main/java/io/sentry}/util/StringUtils.java (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/BreadcrumbTest.kt (99%) create mode 100644 sentry/src/test/java/io/sentry/CachedEvent.kt rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/CustomEventProcessor.kt (84%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/DateUtilsTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/DiagnosticLoggerTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/DirectoryProcessorTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/DsnTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/DuplicateEventDetectionEventProcessorTest.kt (94%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/EnvelopeSenderTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/FileFromResources.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/GsonSerializerTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/HttpTransportFactoryTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/HubTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/MainEventProcessorTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/NoOpHubTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/NoOpSentryClientTest.kt (94%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/NoOpSerializerTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/OptionsContainerTest.kt (92%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/OutboxSenderTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SampleDsn.kt (93%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/ScopeTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SendCachedEnvelopeFireAndForgetIntegrationTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryClientTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryEnvelopeItemTest.kt (92%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryEnvelopeTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryEventTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryExceptionFactoryTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryExecutorServiceTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryItemTypeTest.kt (93%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryOptionsTest.kt (98%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryStackTraceFactoryTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryThreadFactoryTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SentryValuesTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/SessionTest.kt (98%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/ShutdownHookIntegrationTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/StringExtensions.kt (87%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/UncaughtExceptionHandlerIntegrationTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/cache/CacheStrategyTest.kt (96%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/cache/EnvelopeCacheTest.kt (92%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/AppTest.kt (98%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/BrowserTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/ContextsTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/DeviceTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/GpuTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/OperatingSystemTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/SentryRuntimeTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/protocol/UserTest.kt (98%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/transport/AsyncConnectionTest.kt (95%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/transport/HttpTransportTest.kt (97%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/transport/QueuedThreadPoolExecutorTest.kt (99%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/transport/StdoutTransportTest.kt (85%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/util/ApplyScopeUtilsTest.kt (88%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/util/Extensions.kt (64%) rename {sentry-core/src/test/java/io/sentry/core => sentry/src/test/java/io/sentry}/util/StringUtilsTest.kt (98%) rename {sentry-core => sentry}/src/test/resources/envelope-event-attachment.txt (100%) rename {sentry-core => sentry}/src/test/resources/envelope-session-start.txt (100%) rename {sentry-core => sentry}/src/test/resources/envelope_session.txt (100%) rename {sentry-core => sentry}/src/test/resources/envelope_session_sdkversion.txt (100%) rename {sentry-core => sentry}/src/test/resources/event.json (100%) rename {sentry-core => sentry}/src/test/resources/event_breadcrumb_data.json (100%) rename {sentry-core => sentry}/src/test/resources/event_with_contexts.json (100%) rename {sentry-core => sentry}/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker (100%) rename {sentry-core => sentry}/src/test/resources/session.json (100%) diff --git a/sentry-android-core/build.gradle.kts b/sentry-android-core/build.gradle.kts index 6eb3a5d93..fb25b4332 100644 --- a/sentry-android-core/build.gradle.kts +++ b/sentry-android-core/build.gradle.kts @@ -72,7 +72,7 @@ android { } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) // lifecycle processor, session tracking implementation(Config.Libs.lifecycleProcess) diff --git a/sentry-android-core/proguard-rules.pro b/sentry-android-core/proguard-rules.pro index f96074f8e..c196022e4 100644 --- a/sentry-android-core/proguard-rules.pro +++ b/sentry-android-core/proguard-rules.pro @@ -11,7 +11,7 @@ -keep class com.google.gson.** { *; } # Application classes that will be serialized/deserialized over Gson --keep class io.sentry.core.** { *; } +-keep class io.sentry.** { *; } -keepclassmembers enum * { *; } -keep class io.sentry.android.core.** { *; } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ANRWatchDog.java b/sentry-android-core/src/main/java/io/sentry/android/core/ANRWatchDog.java index 6e10b00bd..b16087a05 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ANRWatchDog.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ANRWatchDog.java @@ -7,8 +7,8 @@ import android.app.ActivityManager; import android.content.Context; import android.os.Debug; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java index d3e438589..bb1274534 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java @@ -5,12 +5,12 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLogger.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLogger.java index 972fc93e2..f1fd6f079 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLogger.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLogger.java @@ -1,8 +1,8 @@ package io.sentry.android.core; import android.util.Log; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; final class AndroidLogger implements ILogger { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index d58393b40..2069fa120 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -6,13 +6,13 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; -import io.sentry.core.ILogger; -import io.sentry.core.SendCachedEnvelopeFireAndForgetIntegration; -import io.sentry.core.SendFireAndForgetEnvelopeSender; -import io.sentry.core.SendFireAndForgetOutboxSender; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.ILogger; +import io.sentry.SendCachedEnvelopeFireAndForgetIntegration; +import io.sentry.SendFireAndForgetEnvelopeSender; +import io.sentry.SendFireAndForgetOutboxSender; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.io.File; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -124,7 +124,7 @@ private static void installDefaultIntegrations( final Class sentryNdkClass = loadNdkIfAvailable(options, buildInfoProvider, loadClass); options.addIntegration(new NdkIntegration(sentryNdkClass)); - // this integration uses android.os.FileObserver, we can't move to sentry-core + // this integration uses android.os.FileObserver, we can't move to sentry // before creating a pure java impl. options.addIntegration(EnvelopeFileObserverIntegration.getOutboxFileObserver()); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransportGate.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransportGate.java index f0469c978..4b9f800c9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransportGate.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransportGate.java @@ -1,9 +1,9 @@ package io.sentry.android.core; import android.content.Context; +import io.sentry.ILogger; import io.sentry.android.core.util.ConnectivityChecker; -import io.sentry.core.ILogger; -import io.sentry.core.transport.ITransportGate; +import io.sentry.transport.ITransportGate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java index c83744d8c..d82689fd5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java @@ -2,14 +2,14 @@ import android.annotation.SuppressLint; import android.content.Context; -import io.sentry.core.IHub; -import io.sentry.core.ILogger; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.exception.ExceptionMechanismException; -import io.sentry.core.protocol.Mechanism; -import io.sentry.core.util.Objects; +import io.sentry.IHub; +import io.sentry.ILogger; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.protocol.Mechanism; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java index 53c45f88d..ce2b3b58a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java @@ -5,14 +5,14 @@ import android.content.res.Configuration; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; import io.sentry.android.core.util.DeviceOrientations; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.Device; -import io.sentry.core.util.Objects; +import io.sentry.protocol.Device; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import java.util.Locale; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java index 6f097bb71..ae163a8b6 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java @@ -1,12 +1,12 @@ package io.sentry.android.core; import androidx.lifecycle.ProcessLifecycleOwner; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; import io.sentry.android.core.util.MainThreadChecker; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationNotResponding.java b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationNotResponding.java index c346d4293..7299cd29d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationNotResponding.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationNotResponding.java @@ -2,7 +2,7 @@ // Based on the class above. The API unnecessary here was removed. package io.sentry.android.core; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.NotNull; /** diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java index cdd3dcdd6..ff4cd9d60 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java @@ -3,8 +3,8 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 304afa861..e1564e859 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -18,24 +18,24 @@ import android.os.SystemClock; import android.provider.Settings; import android.util.DisplayMetrics; +import io.sentry.DateUtils; +import io.sentry.EventProcessor; +import io.sentry.ILogger; +import io.sentry.SentryEvent; +import io.sentry.SentryLevel; import io.sentry.android.core.util.ConnectivityChecker; import io.sentry.android.core.util.DeviceOrientations; import io.sentry.android.core.util.MainThreadChecker; import io.sentry.android.core.util.RootChecker; -import io.sentry.core.DateUtils; -import io.sentry.core.EventProcessor; -import io.sentry.core.ILogger; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.App; -import io.sentry.core.protocol.DebugImage; -import io.sentry.core.protocol.DebugMeta; -import io.sentry.core.protocol.Device; -import io.sentry.core.protocol.OperatingSystem; -import io.sentry.core.protocol.SentryThread; -import io.sentry.core.protocol.User; -import io.sentry.core.util.ApplyScopeUtils; -import io.sentry.core.util.Objects; +import io.sentry.protocol.App; +import io.sentry.protocol.DebugImage; +import io.sentry.protocol.DebugMeta; +import io.sentry.protocol.Device; +import io.sentry.protocol.OperatingSystem; +import io.sentry.protocol.SentryThread; +import io.sentry.protocol.User; +import io.sentry.util.ApplyScopeUtils; +import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserver.java b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserver.java index 4061fdae9..b7b2d2abe 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserver.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserver.java @@ -1,17 +1,17 @@ package io.sentry.android.core; -import static io.sentry.core.SentryLevel.ERROR; +import static io.sentry.SentryLevel.ERROR; import android.os.FileObserver; -import io.sentry.core.IEnvelopeSender; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.hints.ApplyScopeData; -import io.sentry.core.hints.Cached; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SubmissionResult; -import io.sentry.core.util.Objects; +import io.sentry.IEnvelopeSender; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.hints.ApplyScopeData; +import io.sentry.hints.Cached; +import io.sentry.hints.Flushable; +import io.sentry.hints.Retryable; +import io.sentry.hints.SubmissionResult; +import io.sentry.util.Objects; import java.io.File; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java index 340fd9e92..2e6947da5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java @@ -1,12 +1,12 @@ package io.sentry.android.core; -import io.sentry.core.IHub; -import io.sentry.core.ILogger; -import io.sentry.core.Integration; -import io.sentry.core.OutboxSender; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.IHub; +import io.sentry.ILogger; +import io.sentry.Integration; +import io.sentry.OutboxSender; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.io.Closeable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java index a83ea1a44..b0a435f06 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java @@ -2,11 +2,11 @@ import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.SentryLevel; -import io.sentry.core.transport.CurrentDateProvider; -import io.sentry.core.transport.ICurrentDateProvider; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.SentryLevel; +import io.sentry.transport.CurrentDateProvider; +import io.sentry.transport.ICurrentDateProvider; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java index 6077b528d..e774219ac 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java @@ -4,9 +4,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.util.Objects; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.util.Objects; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java index 5d0022e09..497192370 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java @@ -1,10 +1,10 @@ package io.sentry.android.core; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.lang.reflect.Method; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java index bb8654e34..91a59f10e 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java @@ -8,13 +8,13 @@ import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import androidx.annotation.Nullable; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; import io.sentry.android.core.util.Permissions; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java index bebd25e60..0bf9fcb99 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java @@ -1,10 +1,10 @@ package io.sentry.android.core; import android.content.Context; -import io.sentry.core.ILogger; -import io.sentry.core.OptionsContainer; -import io.sentry.core.Sentry; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.OptionsContainer; +import io.sentry.Sentry; +import io.sentry.SentryLevel; import java.lang.reflect.InvocationTargetException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java index 0c10ba972..9e98a78a7 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java @@ -1,7 +1,7 @@ package io.sentry.android.core; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.SdkVersion; +import io.sentry.SentryOptions; +import io.sentry.protocol.SdkVersion; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryInitProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryInitProvider.java index 0a5317267..d4e5b30e5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryInitProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryInitProvider.java @@ -6,8 +6,8 @@ import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; -import io.sentry.core.Sentry; -import io.sentry.core.SentryLevel; +import io.sentry.Sentry; +import io.sentry.SentryLevel; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java index 017cfc382..921ee5aa8 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java @@ -37,14 +37,14 @@ import android.content.IntentFilter; import android.os.Bundle; import androidx.annotation.Nullable; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.ILogger; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; -import io.sentry.core.util.StringUtils; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.ILogger; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; +import io.sentry.util.StringUtils; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java index c93991130..a91b0d69d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java @@ -8,12 +8,12 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import androidx.annotation.Nullable; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/util/ConnectivityChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/util/ConnectivityChecker.java index 02b23437c..a9f8e0fe8 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/util/ConnectivityChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/util/ConnectivityChecker.java @@ -7,9 +7,9 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.os.Build; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import io.sentry.android.core.IBuildInfoProvider; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/util/DeviceOrientations.java b/sentry-android-core/src/main/java/io/sentry/android/core/util/DeviceOrientations.java index 597c3d68a..638298b66 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/util/DeviceOrientations.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/util/DeviceOrientations.java @@ -1,7 +1,7 @@ package io.sentry.android.core.util; import android.content.res.Configuration; -import io.sentry.core.protocol.Device; +import io.sentry.protocol.Device; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/util/MainThreadChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/util/MainThreadChecker.java index ea0d9f17e..c6233af9c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/util/MainThreadChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/util/MainThreadChecker.java @@ -1,7 +1,7 @@ package io.sentry.android.core.util; import android.os.Looper; -import io.sentry.core.protocol.SentryThread; +import io.sentry.protocol.SentryThread; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/util/Permissions.java b/sentry-android-core/src/main/java/io/sentry/android/core/util/Permissions.java index 3fd2f0e5c..1df9bf390 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/util/Permissions.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/util/Permissions.java @@ -3,7 +3,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Process; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/util/RootChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/util/RootChecker.java index 321664203..7c2e4bfab 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/util/RootChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/util/RootChecker.java @@ -2,10 +2,10 @@ import android.content.Context; import android.content.pm.PackageManager; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import io.sentry.android.core.IBuildInfoProvider; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.io.BufferedReader; import java.io.File; import java.io.IOException; diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt index 2c2306b04..0d77c3e23 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityBreadcrumbsIntegrationTest.kt @@ -6,9 +6,9 @@ import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index 658935874..ef1fa0c5f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -11,11 +11,11 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.ILogger -import io.sentry.core.MainEventProcessor -import io.sentry.core.SendCachedEnvelopeFireAndForgetIntegration -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions +import io.sentry.ILogger +import io.sentry.MainEventProcessor +import io.sentry.SendCachedEnvelopeFireAndForgetIntegration +import io.sentry.SentryLevel +import io.sentry.SentryOptions import java.io.File import java.lang.RuntimeException import kotlin.test.BeforeTest diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AnrIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AnrIntegrationTest.kt index c292c6423..14d55987a 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AnrIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AnrIntegrationTest.kt @@ -3,7 +3,7 @@ package io.sentry.android.core import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.IHub +import io.sentry.IHub import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertNotNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegrationTest.kt index 8bbe23106..0bda79e75 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegrationTest.kt @@ -10,9 +10,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel import java.lang.NullPointerException import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AppLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AppLifecycleIntegrationTest.kt index 084f6268a..614962269 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AppLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AppLifecycleIntegrationTest.kt @@ -4,7 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.IHub +import io.sentry.IHub import java.util.concurrent.CountDownLatch import kotlin.test.Test import kotlin.test.assertNotNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/CachedEvent.kt b/sentry-android-core/src/test/java/io/sentry/android/core/CachedEvent.kt index caee1a774..486404a14 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/CachedEvent.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/CachedEvent.kt @@ -1,5 +1,5 @@ package io.sentry.android.core -import io.sentry.core.hints.Cached +import io.sentry.hints.Cached class CachedEvent : Cached diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt index d227d9524..3a9961a46 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt @@ -9,18 +9,18 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify +import io.sentry.DiagnosticLogger +import io.sentry.ILogger +import io.sentry.SentryEvent +import io.sentry.SentryLevel +import io.sentry.SentryOptions import io.sentry.android.core.DefaultAndroidEventProcessor.ANDROID_ID import io.sentry.android.core.DefaultAndroidEventProcessor.EMULATOR import io.sentry.android.core.DefaultAndroidEventProcessor.KERNEL_VERSION import io.sentry.android.core.DefaultAndroidEventProcessor.PROGUARD_UUID import io.sentry.android.core.DefaultAndroidEventProcessor.ROOTED -import io.sentry.core.DiagnosticLogger -import io.sentry.core.ILogger -import io.sentry.core.SentryEvent -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.protocol.SdkVersion -import io.sentry.core.protocol.SentryThread +import io.sentry.protocol.SdkVersion +import io.sentry.protocol.SentryThread import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt index 55d22aff7..2899c2c83 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt @@ -3,9 +3,9 @@ package io.sentry.android.core import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Hub -// import io.sentry.core.HubAdapter -import io.sentry.core.SentryOptions +import io.sentry.Hub +// import io.sentry.HubAdapter +import io.sentry.SentryOptions import java.io.File import java.nio.file.Files import kotlin.test.AfterTest diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverTest.kt index b28af8ef9..d0ecd315b 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverTest.kt @@ -10,10 +10,10 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyZeroInteractions -import io.sentry.core.IEnvelopeSender -import io.sentry.core.ILogger -import io.sentry.core.SentryOptions -import io.sentry.core.hints.ApplyScopeData +import io.sentry.IEnvelopeSender +import io.sentry.ILogger +import io.sentry.SentryOptions +import io.sentry.hints.ApplyScopeData import java.io.File import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/LifecycleWatcherTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/LifecycleWatcherTest.kt index 3b1091af8..58e7c77d0 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/LifecycleWatcherTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/LifecycleWatcherTest.kt @@ -8,10 +8,10 @@ import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel -import io.sentry.core.transport.ICurrentDateProvider +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel +import io.sentry.transport.ICurrentDateProvider import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt index 08b8ca85d..392d3a1ec 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt @@ -7,8 +7,8 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.ILogger -import io.sentry.core.SentryLevel +import io.sentry.ILogger +import io.sentry.SentryLevel import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/NdkIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/NdkIntegrationTest.kt index 3d9ed591f..717bfbc9c 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/NdkIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/NdkIntegrationTest.kt @@ -5,9 +5,9 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.ILogger -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions +import io.sentry.ILogger +import io.sentry.SentryLevel +import io.sentry.SentryOptions import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegrationTest.kt index 7bc7b61ee..0a7dcd8f5 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegrationTest.kt @@ -10,9 +10,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt index c43297577..323b911a7 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt @@ -31,7 +31,7 @@ class SentryAndroidOptionsTest { }) assertTrue(sdkVersion.packages!!.any { - it.name == "maven:sentry-core" && + it.name == "maven:sentry" && it.version == BuildConfig.VERSION_NAME }) } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt index f0ec60762..ecf41c538 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt @@ -7,9 +7,9 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.ILogger -import io.sentry.core.Sentry -import io.sentry.core.SentryLevel +import io.sentry.ILogger +import io.sentry.Sentry +import io.sentry.SentryLevel import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryInitProviderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryInitProviderTest.kt index f90b689ae..345d550d4 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryInitProviderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryInitProviderTest.kt @@ -4,9 +4,9 @@ import android.content.pm.ProviderInfo import android.os.Bundle import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.ILogger -import io.sentry.core.InvalidDsnException -import io.sentry.core.Sentry +import io.sentry.ILogger +import io.sentry.InvalidDsnException +import io.sentry.Sentry import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertFailsWith diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryNdk.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryNdk.kt index dca1cf09e..b112c8d27 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryNdk.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryNdk.kt @@ -1,6 +1,6 @@ package io.sentry.android.core -import io.sentry.core.SentryOptions +import io.sentry.SentryOptions class SentryNdk { companion object { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt index 894a941ae..81f6a7e2e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt @@ -7,9 +7,9 @@ import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/TempSensorBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/TempSensorBreadcrumbsIntegrationTest.kt index 7fdddce9b..1d31a4077 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/TempSensorBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/TempSensorBreadcrumbsIntegrationTest.kt @@ -12,9 +12,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/util/DeviceOrientationsTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/util/DeviceOrientationsTest.kt index b1a8130ba..f0148f67e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/util/DeviceOrientationsTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/util/DeviceOrientationsTest.kt @@ -5,7 +5,7 @@ import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.content.res.Configuration.ORIENTATION_SQUARE import android.content.res.Configuration.ORIENTATION_UNDEFINED import io.sentry.android.core.util.DeviceOrientations.getOrientation -import io.sentry.core.protocol.Device +import io.sentry.protocol.Device import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/util/MainThreadCheckerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/util/MainThreadCheckerTest.kt index 95ba09e43..5619200c8 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/util/MainThreadCheckerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/util/MainThreadCheckerTest.kt @@ -1,7 +1,7 @@ package io.sentry.android.core.util import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.sentry.core.protocol.SentryThread +import io.sentry.protocol.SentryThread import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/util/RootCheckerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/util/RootCheckerTest.kt index 6474bf3b1..a17b19694 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/util/RootCheckerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/util/RootCheckerTest.kt @@ -8,8 +8,8 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever +import io.sentry.ILogger import io.sentry.android.core.IBuildInfoProvider -import io.sentry.core.ILogger import java.io.ByteArrayInputStream import java.io.File import java.io.IOException diff --git a/sentry-android-ndk/build.gradle.kts b/sentry-android-ndk/build.gradle.kts index 59fded3c3..f59a4cb7b 100644 --- a/sentry-android-ndk/build.gradle.kts +++ b/sentry-android-ndk/build.gradle.kts @@ -100,7 +100,7 @@ android { } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) api(project(":sentry-android-core")) compileOnly(Config.CompileOnly.jetbrainsAnnotations) diff --git a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java index aaecb89f8..faf1e585a 100644 --- a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java +++ b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java @@ -1,6 +1,6 @@ package io.sentry.android.ndk; -import io.sentry.core.SentryOptions; +import io.sentry.SentryOptions; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdkUtil.java b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdkUtil.java index 1b492aa04..e2686fe88 100644 --- a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdkUtil.java +++ b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdkUtil.java @@ -1,6 +1,6 @@ package io.sentry.android.ndk; -import io.sentry.core.protocol.SdkVersion; +import io.sentry.protocol.SdkVersion; import org.jetbrains.annotations.Nullable; /** diff --git a/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt b/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt index f861cc235..0082565cd 100644 --- a/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt +++ b/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt @@ -1,6 +1,6 @@ package io.sentry.android.ndk -import io.sentry.core.SentryOptions +import io.sentry.SentryOptions import kotlin.test.Test import kotlin.test.assertNull import kotlin.test.assertTrue diff --git a/sentry-android-timber/build.gradle.kts b/sentry-android-timber/build.gradle.kts index 3a1b82c9c..1bdc04f15 100644 --- a/sentry-android-timber/build.gradle.kts +++ b/sentry-android-timber/build.gradle.kts @@ -67,7 +67,7 @@ android { } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) api(Config.Libs.timber) diff --git a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt index 0ddb31e85..58571fcf4 100644 --- a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt +++ b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt @@ -1,11 +1,11 @@ package io.sentry.android.timber -import io.sentry.core.IHub -import io.sentry.core.ILogger -import io.sentry.core.Integration -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.protocol.SdkVersion +import io.sentry.IHub +import io.sentry.ILogger +import io.sentry.Integration +import io.sentry.SentryLevel +import io.sentry.SentryOptions +import io.sentry.protocol.SdkVersion import java.io.Closeable import timber.log.Timber diff --git a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberTree.kt b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberTree.kt index 0a028e5ff..04e77610c 100644 --- a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberTree.kt +++ b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberTree.kt @@ -1,11 +1,11 @@ package io.sentry.android.timber import android.util.Log -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryEvent -import io.sentry.core.SentryLevel -import io.sentry.core.protocol.Message +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryEvent +import io.sentry.SentryLevel +import io.sentry.protocol.Message import timber.log.Timber /** diff --git a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt index 3eb307216..cf6efee20 100644 --- a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt +++ b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt @@ -3,10 +3,10 @@ package io.sentry.android.timber import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.IHub -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.protocol.SdkVersion +import io.sentry.IHub +import io.sentry.SentryLevel +import io.sentry.SentryOptions +import io.sentry.protocol.SdkVersion import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberTreeTest.kt b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberTreeTest.kt index c0954b577..ee6dbe92a 100644 --- a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberTreeTest.kt +++ b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberTreeTest.kt @@ -5,10 +5,10 @@ import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Breadcrumb -import io.sentry.core.IHub -import io.sentry.core.SentryLevel -import io.sentry.core.getExc +import io.sentry.Breadcrumb +import io.sentry.IHub +import io.sentry.SentryLevel +import io.sentry.getExc import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-android-timber/src/test/java/io/sentry/core/SentryEventKtx.kt b/sentry-android-timber/src/test/java/io/sentry/core/SentryEventKtx.kt index 329092cfb..95d342f3b 100644 --- a/sentry-android-timber/src/test/java/io/sentry/core/SentryEventKtx.kt +++ b/sentry-android-timber/src/test/java/io/sentry/core/SentryEventKtx.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry /** * package-private hack. diff --git a/sentry-core/src/test/java/io/sentry/core/CachedEvent.kt b/sentry-core/src/test/java/io/sentry/core/CachedEvent.kt deleted file mode 100644 index 6531f40f4..000000000 --- a/sentry-core/src/test/java/io/sentry/core/CachedEvent.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.sentry.core - -import io.sentry.core.hints.Cached - -class CachedEvent : Cached diff --git a/sentry-log4j2/build.gradle.kts b/sentry-log4j2/build.gradle.kts index d5c60ab80..00090d222 100644 --- a/sentry-log4j2/build.gradle.kts +++ b/sentry-log4j2/build.gradle.kts @@ -20,7 +20,7 @@ tasks.withType().configureEach } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) implementation(Config.Libs.log4j2Api) implementation(Config.Libs.log4j2Core) diff --git a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java index 39349e757..44da41561 100644 --- a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java +++ b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java @@ -1,17 +1,17 @@ package io.sentry.log4j2; -import io.sentry.core.Breadcrumb; -import io.sentry.core.DateUtils; -import io.sentry.core.HubAdapter; -import io.sentry.core.IHub; -import io.sentry.core.Sentry; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.Message; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.transport.ITransport; -import io.sentry.core.util.CollectionUtils; +import io.sentry.Breadcrumb; +import io.sentry.DateUtils; +import io.sentry.HubAdapter; +import io.sentry.IHub; +import io.sentry.Sentry; +import io.sentry.SentryEvent; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.protocol.Message; +import io.sentry.protocol.SdkVersion; +import io.sentry.transport.ITransport; +import io.sentry.util.CollectionUtils; import java.util.Arrays; import java.util.Collections; import java.util.Date; diff --git a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt index 54ffc7918..50ab78fa2 100644 --- a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt +++ b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt @@ -2,10 +2,10 @@ package io.sentry.log4j2 import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.HubAdapter -import io.sentry.core.SentryLevel -import io.sentry.core.transport.ITransport +import io.sentry.HubAdapter +import io.sentry.SentryLevel import io.sentry.test.checkEvent +import io.sentry.transport.ITransport import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId diff --git a/sentry-logback/build.gradle.kts b/sentry-logback/build.gradle.kts index 942a171ad..0209b1ca6 100644 --- a/sentry-logback/build.gradle.kts +++ b/sentry-logback/build.gradle.kts @@ -20,7 +20,7 @@ tasks.withType().configureEach } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) implementation(Config.Libs.logbackClassic) compileOnly(Config.CompileOnly.nopen) 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 35e69b829..b9d4a5134 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -4,16 +4,16 @@ 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; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.Message; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.transport.ITransport; -import io.sentry.core.util.CollectionUtils; +import io.sentry.Breadcrumb; +import io.sentry.DateUtils; +import io.sentry.Sentry; +import io.sentry.SentryEvent; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.protocol.Message; +import io.sentry.protocol.SdkVersion; +import io.sentry.transport.ITransport; +import io.sentry.util.CollectionUtils; import java.util.Arrays; import java.util.Collections; import java.util.Date; 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 297dce4f7..7def3e5bd 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -6,11 +6,11 @@ import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.transport.ITransport -import io.sentry.core.transport.TransportResult +import io.sentry.SentryLevel +import io.sentry.SentryOptions import io.sentry.test.checkEvent +import io.sentry.transport.ITransport +import io.sentry.transport.TransportResult import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/sample/MainActivity.java b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/sample/MainActivity.java index 9a9b367a4..07f21b628 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/sample/MainActivity.java +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/sample/MainActivity.java @@ -2,8 +2,8 @@ import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; -import io.sentry.core.Sentry; -import io.sentry.core.protocol.User; +import io.sentry.Sentry; +import io.sentry.protocol.User; import io.sentry.sample.databinding.ActivityMainBinding; import java.util.Collections; diff --git a/sentry-samples/sentry-samples-console/build.gradle.kts b/sentry-samples/sentry-samples-console/build.gradle.kts index 496bd3052..44f48604a 100644 --- a/sentry-samples/sentry-samples-console/build.gradle.kts +++ b/sentry-samples/sentry-samples-console/build.gradle.kts @@ -9,5 +9,5 @@ configure { } dependencies { - implementation(project(":sentry-core")) + implementation(project(":sentry")) } diff --git a/sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java index 2ecd50a29..ae9b2688a 100644 --- a/sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java @@ -1,12 +1,12 @@ package io.sentry.samples.console; -import io.sentry.core.Breadcrumb; -import io.sentry.core.EventProcessor; -import io.sentry.core.Sentry; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.Message; -import io.sentry.core.protocol.User; +import io.sentry.Breadcrumb; +import io.sentry.EventProcessor; +import io.sentry.Sentry; +import io.sentry.SentryEvent; +import io.sentry.SentryLevel; +import io.sentry.protocol.Message; +import io.sentry.protocol.User; import java.util.Collections; public class Main { diff --git a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java index 40d17a1c6..1eccfb1a5 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java +++ b/sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/CustomEventProcessor.java @@ -1,8 +1,8 @@ package io.sentry.samples.spring.boot; -import io.sentry.core.EventProcessor; -import io.sentry.core.SentryEvent; -import io.sentry.core.protocol.SentryRuntime; +import io.sentry.EventProcessor; +import io.sentry.SentryEvent; +import io.sentry.protocol.SentryRuntime; import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Component; diff --git a/sentry-spring-boot-starter/build.gradle.kts b/sentry-spring-boot-starter/build.gradle.kts index a2adf698b..5f606c037 100644 --- a/sentry-spring-boot-starter/build.gradle.kts +++ b/sentry-spring-boot-starter/build.gradle.kts @@ -33,7 +33,7 @@ tasks.withType().configureEach { } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) api(project(":sentry-spring")) implementation(Config.Libs.springBootStarter) implementation(Config.Libs.springWeb) diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index f47cf467c..3f4a1e9bb 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -1,18 +1,18 @@ package io.sentry.spring.boot; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.EventProcessor; -import io.sentry.core.HubAdapter; -import io.sentry.core.IHub; -import io.sentry.core.Integration; -import io.sentry.core.Sentry; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.transport.ITransport; -import io.sentry.core.transport.ITransportGate; +import io.sentry.EventProcessor; +import io.sentry.HubAdapter; +import io.sentry.IHub; +import io.sentry.Integration; +import io.sentry.Sentry; +import io.sentry.SentryOptions; +import io.sentry.protocol.SdkVersion; import io.sentry.spring.SentryUserProvider; import io.sentry.spring.SentryUserProviderEventProcessor; import io.sentry.spring.SentryWebConfiguration; +import io.sentry.transport.ITransport; +import io.sentry.transport.ITransportGate; import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.ObjectProvider; diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java index 18cb6f4ee..67bb103a6 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryProperties.java @@ -1,7 +1,7 @@ package io.sentry.spring.boot; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.SentryOptions; +import io.sentry.SentryOptions; import org.springframework.boot.context.properties.ConfigurationProperties; /** Configuration for Sentry integration. */ diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index e78de75df..88dd99fad 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -3,17 +3,17 @@ package io.sentry.spring.boot import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.Breadcrumb -import io.sentry.core.EventProcessor -import io.sentry.core.IHub -import io.sentry.core.Integration -import io.sentry.core.Sentry -import io.sentry.core.SentryEvent -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.transport.ITransport -import io.sentry.core.transport.ITransportGate +import io.sentry.Breadcrumb +import io.sentry.EventProcessor +import io.sentry.IHub +import io.sentry.Integration +import io.sentry.Sentry +import io.sentry.SentryEvent +import io.sentry.SentryLevel +import io.sentry.SentryOptions import io.sentry.test.checkEvent +import io.sentry.transport.ITransport +import io.sentry.transport.ITransportGate import kotlin.test.Test import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt index 36aef8f0d..808c7ce1f 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpringIntegrationTest.kt @@ -1,9 +1,9 @@ package io.sentry.spring.boot import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Sentry -import io.sentry.core.transport.ITransport +import io.sentry.Sentry import io.sentry.test.checkEvent +import io.sentry.transport.ITransport import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await diff --git a/sentry-spring/build.gradle.kts b/sentry-spring/build.gradle.kts index 31d69e95a..fc31b4fd0 100644 --- a/sentry-spring/build.gradle.kts +++ b/sentry-spring/build.gradle.kts @@ -33,7 +33,7 @@ tasks.withType().configureEach { } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) implementation(Config.Libs.springWeb) implementation(Config.Libs.servletApi) diff --git a/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java b/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java index 2ab00f6ee..17b24d66c 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java +++ b/sentry-spring/src/main/java/io/sentry/spring/EnableSentry.java @@ -10,8 +10,8 @@ * Enables Sentry error handling capabilities. * *

    - *
  • creates bean of type {@link io.sentry.core.SentryOptions} - *
  • registers {@link io.sentry.core.IHub} for sending Sentry events + *
  • creates bean of type {@link io.sentry.SentryOptions} + *
  • registers {@link io.sentry.IHub} for sending Sentry events *
  • registers {@link SentryRequestFilter} for attaching request information to Sentry events *
  • registers {@link SentryExceptionResolver} to send Sentry event for any uncaught exception * in Spring MVC flow. diff --git a/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java b/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java index 55776b82a..c24d2c2ff 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java +++ b/sentry-spring/src/main/java/io/sentry/spring/HttpServletRequestSentryUserProvider.java @@ -1,8 +1,8 @@ package io.sentry.spring; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.User; -import io.sentry.core.util.Objects; +import io.sentry.SentryOptions; +import io.sentry.protocol.User; +import io.sentry.util.Objects; import javax.servlet.http.HttpServletRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java b/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java index eba7bfbf4..30c76a680 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java @@ -1,12 +1,12 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.IHub; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryLevel; -import io.sentry.core.exception.ExceptionMechanismException; -import io.sentry.core.protocol.Mechanism; -import io.sentry.core.util.Objects; +import io.sentry.IHub; +import io.sentry.SentryEvent; +import io.sentry.SentryLevel; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.protocol.Mechanism; +import io.sentry.util.Objects; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java index 3b85dae5c..0fc33653d 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java @@ -1,9 +1,9 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.HubAdapter; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.SdkVersion; +import io.sentry.HubAdapter; +import io.sentry.SentryOptions; +import io.sentry.protocol.SdkVersion; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java index 3bae29feb..96c57b7f6 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryInitBeanPostProcessor.java @@ -1,8 +1,8 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.Sentry; -import io.sentry.core.SentryOptions; +import io.sentry.Sentry; +import io.sentry.SentryOptions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.beans.BeansException; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java index d9f22adc2..f72d3b3d5 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestFilter.java @@ -1,10 +1,10 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.Breadcrumb; -import io.sentry.core.IHub; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; +import io.sentry.Breadcrumb; +import io.sentry.IHub; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -14,7 +14,7 @@ import org.springframework.core.Ordered; import org.springframework.web.filter.OncePerRequestFilter; -/** Pushes new {@link io.sentry.core.Scope} on each incoming HTTP request. */ +/** Pushes new {@link io.sentry.Scope} on each incoming HTTP request. */ @Open public class SentryRequestFilter extends OncePerRequestFilter implements Ordered { private final @NotNull IHub hub; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java index ffcb5e2d0..d3f54ae64 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java @@ -1,11 +1,11 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.EventProcessor; -import io.sentry.core.SentryEvent; -import io.sentry.core.SentryOptions; -import io.sentry.core.protocol.Request; -import io.sentry.core.util.Objects; +import io.sentry.EventProcessor; +import io.sentry.SentryEvent; +import io.sentry.SentryOptions; +import io.sentry.protocol.Request; +import io.sentry.util.Objects; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java index 724e5676a..6ee1f899a 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProvider.java @@ -1,10 +1,10 @@ package io.sentry.spring; -import io.sentry.core.protocol.User; +import io.sentry.protocol.User; import org.jetbrains.annotations.Nullable; /** - * Provides user information that's set on {@link io.sentry.core.SentryEvent} using {@link + * Provides user information that's set on {@link io.sentry.SentryEvent} using {@link * SentryUserProviderEventProcessor}. * *

    Out of the box Spring integration configures single {@link SentryUserProvider} - {@link diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java index 687b7b768..2e5370926 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryUserProviderEventProcessor.java @@ -1,9 +1,9 @@ package io.sentry.spring; -import io.sentry.core.EventProcessor; -import io.sentry.core.SentryEvent; -import io.sentry.core.protocol.User; -import io.sentry.core.util.Objects; +import io.sentry.EventProcessor; +import io.sentry.SentryEvent; +import io.sentry.protocol.User; +import io.sentry.util.Objects; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java index 902f6b449..86aaf6657 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryWebConfiguration.java @@ -1,8 +1,8 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.IHub; -import io.sentry.core.SentryOptions; +import io.sentry.IHub; +import io.sentry.SentryOptions; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt index 1255f96a9..df7e8a5f0 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt @@ -1,7 +1,7 @@ package io.sentry.spring -import io.sentry.core.IHub -import io.sentry.core.SentryOptions +import io.sentry.IHub +import io.sentry.SentryOptions import kotlin.test.Test import org.assertj.core.api.Assertions.assertThat import org.springframework.boot.context.annotation.UserConfigurations diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt index aa9c1529f..20b2617cd 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/HttpServletRequestSentryUserProviderTest.kt @@ -2,7 +2,7 @@ package io.sentry.spring import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.SentryOptions +import io.sentry.SentryOptions import java.security.Principal import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt index ca33e331d..ed4bcbf8f 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt @@ -1,7 +1,7 @@ package io.sentry.spring -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions +import io.sentry.SentryEvent +import io.sentry.SentryOptions import java.net.URI import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt index 6ac380819..40d726c81 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentrySpringIntegrationTest.kt @@ -3,9 +3,9 @@ package io.sentry.spring import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Sentry -import io.sentry.core.transport.ITransport +import io.sentry.Sentry import io.sentry.test.checkEvent +import io.sentry.transport.ITransport import java.lang.RuntimeException import org.assertj.core.api.Assertions.assertThat import org.awaitility.kotlin.await diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt index 8de2d92eb..6cfd87a35 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorIntegrationTest.kt @@ -3,12 +3,12 @@ package io.sentry.spring import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.Sentry -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions -import io.sentry.core.protocol.User -import io.sentry.core.transport.ITransport +import io.sentry.Sentry +import io.sentry.SentryEvent +import io.sentry.SentryOptions +import io.sentry.protocol.User import io.sentry.test.checkEvent +import io.sentry.transport.ITransport import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt index 8f0d4ae84..5694f52ab 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryUserProviderEventProcessorTest.kt @@ -1,7 +1,7 @@ package io.sentry.spring -import io.sentry.core.SentryEvent -import io.sentry.core.protocol.User +import io.sentry.SentryEvent +import io.sentry.protocol.User import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-test-support/build.gradle.kts b/sentry-test-support/build.gradle.kts index fefac4ef7..a2821878e 100644 --- a/sentry-test-support/build.gradle.kts +++ b/sentry-test-support/build.gradle.kts @@ -16,7 +16,7 @@ tasks.withType().configureEach } dependencies { - api(project(":sentry-core")) + api(project(":sentry")) // Envelopes require JSON. Until a parse is done without GSON, we'll depend on it explicitly here implementation(Config.Libs.gson) diff --git a/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt b/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt index a1d02db8a..4b8ca5971 100644 --- a/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt +++ b/sentry-test-support/src/main/kotlin/io/sentry/test/assertions.kt @@ -1,11 +1,11 @@ package io.sentry.test import com.nhaarman.mockitokotlin2.check -import io.sentry.core.GsonSerializer -import io.sentry.core.NoOpLogger -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions +import io.sentry.GsonSerializer +import io.sentry.NoOpLogger +import io.sentry.SentryEnvelope +import io.sentry.SentryEvent +import io.sentry.SentryOptions /** * Verifies is [SentryEnvelope] contains first event matching a predicate. diff --git a/sentry-core/build.gradle.kts b/sentry/build.gradle.kts similarity index 98% rename from sentry-core/build.gradle.kts rename to sentry/build.gradle.kts index 095269f99..3dd509f5b 100644 --- a/sentry-core/build.gradle.kts +++ b/sentry/build.gradle.kts @@ -68,7 +68,7 @@ tasks { buildConfig { useJavaOutput() - packageName("io.sentry.core") + packageName("io.sentry") buildConfigField("String", "SENTRY_JAVA_SDK_NAME", "\"${Config.Sentry.SENTRY_JAVA_SDK_NAME}\"") buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") } diff --git a/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java b/sentry/src/main/java/io/sentry/AsyncConnectionFactory.java similarity index 81% rename from sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java rename to sentry/src/main/java/io/sentry/AsyncConnectionFactory.java index 6d51298e5..663a4f0a0 100644 --- a/sentry-core/src/main/java/io/sentry/core/AsyncConnectionFactory.java +++ b/sentry/src/main/java/io/sentry/AsyncConnectionFactory.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.transport.AsyncConnection; +import io.sentry.cache.IEnvelopeCache; +import io.sentry.transport.AsyncConnection; final class AsyncConnectionFactory { private AsyncConnectionFactory() {} diff --git a/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java b/sentry/src/main/java/io/sentry/Breadcrumb.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/Breadcrumb.java rename to sentry/src/main/java/io/sentry/Breadcrumb.java index d990e4daf..b428dd650 100644 --- a/sentry-core/src/main/java/io/sentry/core/Breadcrumb.java +++ b/sentry/src/main/java/io/sentry/Breadcrumb.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.CollectionUtils; +import io.sentry.util.CollectionUtils; import java.util.Date; import java.util.Locale; import java.util.Map; diff --git a/sentry-core/src/main/java/io/sentry/core/CircularFifoQueue.java b/sentry/src/main/java/io/sentry/CircularFifoQueue.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/CircularFifoQueue.java rename to sentry/src/main/java/io/sentry/CircularFifoQueue.java index 46ae914f3..60a1df35a 100644 --- a/sentry-core/src/main/java/io/sentry/core/CircularFifoQueue.java +++ b/sentry/src/main/java/io/sentry/CircularFifoQueue.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.IOException; import java.io.ObjectInputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/CredentialsSettingConfigurator.java b/sentry/src/main/java/io/sentry/CredentialsSettingConfigurator.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/CredentialsSettingConfigurator.java rename to sentry/src/main/java/io/sentry/CredentialsSettingConfigurator.java index 2d244c057..32b9faf33 100644 --- a/sentry-core/src/main/java/io/sentry/core/CredentialsSettingConfigurator.java +++ b/sentry/src/main/java/io/sentry/CredentialsSettingConfigurator.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.transport.IConnectionConfigurator; +import io.sentry.transport.IConnectionConfigurator; import java.net.HttpURLConnection; /** diff --git a/sentry-core/src/main/java/io/sentry/core/DateUtils.java b/sentry/src/main/java/io/sentry/DateUtils.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/DateUtils.java rename to sentry/src/main/java/io/sentry/DateUtils.java index 2110ea896..7670c8b01 100644 --- a/sentry-core/src/main/java/io/sentry/core/DateUtils.java +++ b/sentry/src/main/java/io/sentry/DateUtils.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.text.DateFormat; import java.text.ParseException; diff --git a/sentry-core/src/main/java/io/sentry/core/DiagnosticLogger.java b/sentry/src/main/java/io/sentry/DiagnosticLogger.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/DiagnosticLogger.java rename to sentry/src/main/java/io/sentry/DiagnosticLogger.java index 327e7bd00..c48f79d95 100644 --- a/sentry-core/src/main/java/io/sentry/core/DiagnosticLogger.java +++ b/sentry/src/main/java/io/sentry/DiagnosticLogger.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java b/sentry/src/main/java/io/sentry/DirectoryProcessor.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java rename to sentry/src/main/java/io/sentry/DirectoryProcessor.java index b5edc27c7..cdd47b3f5 100644 --- a/sentry-core/src/main/java/io/sentry/core/DirectoryProcessor.java +++ b/sentry/src/main/java/io/sentry/DirectoryProcessor.java @@ -1,11 +1,11 @@ -package io.sentry.core; +package io.sentry; -import static io.sentry.core.SentryLevel.ERROR; +import static io.sentry.SentryLevel.ERROR; -import io.sentry.core.hints.Cached; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SubmissionResult; +import io.sentry.hints.Cached; +import io.sentry.hints.Flushable; +import io.sentry.hints.Retryable; +import io.sentry.hints.SubmissionResult; import java.io.File; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/sentry-core/src/main/java/io/sentry/core/Dsn.java b/sentry/src/main/java/io/sentry/Dsn.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/Dsn.java rename to sentry/src/main/java/io/sentry/Dsn.java index d686a83a0..1fc0d15a3 100644 --- a/sentry-core/src/main/java/io/sentry/core/Dsn.java +++ b/sentry/src/main/java/io/sentry/Dsn.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.net.URI; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java b/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java rename to sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java index e62824128..686ccbf45 100644 --- a/sentry-core/src/main/java/io/sentry/core/DuplicateEventDetectionEventProcessor.java +++ b/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.exception.ExceptionMechanismException; -import io.sentry.core.util.Objects; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.util.Objects; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/sentry-core/src/main/java/io/sentry/core/EnvelopeReader.java b/sentry/src/main/java/io/sentry/EnvelopeReader.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/EnvelopeReader.java rename to sentry/src/main/java/io/sentry/EnvelopeReader.java index 5ffec841c..6ec6d6059 100644 --- a/sentry-core/src/main/java/io/sentry/core/EnvelopeReader.java +++ b/sentry/src/main/java/io/sentry/EnvelopeReader.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java b/sentry/src/main/java/io/sentry/EnvelopeSender.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java rename to sentry/src/main/java/io/sentry/EnvelopeSender.java index 2c10965ce..26b4ab771 100644 --- a/sentry-core/src/main/java/io/sentry/core/EnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/EnvelopeSender.java @@ -1,10 +1,10 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.cache.EnvelopeCache; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.Retryable; -import io.sentry.core.util.LogUtils; -import io.sentry.core.util.Objects; +import io.sentry.cache.EnvelopeCache; +import io.sentry.hints.Flushable; +import io.sentry.hints.Retryable; +import io.sentry.util.LogUtils; +import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/EventProcessor.java b/sentry/src/main/java/io/sentry/EventProcessor.java similarity index 86% rename from sentry-core/src/main/java/io/sentry/core/EventProcessor.java rename to sentry/src/main/java/io/sentry/EventProcessor.java index 9e225ed63..107cbd715 100644 --- a/sentry-core/src/main/java/io/sentry/core/EventProcessor.java +++ b/sentry/src/main/java/io/sentry/EventProcessor.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/GsonSerializer.java b/sentry/src/main/java/io/sentry/GsonSerializer.java similarity index 88% rename from sentry-core/src/main/java/io/sentry/core/GsonSerializer.java rename to sentry/src/main/java/io/sentry/GsonSerializer.java index 4d44fa523..3a2ec985e 100644 --- a/sentry-core/src/main/java/io/sentry/core/GsonSerializer.java +++ b/sentry/src/main/java/io/sentry/GsonSerializer.java @@ -1,24 +1,24 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import io.sentry.core.adapters.ContextsDeserializerAdapter; -import io.sentry.core.adapters.ContextsSerializerAdapter; -import io.sentry.core.adapters.DateDeserializerAdapter; -import io.sentry.core.adapters.DateSerializerAdapter; -import io.sentry.core.adapters.OrientationDeserializerAdapter; -import io.sentry.core.adapters.OrientationSerializerAdapter; -import io.sentry.core.adapters.SentryIdDeserializerAdapter; -import io.sentry.core.adapters.SentryIdSerializerAdapter; -import io.sentry.core.adapters.SentryLevelDeserializerAdapter; -import io.sentry.core.adapters.SentryLevelSerializerAdapter; -import io.sentry.core.adapters.TimeZoneDeserializerAdapter; -import io.sentry.core.adapters.TimeZoneSerializerAdapter; -import io.sentry.core.protocol.Contexts; -import io.sentry.core.protocol.Device; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.util.Objects; +import io.sentry.adapters.ContextsDeserializerAdapter; +import io.sentry.adapters.ContextsSerializerAdapter; +import io.sentry.adapters.DateDeserializerAdapter; +import io.sentry.adapters.DateSerializerAdapter; +import io.sentry.adapters.OrientationDeserializerAdapter; +import io.sentry.adapters.OrientationSerializerAdapter; +import io.sentry.adapters.SentryIdDeserializerAdapter; +import io.sentry.adapters.SentryIdSerializerAdapter; +import io.sentry.adapters.SentryLevelDeserializerAdapter; +import io.sentry.adapters.SentryLevelSerializerAdapter; +import io.sentry.adapters.TimeZoneDeserializerAdapter; +import io.sentry.adapters.TimeZoneSerializerAdapter; +import io.sentry.protocol.Contexts; +import io.sentry.protocol.Device; +import io.sentry.protocol.SentryId; +import io.sentry.util.Objects; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/sentry-core/src/main/java/io/sentry/core/HttpTransportFactory.java b/sentry/src/main/java/io/sentry/HttpTransportFactory.java similarity index 83% rename from sentry-core/src/main/java/io/sentry/core/HttpTransportFactory.java rename to sentry/src/main/java/io/sentry/HttpTransportFactory.java index 29a457c0e..7f902498e 100644 --- a/sentry-core/src/main/java/io/sentry/core/HttpTransportFactory.java +++ b/sentry/src/main/java/io/sentry/HttpTransportFactory.java @@ -1,8 +1,8 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.transport.HttpTransport; -import io.sentry.core.transport.IConnectionConfigurator; -import io.sentry.core.transport.ITransport; +import io.sentry.transport.HttpTransport; +import io.sentry.transport.IConnectionConfigurator; +import io.sentry.transport.ITransport; import java.net.MalformedURLException; import java.net.URL; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/Hub.java b/sentry/src/main/java/io/sentry/Hub.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/Hub.java rename to sentry/src/main/java/io/sentry/Hub.java index 44421fdaa..69d4c112a 100644 --- a/sentry-core/src/main/java/io/sentry/core/Hub.java +++ b/sentry/src/main/java/io/sentry/Hub.java @@ -1,10 +1,10 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.hints.SessionEndHint; -import io.sentry.core.hints.SessionStartHint; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.User; -import io.sentry.core.util.Objects; +import io.sentry.hints.SessionEndHint; +import io.sentry.hints.SessionStartHint; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.User; +import io.sentry.util.Objects; import java.io.Closeable; import java.util.Deque; import java.util.List; diff --git a/sentry-core/src/main/java/io/sentry/core/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/HubAdapter.java rename to sentry/src/main/java/io/sentry/HubAdapter.java index 6bf16abc3..ed4c0b474 100644 --- a/sentry-core/src/main/java/io/sentry/core/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.User; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/IEnvelopeReader.java b/sentry/src/main/java/io/sentry/IEnvelopeReader.java similarity index 91% rename from sentry-core/src/main/java/io/sentry/core/IEnvelopeReader.java rename to sentry/src/main/java/io/sentry/IEnvelopeReader.java index d97f6fbd6..145b63729 100644 --- a/sentry-core/src/main/java/io/sentry/core/IEnvelopeReader.java +++ b/sentry/src/main/java/io/sentry/IEnvelopeReader.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.IOException; import java.io.InputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/IEnvelopeSender.java b/sentry/src/main/java/io/sentry/IEnvelopeSender.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/IEnvelopeSender.java rename to sentry/src/main/java/io/sentry/IEnvelopeSender.java index 5af52c195..2e203e039 100644 --- a/sentry-core/src/main/java/io/sentry/core/IEnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/IEnvelopeSender.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/IHub.java b/sentry/src/main/java/io/sentry/IHub.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/IHub.java rename to sentry/src/main/java/io/sentry/IHub.java index 1b71b994b..9f0369d88 100644 --- a/sentry-core/src/main/java/io/sentry/core/IHub.java +++ b/sentry/src/main/java/io/sentry/IHub.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.User; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/ILogger.java b/sentry/src/main/java/io/sentry/ILogger.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/ILogger.java rename to sentry/src/main/java/io/sentry/ILogger.java index 08e8e4a2f..09804e81a 100644 --- a/sentry-core/src/main/java/io/sentry/core/ILogger.java +++ b/sentry/src/main/java/io/sentry/ILogger.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; /** Sentry SDK internal logging interface. */ public interface ILogger { diff --git a/sentry-core/src/main/java/io/sentry/core/ISentryClient.java b/sentry/src/main/java/io/sentry/ISentryClient.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/ISentryClient.java rename to sentry/src/main/java/io/sentry/ISentryClient.java index 0fc363fe1..e41efec32 100644 --- a/sentry-core/src/main/java/io/sentry/core/ISentryClient.java +++ b/sentry/src/main/java/io/sentry/ISentryClient.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.Message; -import io.sentry.core.protocol.SentryId; +import io.sentry.protocol.Message; +import io.sentry.protocol.SentryId; import org.jetbrains.annotations.Nullable; /** Sentry Client interface */ diff --git a/sentry-core/src/main/java/io/sentry/core/ISentryExecutorService.java b/sentry/src/main/java/io/sentry/ISentryExecutorService.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/ISentryExecutorService.java rename to sentry/src/main/java/io/sentry/ISentryExecutorService.java index b096ce7b6..1f54c388b 100644 --- a/sentry-core/src/main/java/io/sentry/core/ISentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/ISentryExecutorService.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.util.concurrent.Future; diff --git a/sentry-core/src/main/java/io/sentry/core/ISerializer.java b/sentry/src/main/java/io/sentry/ISerializer.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/ISerializer.java rename to sentry/src/main/java/io/sentry/ISerializer.java index b9664472f..8b8921644 100644 --- a/sentry-core/src/main/java/io/sentry/core/ISerializer.java +++ b/sentry/src/main/java/io/sentry/ISerializer.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.IOException; import java.io.InputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/IUnknownPropertiesConsumer.java b/sentry/src/main/java/io/sentry/IUnknownPropertiesConsumer.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/IUnknownPropertiesConsumer.java rename to sentry/src/main/java/io/sentry/IUnknownPropertiesConsumer.java index f6e31a6df..5da2df302 100644 --- a/sentry-core/src/main/java/io/sentry/core/IUnknownPropertiesConsumer.java +++ b/sentry/src/main/java/io/sentry/IUnknownPropertiesConsumer.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/Integration.java b/sentry/src/main/java/io/sentry/Integration.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/Integration.java rename to sentry/src/main/java/io/sentry/Integration.java index 1f80bdd20..346528671 100644 --- a/sentry-core/src/main/java/io/sentry/core/Integration.java +++ b/sentry/src/main/java/io/sentry/Integration.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; /** * Code that provides middlewares, bindings or hooks into certain frameworks or environments, along diff --git a/sentry-core/src/main/java/io/sentry/core/InvalidDsnException.java b/sentry/src/main/java/io/sentry/InvalidDsnException.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/InvalidDsnException.java rename to sentry/src/main/java/io/sentry/InvalidDsnException.java index 7c4e4966f..8ff38297a 100644 --- a/sentry-core/src/main/java/io/sentry/core/InvalidDsnException.java +++ b/sentry/src/main/java/io/sentry/InvalidDsnException.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; public final class InvalidDsnException extends RuntimeException { private static final long serialVersionUID = 412945154259913013L; diff --git a/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java b/sentry/src/main/java/io/sentry/MainEventProcessor.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java rename to sentry/src/main/java/io/sentry/MainEventProcessor.java index ea0b23a73..a1a822698 100644 --- a/sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java +++ b/sentry/src/main/java/io/sentry/MainEventProcessor.java @@ -1,8 +1,8 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryException; -import io.sentry.core.util.ApplyScopeUtils; -import io.sentry.core.util.Objects; +import io.sentry.protocol.SentryException; +import io.sentry.util.ApplyScopeUtils; +import io.sentry.util.Objects; import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/NoOpEnvelopeReader.java b/sentry/src/main/java/io/sentry/NoOpEnvelopeReader.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/NoOpEnvelopeReader.java rename to sentry/src/main/java/io/sentry/NoOpEnvelopeReader.java index 208cbc438..f06533c32 100644 --- a/sentry-core/src/main/java/io/sentry/core/NoOpEnvelopeReader.java +++ b/sentry/src/main/java/io/sentry/NoOpEnvelopeReader.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.IOException; import java.io.InputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/NoOpHub.java rename to sentry/src/main/java/io/sentry/NoOpHub.java index fb2b14bb0..8319ff554 100644 --- a/sentry-core/src/main/java/io/sentry/core/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.User; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/NoOpLogger.java b/sentry/src/main/java/io/sentry/NoOpLogger.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/NoOpLogger.java rename to sentry/src/main/java/io/sentry/NoOpLogger.java index d7aaf3a8c..32fc35a85 100644 --- a/sentry-core/src/main/java/io/sentry/core/NoOpLogger.java +++ b/sentry/src/main/java/io/sentry/NoOpLogger.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; /** No-op implementation of ILogger */ public final class NoOpLogger implements ILogger { diff --git a/sentry-core/src/main/java/io/sentry/core/NoOpSentryClient.java b/sentry/src/main/java/io/sentry/NoOpSentryClient.java similarity index 92% rename from sentry-core/src/main/java/io/sentry/core/NoOpSentryClient.java rename to sentry/src/main/java/io/sentry/NoOpSentryClient.java index 69e7f3bb4..65c6256d7 100644 --- a/sentry-core/src/main/java/io/sentry/core/NoOpSentryClient.java +++ b/sentry/src/main/java/io/sentry/NoOpSentryClient.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryId; +import io.sentry.protocol.SentryId; import org.jetbrains.annotations.Nullable; final class NoOpSentryClient implements ISentryClient { diff --git a/sentry-core/src/main/java/io/sentry/core/NoOpSerializer.java b/sentry/src/main/java/io/sentry/NoOpSerializer.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/NoOpSerializer.java rename to sentry/src/main/java/io/sentry/NoOpSerializer.java index ab988299f..f4047d47c 100644 --- a/sentry-core/src/main/java/io/sentry/core/NoOpSerializer.java +++ b/sentry/src/main/java/io/sentry/NoOpSerializer.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.IOException; import java.io.InputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/OptionsContainer.java b/sentry/src/main/java/io/sentry/OptionsContainer.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/OptionsContainer.java rename to sentry/src/main/java/io/sentry/OptionsContainer.java index d5c6835f8..a3593c537 100644 --- a/sentry-core/src/main/java/io/sentry/core/OptionsContainer.java +++ b/sentry/src/main/java/io/sentry/OptionsContainer.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.lang.reflect.InvocationTargetException; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/OutboxSender.java b/sentry/src/main/java/io/sentry/OutboxSender.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/OutboxSender.java rename to sentry/src/main/java/io/sentry/OutboxSender.java index 3d466e409..55c5b2104 100644 --- a/sentry-core/src/main/java/io/sentry/core/OutboxSender.java +++ b/sentry/src/main/java/io/sentry/OutboxSender.java @@ -1,14 +1,14 @@ -package io.sentry.core; +package io.sentry; -import static io.sentry.core.SentryLevel.ERROR; -import static io.sentry.core.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE; +import static io.sentry.SentryLevel.ERROR; +import static io.sentry.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SubmissionResult; -import io.sentry.core.util.CollectionUtils; -import io.sentry.core.util.LogUtils; -import io.sentry.core.util.Objects; +import io.sentry.hints.Flushable; +import io.sentry.hints.Retryable; +import io.sentry.hints.SubmissionResult; +import io.sentry.util.CollectionUtils; +import io.sentry.util.LogUtils; +import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/Scope.java b/sentry/src/main/java/io/sentry/Scope.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/Scope.java rename to sentry/src/main/java/io/sentry/Scope.java index ec54ab860..4bea21754 100644 --- a/sentry-core/src/main/java/io/sentry/core/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.Contexts; -import io.sentry.core.protocol.User; +import io.sentry.protocol.Contexts; +import io.sentry.protocol.User; import java.util.ArrayList; import java.util.List; import java.util.Locale; diff --git a/sentry-core/src/main/java/io/sentry/core/ScopeCallback.java b/sentry/src/main/java/io/sentry/ScopeCallback.java similarity index 71% rename from sentry-core/src/main/java/io/sentry/core/ScopeCallback.java rename to sentry/src/main/java/io/sentry/ScopeCallback.java index 90d2e51f2..a20632c46 100644 --- a/sentry-core/src/main/java/io/sentry/core/ScopeCallback.java +++ b/sentry/src/main/java/io/sentry/ScopeCallback.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; public interface ScopeCallback { void run(Scope scope); diff --git a/sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java rename to sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java index 8200be48d..9ecef1a77 100644 --- a/sentry-core/src/main/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegration.java +++ b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.io.File; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java b/sentry/src/main/java/io/sentry/SendFireAndForgetEnvelopeSender.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java rename to sentry/src/main/java/io/sentry/SendFireAndForgetEnvelopeSender.java index 172fe51f2..1e90cabc1 100644 --- a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetEnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/SendFireAndForgetEnvelopeSender.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java b/sentry/src/main/java/io/sentry/SendFireAndForgetOutboxSender.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java rename to sentry/src/main/java/io/sentry/SendFireAndForgetOutboxSender.java index a56b1a7da..766b9fa4e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SendFireAndForgetOutboxSender.java +++ b/sentry/src/main/java/io/sentry/SendFireAndForgetOutboxSender.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/Sentry.java rename to sentry/src/main/java/io/sentry/Sentry.java index 05c2664cd..36c8a684f 100644 --- a/sentry-core/src/main/java/io/sentry/core/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -1,8 +1,8 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.cache.EnvelopeCache; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.User; +import io.sentry.cache.EnvelopeCache; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.User; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.List; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/SentryClient.java rename to sentry/src/main/java/io/sentry/SentryClient.java index 7f00fa580..2dee70f8f 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -1,12 +1,12 @@ -package io.sentry.core; - -import io.sentry.core.hints.DiskFlushNotification; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.transport.Connection; -import io.sentry.core.transport.ITransport; -import io.sentry.core.transport.NoOpTransport; -import io.sentry.core.util.ApplyScopeUtils; -import io.sentry.core.util.Objects; +package io.sentry; + +import io.sentry.hints.DiskFlushNotification; +import io.sentry.protocol.SentryId; +import io.sentry.transport.Connection; +import io.sentry.transport.ITransport; +import io.sentry.transport.NoOpTransport; +import io.sentry.util.ApplyScopeUtils; +import io.sentry.util.Objects; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java b/sentry/src/main/java/io/sentry/SentryEnvelope.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java rename to sentry/src/main/java/io/sentry/SentryEnvelope.java index 54ceb3a3b..f2a967b72 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelope.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelope.java @@ -1,8 +1,8 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.util.Objects; +import io.sentry.protocol.SdkVersion; +import io.sentry.protocol.SentryId; +import io.sentry.util.Objects; import java.io.IOException; import java.util.ArrayList; import java.util.List; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java similarity index 88% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeader.java rename to sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java index 03a6e14a1..6c8dc80bb 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java @@ -1,7 +1,7 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.protocol.SentryId; +import io.sentry.protocol.SdkVersion; +import io.sentry.protocol.SentryId; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeaderAdapter.java b/sentry/src/main/java/io/sentry/SentryEnvelopeHeaderAdapter.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeaderAdapter.java rename to sentry/src/main/java/io/sentry/SentryEnvelopeHeaderAdapter.java index 386098bb7..e0266bb8e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeHeaderAdapter.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeHeaderAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.protocol.SentryId; -import io.sentry.core.protocol.SentryPackage; +import io.sentry.protocol.SdkVersion; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryPackage; import java.io.IOException; import java.util.List; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java rename to sentry/src/main/java/io/sentry/SentryEnvelopeItem.java index 46cf879d5..7e71d6552 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItem.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeader.java rename to sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java index caa2bea77..2e39b3520 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import java.util.concurrent.Callable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeaderAdapter.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeaderAdapter.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeaderAdapter.java rename to sentry/src/main/java/io/sentry/SentryEnvelopeItemHeaderAdapter.java index 8a161e54d..ee3f9030d 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEnvelopeItemHeaderAdapter.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeaderAdapter.java @@ -1,10 +1,10 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import io.sentry.core.util.StringUtils; +import io.sentry.util.StringUtils; import java.io.IOException; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java b/sentry/src/main/java/io/sentry/SentryEvent.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/SentryEvent.java rename to sentry/src/main/java/io/sentry/SentryEvent.java index 854d68c47..1bd1b1a44 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryEvent.java +++ b/sentry/src/main/java/io/sentry/SentryEvent.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.*; +import io.sentry.protocol.*; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryExceptionFactory.java b/sentry/src/main/java/io/sentry/SentryExceptionFactory.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/SentryExceptionFactory.java rename to sentry/src/main/java/io/sentry/SentryExceptionFactory.java index ffc5db043..df6d6cf34 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryExceptionFactory.java +++ b/sentry/src/main/java/io/sentry/SentryExceptionFactory.java @@ -1,10 +1,10 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.exception.ExceptionMechanismException; -import io.sentry.core.protocol.Mechanism; -import io.sentry.core.protocol.SentryException; -import io.sentry.core.protocol.SentryStackTrace; -import io.sentry.core.util.Objects; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.protocol.Mechanism; +import io.sentry.protocol.SentryException; +import io.sentry.protocol.SentryStackTrace; +import io.sentry.util.Objects; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SentryExecutorService.java rename to sentry/src/main/java/io/sentry/SentryExecutorService.java index 9df4773d5..d115988d8 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryItemType.java b/sentry/src/main/java/io/sentry/SentryItemType.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/SentryItemType.java rename to sentry/src/main/java/io/sentry/SentryItemType.java index 145bdc264..3ad9b3afb 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryItemType.java +++ b/sentry/src/main/java/io/sentry/SentryItemType.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryLevel.java b/sentry/src/main/java/io/sentry/SentryLevel.java similarity index 87% rename from sentry-core/src/main/java/io/sentry/core/SentryLevel.java rename to sentry/src/main/java/io/sentry/SentryLevel.java index 244f2331c..e1a6c2dbf 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryLevel.java +++ b/sentry/src/main/java/io/sentry/SentryLevel.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; /** the SentryLevel */ public enum SentryLevel { diff --git a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SentryOptions.java rename to sentry/src/main/java/io/sentry/SentryOptions.java index 73bad4341..5569311fa 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -1,13 +1,13 @@ -package io.sentry.core; +package io.sentry; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.protocol.SdkVersion; -import io.sentry.core.transport.ITransport; -import io.sentry.core.transport.ITransportGate; -import io.sentry.core.transport.NoOpEnvelopeCache; -import io.sentry.core.transport.NoOpTransport; -import io.sentry.core.transport.NoOpTransportGate; +import io.sentry.cache.IEnvelopeCache; +import io.sentry.protocol.SdkVersion; +import io.sentry.transport.ITransport; +import io.sentry.transport.ITransportGate; +import io.sentry.transport.NoOpEnvelopeCache; +import io.sentry.transport.NoOpTransport; +import io.sentry.transport.NoOpTransportGate; import java.io.File; import java.net.Proxy; import java.util.List; @@ -1003,7 +1003,7 @@ public SentryOptions() { sdkVersion.setName(BuildConfig.SENTRY_JAVA_SDK_NAME); String version = BuildConfig.VERSION_NAME; sdkVersion.setVersion(version); - sdkVersion.addPackage("maven:sentry-core", version); + sdkVersion.addPackage("maven:sentry", version); return sdkVersion; } diff --git a/sentry-core/src/main/java/io/sentry/core/SentryStackTraceFactory.java b/sentry/src/main/java/io/sentry/SentryStackTraceFactory.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/SentryStackTraceFactory.java rename to sentry/src/main/java/io/sentry/SentryStackTraceFactory.java index 62e3d5419..10fe8d2fe 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryStackTraceFactory.java +++ b/sentry/src/main/java/io/sentry/SentryStackTraceFactory.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryStackFrame; +import io.sentry.protocol.SentryStackFrame; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryThreadFactory.java b/sentry/src/main/java/io/sentry/SentryThreadFactory.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/SentryThreadFactory.java rename to sentry/src/main/java/io/sentry/SentryThreadFactory.java index fe2b223f8..ec6ce0dc1 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryThreadFactory.java +++ b/sentry/src/main/java/io/sentry/SentryThreadFactory.java @@ -1,9 +1,9 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.SentryStackFrame; -import io.sentry.core.protocol.SentryStackTrace; -import io.sentry.core.protocol.SentryThread; -import io.sentry.core.util.Objects; +import io.sentry.protocol.SentryStackFrame; +import io.sentry.protocol.SentryStackTrace; +import io.sentry.protocol.SentryThread; +import io.sentry.util.Objects; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/sentry-core/src/main/java/io/sentry/core/SentryValues.java b/sentry/src/main/java/io/sentry/SentryValues.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/SentryValues.java rename to sentry/src/main/java/io/sentry/SentryValues.java index ced625df1..ecf32e72e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SentryValues.java +++ b/sentry/src/main/java/io/sentry/SentryValues.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.util.ArrayList; import java.util.List; diff --git a/sentry-core/src/main/java/io/sentry/core/Session.java b/sentry/src/main/java/io/sentry/Session.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/Session.java rename to sentry/src/main/java/io/sentry/Session.java index c5dd5a08a..999ba4e20 100644 --- a/sentry-core/src/main/java/io/sentry/core/Session.java +++ b/sentry/src/main/java/io/sentry/Session.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.protocol.User; +import io.sentry.protocol.User; import java.util.Date; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; diff --git a/sentry-core/src/main/java/io/sentry/core/SessionAdapter.java b/sentry/src/main/java/io/sentry/SessionAdapter.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SessionAdapter.java rename to sentry/src/main/java/io/sentry/SessionAdapter.java index c463fd86a..5480b6493 100644 --- a/sentry-core/src/main/java/io/sentry/core/SessionAdapter.java +++ b/sentry/src/main/java/io/sentry/SessionAdapter.java @@ -1,11 +1,11 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import io.sentry.core.util.Objects; -import io.sentry.core.util.StringUtils; +import io.sentry.util.Objects; +import io.sentry.util.StringUtils; import java.io.IOException; import java.util.Date; import java.util.Locale; diff --git a/sentry-core/src/main/java/io/sentry/core/ShutdownHookIntegration.java b/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java similarity index 92% rename from sentry-core/src/main/java/io/sentry/core/ShutdownHookIntegration.java rename to sentry/src/main/java/io/sentry/ShutdownHookIntegration.java index b30149ba9..cc76d7b47 100644 --- a/sentry-core/src/main/java/io/sentry/core/ShutdownHookIntegration.java +++ b/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java @@ -1,6 +1,6 @@ -package io.sentry.core; +package io.sentry; -import io.sentry.core.util.Objects; +import io.sentry.util.Objects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; diff --git a/sentry-core/src/main/java/io/sentry/core/SynchronizedCollection.java b/sentry/src/main/java/io/sentry/SynchronizedCollection.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/SynchronizedCollection.java rename to sentry/src/main/java/io/sentry/SynchronizedCollection.java index 84d5ba18f..3d430952e 100644 --- a/sentry-core/src/main/java/io/sentry/core/SynchronizedCollection.java +++ b/sentry/src/main/java/io/sentry/SynchronizedCollection.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.sentry.core; +package io.sentry; import com.jakewharton.nopen.annotation.Open; import java.io.Serializable; diff --git a/sentry-core/src/main/java/io/sentry/core/SynchronizedQueue.java b/sentry/src/main/java/io/sentry/SynchronizedQueue.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/SynchronizedQueue.java rename to sentry/src/main/java/io/sentry/SynchronizedQueue.java index 015e35066..6236f052d 100644 --- a/sentry-core/src/main/java/io/sentry/core/SynchronizedQueue.java +++ b/sentry/src/main/java/io/sentry/SynchronizedQueue.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.sentry.core; +package io.sentry; import java.util.Queue; diff --git a/sentry-core/src/main/java/io/sentry/core/SystemOutLogger.java b/sentry/src/main/java/io/sentry/SystemOutLogger.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/SystemOutLogger.java rename to sentry/src/main/java/io/sentry/SystemOutLogger.java index 20f7ce810..90aef4244 100644 --- a/sentry-core/src/main/java/io/sentry/core/SystemOutLogger.java +++ b/sentry/src/main/java/io/sentry/SystemOutLogger.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandler.java b/sentry/src/main/java/io/sentry/UncaughtExceptionHandler.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandler.java rename to sentry/src/main/java/io/sentry/UncaughtExceptionHandler.java index 4c7dcea07..74457d8d3 100644 --- a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandler.java +++ b/sentry/src/main/java/io/sentry/UncaughtExceptionHandler.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; /** An adapter to make UncaughtExceptionHandler testable */ interface UncaughtExceptionHandler { diff --git a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java rename to sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java index 10ea15646..6ae251254 100644 --- a/sentry-core/src/main/java/io/sentry/core/UncaughtExceptionHandlerIntegration.java +++ b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java @@ -1,13 +1,13 @@ -package io.sentry.core; +package io.sentry; -import static io.sentry.core.SentryLevel.ERROR; +import static io.sentry.SentryLevel.ERROR; -import io.sentry.core.exception.ExceptionMechanismException; -import io.sentry.core.hints.DiskFlushNotification; -import io.sentry.core.hints.Flushable; -import io.sentry.core.hints.SessionEnd; -import io.sentry.core.protocol.Mechanism; -import io.sentry.core.util.Objects; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.hints.DiskFlushNotification; +import io.sentry.hints.Flushable; +import io.sentry.hints.SessionEnd; +import io.sentry.protocol.Mechanism; +import io.sentry.util.Objects; import java.io.Closeable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/sentry-core/src/main/java/io/sentry/core/UnknownPropertiesTypeAdapterFactory.java b/sentry/src/main/java/io/sentry/UnknownPropertiesTypeAdapterFactory.java similarity index 99% rename from sentry-core/src/main/java/io/sentry/core/UnknownPropertiesTypeAdapterFactory.java rename to sentry/src/main/java/io/sentry/UnknownPropertiesTypeAdapterFactory.java index 42717f0d1..e9c9c5b5d 100644 --- a/sentry-core/src/main/java/io/sentry/core/UnknownPropertiesTypeAdapterFactory.java +++ b/sentry/src/main/java/io/sentry/UnknownPropertiesTypeAdapterFactory.java @@ -1,4 +1,4 @@ -package io.sentry.core; +package io.sentry; import com.google.gson.FieldNamingStrategy; import com.google.gson.Gson; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/ContextsDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/ContextsDeserializerAdapter.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/adapters/ContextsDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/ContextsDeserializerAdapter.java index eaa86e60d..aaf90d90d 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/ContextsDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/ContextsDeserializerAdapter.java @@ -1,19 +1,19 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.App; -import io.sentry.core.protocol.Browser; -import io.sentry.core.protocol.Contexts; -import io.sentry.core.protocol.Device; -import io.sentry.core.protocol.Gpu; -import io.sentry.core.protocol.OperatingSystem; -import io.sentry.core.protocol.SentryRuntime; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.App; +import io.sentry.protocol.Browser; +import io.sentry.protocol.Contexts; +import io.sentry.protocol.Device; +import io.sentry.protocol.Gpu; +import io.sentry.protocol.OperatingSystem; +import io.sentry.protocol.SentryRuntime; import java.lang.reflect.Type; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/ContextsSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/ContextsSerializerAdapter.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/adapters/ContextsSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/ContextsSerializerAdapter.java index ef96fafd8..834c04915 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/ContextsSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/ContextsSerializerAdapter.java @@ -1,13 +1,13 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.Contexts; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.Contexts; import java.lang.reflect.Type; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/DateDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/DateDeserializerAdapter.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/adapters/DateDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/DateDeserializerAdapter.java index ed0e520d6..d5331f561 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/DateDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/DateDeserializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import io.sentry.core.DateUtils; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.DateUtils; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.Date; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/DateSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/DateSerializerAdapter.java similarity index 86% rename from sentry-core/src/main/java/io/sentry/core/adapters/DateSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/DateSerializerAdapter.java index 3a7e2ae61..419b57917 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/DateSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/DateSerializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.DateUtils; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.DateUtils; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.Date; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/OrientationDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/OrientationDeserializerAdapter.java similarity index 88% rename from sentry-core/src/main/java/io/sentry/core/adapters/OrientationDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/OrientationDeserializerAdapter.java index 53d3a1d8d..d4fd295ec 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/OrientationDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/OrientationDeserializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.Device; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.Device; import java.lang.reflect.Type; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/OrientationSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/OrientationSerializerAdapter.java similarity index 87% rename from sentry-core/src/main/java/io/sentry/core/adapters/OrientationSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/OrientationSerializerAdapter.java index 9a7c97ed3..4e1ee6c72 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/OrientationSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/OrientationSerializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.Device; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.Device; import java.lang.reflect.Type; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/SentryIdDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SentryIdDeserializerAdapter.java similarity index 86% rename from sentry-core/src/main/java/io/sentry/core/adapters/SentryIdDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/SentryIdDeserializerAdapter.java index 10c0b77dd..83ed4193b 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/SentryIdDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/SentryIdDeserializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.SentryId; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.SentryId; import java.lang.reflect.Type; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/SentryIdSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SentryIdSerializerAdapter.java similarity index 85% rename from sentry-core/src/main/java/io/sentry/core/adapters/SentryIdSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/SentryIdSerializerAdapter.java index 251b3ccba..7cf6efab4 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/SentryIdSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/SentryIdSerializerAdapter.java @@ -1,12 +1,12 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; -import io.sentry.core.protocol.SentryId; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.protocol.SentryId; import java.lang.reflect.Type; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SentryLevelDeserializerAdapter.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/SentryLevelDeserializerAdapter.java index 8018a64e3..09f109d5b 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/SentryLevelDeserializerAdapter.java @@ -1,11 +1,11 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SentryLevelSerializerAdapter.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/SentryLevelSerializerAdapter.java index fb5a383a3..911f83015 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/SentryLevelSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/SentryLevelSerializerAdapter.java @@ -1,11 +1,11 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneDeserializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/TimeZoneDeserializerAdapter.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneDeserializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/TimeZoneDeserializerAdapter.java index 6d7ecaeb2..2cd89b4fb 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneDeserializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/TimeZoneDeserializerAdapter.java @@ -1,11 +1,11 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.TimeZone; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/TimeZoneSerializerAdapter.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneSerializerAdapter.java rename to sentry/src/main/java/io/sentry/adapters/TimeZoneSerializerAdapter.java index 6e7009d99..4c5356229 100644 --- a/sentry-core/src/main/java/io/sentry/core/adapters/TimeZoneSerializerAdapter.java +++ b/sentry/src/main/java/io/sentry/adapters/TimeZoneSerializerAdapter.java @@ -1,11 +1,11 @@ -package io.sentry.core.adapters; +package io.sentry.adapters; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.lang.reflect.Type; import java.util.TimeZone; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java b/sentry/src/main/java/io/sentry/cache/CacheStrategy.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java rename to sentry/src/main/java/io/sentry/cache/CacheStrategy.java index 61e224e5d..40d36c585 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/CacheStrategy.java +++ b/sentry/src/main/java/io/sentry/cache/CacheStrategy.java @@ -1,15 +1,15 @@ -package io.sentry.core.cache; - -import static io.sentry.core.SentryLevel.ERROR; - -import io.sentry.core.ISerializer; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEnvelopeItem; -import io.sentry.core.SentryItemType; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.Session; -import io.sentry.core.util.Objects; +package io.sentry.cache; + +import static io.sentry.SentryLevel.ERROR; + +import io.sentry.ISerializer; +import io.sentry.SentryEnvelope; +import io.sentry.SentryEnvelopeItem; +import io.sentry.SentryItemType; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.Session; +import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java rename to sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index a66cc6602..347712cb7 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -1,21 +1,21 @@ -package io.sentry.core.cache; +package io.sentry.cache; -import static io.sentry.core.SentryLevel.DEBUG; -import static io.sentry.core.SentryLevel.ERROR; -import static io.sentry.core.SentryLevel.INFO; -import static io.sentry.core.SentryLevel.WARNING; +import static io.sentry.SentryLevel.DEBUG; +import static io.sentry.SentryLevel.ERROR; +import static io.sentry.SentryLevel.INFO; +import static io.sentry.SentryLevel.WARNING; import static java.lang.String.format; -import io.sentry.core.DateUtils; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEnvelopeItem; -import io.sentry.core.SentryItemType; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.Session; -import io.sentry.core.hints.SessionEnd; -import io.sentry.core.hints.SessionStart; -import io.sentry.core.util.Objects; +import io.sentry.DateUtils; +import io.sentry.SentryEnvelope; +import io.sentry.SentryEnvelopeItem; +import io.sentry.SentryItemType; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.Session; +import io.sentry.hints.SessionEnd; +import io.sentry.hints.SessionStart; +import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/sentry-core/src/main/java/io/sentry/core/cache/IEnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java similarity index 81% rename from sentry-core/src/main/java/io/sentry/core/cache/IEnvelopeCache.java rename to sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java index eac573080..a674c7f77 100644 --- a/sentry-core/src/main/java/io/sentry/core/cache/IEnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java @@ -1,6 +1,6 @@ -package io.sentry.core.cache; +package io.sentry.cache; -import io.sentry.core.SentryEnvelope; +import io.sentry.SentryEnvelope; import org.jetbrains.annotations.Nullable; public interface IEnvelopeCache extends Iterable { diff --git a/sentry-core/src/main/java/io/sentry/core/exception/ExceptionMechanismException.java b/sentry/src/main/java/io/sentry/exception/ExceptionMechanismException.java similarity index 83% rename from sentry-core/src/main/java/io/sentry/core/exception/ExceptionMechanismException.java rename to sentry/src/main/java/io/sentry/exception/ExceptionMechanismException.java index b7f852232..5d7914c98 100644 --- a/sentry-core/src/main/java/io/sentry/core/exception/ExceptionMechanismException.java +++ b/sentry/src/main/java/io/sentry/exception/ExceptionMechanismException.java @@ -1,12 +1,12 @@ -package io.sentry.core.exception; +package io.sentry.exception; -import io.sentry.core.protocol.Mechanism; +import io.sentry.protocol.Mechanism; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; /** - * A throwable decorator that holds an {@link io.sentry.core.protocol.Mechanism} related to the - * decorated {@link Throwable}. + * A throwable decorator that holds an {@link io.sentry.protocol.Mechanism} related to the decorated + * {@link Throwable}. */ @ApiStatus.Internal public final class ExceptionMechanismException extends RuntimeException { diff --git a/sentry-core/src/main/java/io/sentry/core/hints/ApplyScopeData.java b/sentry/src/main/java/io/sentry/hints/ApplyScopeData.java similarity index 86% rename from sentry-core/src/main/java/io/sentry/core/hints/ApplyScopeData.java rename to sentry/src/main/java/io/sentry/hints/ApplyScopeData.java index c3d4997c1..91da65bd8 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/ApplyScopeData.java +++ b/sentry/src/main/java/io/sentry/hints/ApplyScopeData.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; /** * Marker interface for applying scope's data. This means applying data relevant to the current diff --git a/sentry-core/src/main/java/io/sentry/core/hints/Cached.java b/sentry/src/main/java/io/sentry/hints/Cached.java similarity index 76% rename from sentry-core/src/main/java/io/sentry/core/hints/Cached.java rename to sentry/src/main/java/io/sentry/hints/Cached.java index 100f90695..d3bacd850 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/Cached.java +++ b/sentry/src/main/java/io/sentry/hints/Cached.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; /** Marker interface for a capture involving data cached from disk */ public interface Cached {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/DiskFlushNotification.java b/sentry/src/main/java/io/sentry/hints/DiskFlushNotification.java similarity index 68% rename from sentry-core/src/main/java/io/sentry/core/hints/DiskFlushNotification.java rename to sentry/src/main/java/io/sentry/hints/DiskFlushNotification.java index 7ade8f018..52d32e850 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/DiskFlushNotification.java +++ b/sentry/src/main/java/io/sentry/hints/DiskFlushNotification.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; public interface DiskFlushNotification { void markFlushed(); diff --git a/sentry-core/src/main/java/io/sentry/core/hints/Flushable.java b/sentry/src/main/java/io/sentry/hints/Flushable.java similarity index 79% rename from sentry-core/src/main/java/io/sentry/core/hints/Flushable.java rename to sentry/src/main/java/io/sentry/hints/Flushable.java index 970bc1df1..f5348dabf 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/Flushable.java +++ b/sentry/src/main/java/io/sentry/hints/Flushable.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; /** marker interface that awaits events to be flushed */ public interface Flushable { diff --git a/sentry-core/src/main/java/io/sentry/core/hints/Retryable.java b/sentry/src/main/java/io/sentry/hints/Retryable.java similarity index 74% rename from sentry-core/src/main/java/io/sentry/core/hints/Retryable.java rename to sentry/src/main/java/io/sentry/hints/Retryable.java index c9a57ea20..51bf85d33 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/Retryable.java +++ b/sentry/src/main/java/io/sentry/hints/Retryable.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; public interface Retryable { boolean isRetry(); diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionEnd.java b/sentry/src/main/java/io/sentry/hints/SessionEnd.java similarity index 74% rename from sentry-core/src/main/java/io/sentry/core/hints/SessionEnd.java rename to sentry/src/main/java/io/sentry/hints/SessionEnd.java index 84ea9a7b8..59d7f120e 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionEnd.java +++ b/sentry/src/main/java/io/sentry/hints/SessionEnd.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; /** Hint that shows this is a session end envelope */ public interface SessionEnd {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionEndHint.java b/sentry/src/main/java/io/sentry/hints/SessionEndHint.java similarity index 66% rename from sentry-core/src/main/java/io/sentry/core/hints/SessionEndHint.java rename to sentry/src/main/java/io/sentry/hints/SessionEndHint.java index fdccfe95e..c083560da 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionEndHint.java +++ b/sentry/src/main/java/io/sentry/hints/SessionEndHint.java @@ -1,3 +1,3 @@ -package io.sentry.core.hints; +package io.sentry.hints; public final class SessionEndHint implements SessionEnd {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionStart.java b/sentry/src/main/java/io/sentry/hints/SessionStart.java similarity index 75% rename from sentry-core/src/main/java/io/sentry/core/hints/SessionStart.java rename to sentry/src/main/java/io/sentry/hints/SessionStart.java index d9d7d6c08..6fdd7f9dd 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionStart.java +++ b/sentry/src/main/java/io/sentry/hints/SessionStart.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; /** Hint that shows this is a session start envelope */ public interface SessionStart {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SessionStartHint.java b/sentry/src/main/java/io/sentry/hints/SessionStartHint.java similarity index 68% rename from sentry-core/src/main/java/io/sentry/core/hints/SessionStartHint.java rename to sentry/src/main/java/io/sentry/hints/SessionStartHint.java index f8479553a..b59db1fe5 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/SessionStartHint.java +++ b/sentry/src/main/java/io/sentry/hints/SessionStartHint.java @@ -1,3 +1,3 @@ -package io.sentry.core.hints; +package io.sentry.hints; public final class SessionStartHint implements SessionStart {} diff --git a/sentry-core/src/main/java/io/sentry/core/hints/SubmissionResult.java b/sentry/src/main/java/io/sentry/hints/SubmissionResult.java similarity index 76% rename from sentry-core/src/main/java/io/sentry/core/hints/SubmissionResult.java rename to sentry/src/main/java/io/sentry/hints/SubmissionResult.java index 49993b549..ff25fa643 100644 --- a/sentry-core/src/main/java/io/sentry/core/hints/SubmissionResult.java +++ b/sentry/src/main/java/io/sentry/hints/SubmissionResult.java @@ -1,4 +1,4 @@ -package io.sentry.core.hints; +package io.sentry.hints; public interface SubmissionResult { void setResult(boolean success); diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/App.java b/sentry/src/main/java/io/sentry/protocol/App.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/protocol/App.java rename to sentry/src/main/java/io/sentry/protocol/App.java index bfc9abca0..6033b0d9c 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/App.java +++ b/sentry/src/main/java/io/sentry/protocol/App.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Browser.java b/sentry/src/main/java/io/sentry/protocol/Browser.java similarity index 91% rename from sentry-core/src/main/java/io/sentry/core/protocol/Browser.java rename to sentry/src/main/java/io/sentry/protocol/Browser.java index b0fa97ebd..e3c296d31 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Browser.java +++ b/sentry/src/main/java/io/sentry/protocol/Browser.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java b/sentry/src/main/java/io/sentry/protocol/Contexts.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java rename to sentry/src/main/java/io/sentry/protocol/Contexts.java index 7be1aebca..f2dd6d246 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java +++ b/sentry/src/main/java/io/sentry/protocol/Contexts.java @@ -1,4 +1,4 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/DebugImage.java b/sentry/src/main/java/io/sentry/protocol/DebugImage.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/protocol/DebugImage.java rename to sentry/src/main/java/io/sentry/protocol/DebugImage.java index a66ec30fe..598985ceb 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/DebugImage.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugImage.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/DebugMeta.java b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/protocol/DebugMeta.java rename to sentry/src/main/java/io/sentry/protocol/DebugMeta.java index 8000421e3..822ace34d 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/DebugMeta.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.List; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Device.java b/sentry/src/main/java/io/sentry/protocol/Device.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/protocol/Device.java rename to sentry/src/main/java/io/sentry/protocol/Device.java index f11fd8da3..06ddf0e11 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Device.java +++ b/sentry/src/main/java/io/sentry/protocol/Device.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Date; import java.util.Map; import java.util.TimeZone; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Gpu.java b/sentry/src/main/java/io/sentry/protocol/Gpu.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/protocol/Gpu.java rename to sentry/src/main/java/io/sentry/protocol/Gpu.java index ec8d28b51..f407512d1 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Gpu.java +++ b/sentry/src/main/java/io/sentry/protocol/Gpu.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Mechanism.java b/sentry/src/main/java/io/sentry/protocol/Mechanism.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/protocol/Mechanism.java rename to sentry/src/main/java/io/sentry/protocol/Mechanism.java index fd5c8b4b7..e10bc01b7 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Mechanism.java +++ b/sentry/src/main/java/io/sentry/protocol/Mechanism.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Message.java b/sentry/src/main/java/io/sentry/protocol/Message.java similarity index 92% rename from sentry-core/src/main/java/io/sentry/core/protocol/Message.java rename to sentry/src/main/java/io/sentry/protocol/Message.java index 96d95d788..001c5c5bf 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Message.java +++ b/sentry/src/main/java/io/sentry/protocol/Message.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.List; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/OperatingSystem.java b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/protocol/OperatingSystem.java rename to sentry/src/main/java/io/sentry/protocol/OperatingSystem.java index 53be02361..54272d405 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/OperatingSystem.java +++ b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Request.java b/sentry/src/main/java/io/sentry/protocol/Request.java similarity index 95% rename from sentry-core/src/main/java/io/sentry/core/protocol/Request.java rename to sentry/src/main/java/io/sentry/protocol/Request.java index 141d1e55a..8e6b539a9 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Request.java +++ b/sentry/src/main/java/io/sentry/protocol/Request.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SdkInfo.java b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/protocol/SdkInfo.java rename to sentry/src/main/java/io/sentry/protocol/SdkInfo.java index 892db05f0..547c4cff1 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SdkInfo.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SdkVersion.java b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/protocol/SdkVersion.java rename to sentry/src/main/java/io/sentry/protocol/SdkVersion.java index 4621be33d..b37a44227 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SdkVersion.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryException.java b/sentry/src/main/java/io/sentry/protocol/SentryException.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryException.java rename to sentry/src/main/java/io/sentry/protocol/SentryException.java index e61df0029..2beb26bbe 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryException.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryException.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryId.java b/sentry/src/main/java/io/sentry/protocol/SentryId.java similarity index 98% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryId.java rename to sentry/src/main/java/io/sentry/protocol/SentryId.java index 6fc32b754..7606e0d44 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryId.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryId.java @@ -1,4 +1,4 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; import java.util.UUID; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryPackage.java b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java similarity index 88% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryPackage.java rename to sentry/src/main/java/io/sentry/protocol/SentryPackage.java index 646de45e9..01cb92847 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryPackage.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryRuntime.java b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java similarity index 92% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryRuntime.java rename to sentry/src/main/java/io/sentry/protocol/SentryRuntime.java index e5d6735ca..45e5b322a 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryRuntime.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryStackFrame.java b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryStackFrame.java rename to sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java index dbb328ab5..5d39a2a83 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryStackFrame.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; import com.google.gson.annotations.SerializedName; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.List; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryStackTrace.java b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryStackTrace.java rename to sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java index 874f1469a..b70a03f8b 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryStackTrace.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.List; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/SentryThread.java b/sentry/src/main/java/io/sentry/protocol/SentryThread.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/protocol/SentryThread.java rename to sentry/src/main/java/io/sentry/protocol/SentryThread.java index 37ef583be..88e9345b9 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/SentryThread.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryThread.java @@ -1,6 +1,6 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; +import io.sentry.IUnknownPropertiesConsumer; import java.util.Map; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/User.java b/sentry/src/main/java/io/sentry/protocol/User.java similarity index 96% rename from sentry-core/src/main/java/io/sentry/core/protocol/User.java rename to sentry/src/main/java/io/sentry/protocol/User.java index 911624096..7cb42ccc3 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/User.java +++ b/sentry/src/main/java/io/sentry/protocol/User.java @@ -1,7 +1,7 @@ -package io.sentry.core.protocol; +package io.sentry.protocol; -import io.sentry.core.IUnknownPropertiesConsumer; -import io.sentry.core.util.CollectionUtils; +import io.sentry.IUnknownPropertiesConsumer; +import io.sentry.util.CollectionUtils; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java b/sentry/src/main/java/io/sentry/transport/AsyncConnection.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java rename to sentry/src/main/java/io/sentry/transport/AsyncConnection.java index 5e7b484b9..853f83374 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/AsyncConnection.java +++ b/sentry/src/main/java/io/sentry/transport/AsyncConnection.java @@ -1,17 +1,17 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.ILogger; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryEnvelopeItem; -import io.sentry.core.SentryLevel; -import io.sentry.core.SentryOptions; -import io.sentry.core.cache.IEnvelopeCache; -import io.sentry.core.hints.Cached; -import io.sentry.core.hints.DiskFlushNotification; -import io.sentry.core.hints.Retryable; -import io.sentry.core.hints.SubmissionResult; -import io.sentry.core.util.LogUtils; -import io.sentry.core.util.Objects; +import io.sentry.ILogger; +import io.sentry.SentryEnvelope; +import io.sentry.SentryEnvelopeItem; +import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.cache.IEnvelopeCache; +import io.sentry.hints.Cached; +import io.sentry.hints.DiskFlushNotification; +import io.sentry.hints.Retryable; +import io.sentry.hints.SubmissionResult; +import io.sentry.util.LogUtils; +import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/Connection.java b/sentry/src/main/java/io/sentry/transport/Connection.java similarity index 81% rename from sentry-core/src/main/java/io/sentry/core/transport/Connection.java rename to sentry/src/main/java/io/sentry/transport/Connection.java index d925c1b4c..9aa8a39db 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/Connection.java +++ b/sentry/src/main/java/io/sentry/transport/Connection.java @@ -1,6 +1,6 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.SentryEnvelope; +import io.sentry.SentryEnvelope; import java.io.IOException; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/CurrentDateProvider.java b/sentry/src/main/java/io/sentry/transport/CurrentDateProvider.java similarity index 92% rename from sentry-core/src/main/java/io/sentry/core/transport/CurrentDateProvider.java rename to sentry/src/main/java/io/sentry/transport/CurrentDateProvider.java index 289b6e048..9421baac5 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/CurrentDateProvider.java +++ b/sentry/src/main/java/io/sentry/transport/CurrentDateProvider.java @@ -1,4 +1,4 @@ -package io.sentry.core.transport; +package io.sentry.transport; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java b/sentry/src/main/java/io/sentry/transport/HttpTransport.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java rename to sentry/src/main/java/io/sentry/transport/HttpTransport.java index bc0c257f8..e8b0b410c 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/HttpTransport.java +++ b/sentry/src/main/java/io/sentry/transport/HttpTransport.java @@ -1,17 +1,17 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import static io.sentry.core.SentryLevel.DEBUG; -import static io.sentry.core.SentryLevel.ERROR; -import static io.sentry.core.SentryLevel.INFO; +import static io.sentry.SentryLevel.DEBUG; +import static io.sentry.SentryLevel.ERROR; +import static io.sentry.SentryLevel.INFO; import static java.net.HttpURLConnection.HTTP_OK; import com.jakewharton.nopen.annotation.Open; -import io.sentry.core.ILogger; -import io.sentry.core.ISerializer; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.SentryOptions; -import io.sentry.core.util.Objects; -import io.sentry.core.util.StringUtils; +import io.sentry.ILogger; +import io.sentry.ISerializer; +import io.sentry.SentryEnvelope; +import io.sentry.SentryOptions; +import io.sentry.util.Objects; +import io.sentry.util.StringUtils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -88,8 +88,8 @@ public String getCategory() { /** * Constructs a new HTTP transport instance. Notably, the provided {@code requestUpdater} must set - * the appropriate content encoding header for the {@link io.sentry.core.ISerializer} instance - * obtained from the options. + * the appropriate content encoding header for the {@link io.sentry.ISerializer} instance obtained + * from the options. * * @param options sentry options to read the config from * @param connectionConfigurator this consumer is given a chance to set up the request before it diff --git a/sentry-core/src/main/java/io/sentry/core/transport/IConnectionConfigurator.java b/sentry/src/main/java/io/sentry/transport/IConnectionConfigurator.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/transport/IConnectionConfigurator.java rename to sentry/src/main/java/io/sentry/transport/IConnectionConfigurator.java index a067095ed..11337926b 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/IConnectionConfigurator.java +++ b/sentry/src/main/java/io/sentry/transport/IConnectionConfigurator.java @@ -1,4 +1,4 @@ -package io.sentry.core.transport; +package io.sentry.transport; import java.net.HttpURLConnection; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/ICurrentDateProvider.java b/sentry/src/main/java/io/sentry/transport/ICurrentDateProvider.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/transport/ICurrentDateProvider.java rename to sentry/src/main/java/io/sentry/transport/ICurrentDateProvider.java index a4f681002..b4f86cf2d 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/ICurrentDateProvider.java +++ b/sentry/src/main/java/io/sentry/transport/ICurrentDateProvider.java @@ -1,4 +1,4 @@ -package io.sentry.core.transport; +package io.sentry.transport; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java b/sentry/src/main/java/io/sentry/transport/ITransport.java similarity index 79% rename from sentry-core/src/main/java/io/sentry/core/transport/ITransport.java rename to sentry/src/main/java/io/sentry/transport/ITransport.java index c0b165285..6ce301b5f 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/ITransport.java +++ b/sentry/src/main/java/io/sentry/transport/ITransport.java @@ -1,6 +1,6 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.SentryEnvelope; +import io.sentry.SentryEnvelope; import java.io.Closeable; import java.io.IOException; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/ITransportGate.java b/sentry/src/main/java/io/sentry/transport/ITransportGate.java similarity index 94% rename from sentry-core/src/main/java/io/sentry/core/transport/ITransportGate.java rename to sentry/src/main/java/io/sentry/transport/ITransportGate.java index 2493a8969..2a26658c9 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/ITransportGate.java +++ b/sentry/src/main/java/io/sentry/transport/ITransportGate.java @@ -1,4 +1,4 @@ -package io.sentry.core.transport; +package io.sentry.transport; /** * Implementations of this interface serve as gatekeepers that allow or disallow sending of the diff --git a/sentry-core/src/main/java/io/sentry/core/transport/NoOpEnvelopeCache.java b/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java similarity index 84% rename from sentry-core/src/main/java/io/sentry/core/transport/NoOpEnvelopeCache.java rename to sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java index 82b63959c..712623b17 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/NoOpEnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java @@ -1,7 +1,7 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.cache.IEnvelopeCache; +import io.sentry.SentryEnvelope; +import io.sentry.cache.IEnvelopeCache; import java.util.ArrayList; import java.util.Iterator; import org.jetbrains.annotations.NotNull; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java b/sentry/src/main/java/io/sentry/transport/NoOpTransport.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java rename to sentry/src/main/java/io/sentry/transport/NoOpTransport.java index f3e856c6c..194ef1535 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransport.java +++ b/sentry/src/main/java/io/sentry/transport/NoOpTransport.java @@ -1,6 +1,6 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.SentryEnvelope; +import io.sentry.SentryEnvelope; import java.io.IOException; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransportGate.java b/sentry/src/main/java/io/sentry/transport/NoOpTransportGate.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/transport/NoOpTransportGate.java rename to sentry/src/main/java/io/sentry/transport/NoOpTransportGate.java index e9992d275..6b14f5ae3 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/NoOpTransportGate.java +++ b/sentry/src/main/java/io/sentry/transport/NoOpTransportGate.java @@ -1,4 +1,4 @@ -package io.sentry.core.transport; +package io.sentry.transport; public final class NoOpTransportGate implements ITransportGate { diff --git a/sentry-core/src/main/java/io/sentry/core/transport/QueuedThreadPoolExecutor.java b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/transport/QueuedThreadPoolExecutor.java rename to sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java index 9ed64167a..dda6a985c 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/QueuedThreadPoolExecutor.java +++ b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java @@ -1,7 +1,7 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import java.util.concurrent.CancellationException; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java b/sentry/src/main/java/io/sentry/transport/StdoutTransport.java similarity index 89% rename from sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java rename to sentry/src/main/java/io/sentry/transport/StdoutTransport.java index f5b9c1929..058db0719 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/StdoutTransport.java +++ b/sentry/src/main/java/io/sentry/transport/StdoutTransport.java @@ -1,8 +1,8 @@ -package io.sentry.core.transport; +package io.sentry.transport; -import io.sentry.core.ISerializer; -import io.sentry.core.SentryEnvelope; -import io.sentry.core.util.Objects; +import io.sentry.ISerializer; +import io.sentry.SentryEnvelope; +import io.sentry.util.Objects; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; diff --git a/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java b/sentry/src/main/java/io/sentry/transport/TransportResult.java similarity index 93% rename from sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java rename to sentry/src/main/java/io/sentry/transport/TransportResult.java index 845eb38b4..301296f00 100644 --- a/sentry-core/src/main/java/io/sentry/core/transport/TransportResult.java +++ b/sentry/src/main/java/io/sentry/transport/TransportResult.java @@ -1,9 +1,9 @@ -package io.sentry.core.transport; +package io.sentry.transport; import org.jetbrains.annotations.NotNull; /** - * A result of {@link ITransport#send(io.sentry.core.SentryEnvelope)}. Note that this class is + * A result of {@link ITransport#send(io.sentry.SentryEnvelope)}. Note that this class is * intentionally not subclassable and has only two factory methods to capture the 2 possible states * - success or error. */ diff --git a/sentry-core/src/main/java/io/sentry/core/util/ApplyScopeUtils.java b/sentry/src/main/java/io/sentry/util/ApplyScopeUtils.java similarity index 85% rename from sentry-core/src/main/java/io/sentry/core/util/ApplyScopeUtils.java rename to sentry/src/main/java/io/sentry/util/ApplyScopeUtils.java index 002a6c124..420540ae0 100644 --- a/sentry-core/src/main/java/io/sentry/core/util/ApplyScopeUtils.java +++ b/sentry/src/main/java/io/sentry/util/ApplyScopeUtils.java @@ -1,7 +1,7 @@ -package io.sentry.core.util; +package io.sentry.util; -import io.sentry.core.hints.ApplyScopeData; -import io.sentry.core.hints.Cached; +import io.sentry.hints.ApplyScopeData; +import io.sentry.hints.Cached; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/util/CollectionUtils.java b/sentry/src/main/java/io/sentry/util/CollectionUtils.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/util/CollectionUtils.java rename to sentry/src/main/java/io/sentry/util/CollectionUtils.java index 9fc6b95a5..b4f29dc6c 100644 --- a/sentry-core/src/main/java/io/sentry/core/util/CollectionUtils.java +++ b/sentry/src/main/java/io/sentry/util/CollectionUtils.java @@ -1,4 +1,4 @@ -package io.sentry.core.util; +package io.sentry.util; import java.util.Collection; import java.util.Map; diff --git a/sentry-core/src/main/java/io/sentry/core/util/LogUtils.java b/sentry/src/main/java/io/sentry/util/LogUtils.java similarity index 87% rename from sentry-core/src/main/java/io/sentry/core/util/LogUtils.java rename to sentry/src/main/java/io/sentry/util/LogUtils.java index 717802e7b..6e5ba9a61 100644 --- a/sentry-core/src/main/java/io/sentry/core/util/LogUtils.java +++ b/sentry/src/main/java/io/sentry/util/LogUtils.java @@ -1,7 +1,7 @@ -package io.sentry.core.util; +package io.sentry.util; -import io.sentry.core.ILogger; -import io.sentry.core.SentryLevel; +import io.sentry.ILogger; +import io.sentry.SentryLevel; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/sentry-core/src/main/java/io/sentry/core/util/Objects.java b/sentry/src/main/java/io/sentry/util/Objects.java similarity index 90% rename from sentry-core/src/main/java/io/sentry/core/util/Objects.java rename to sentry/src/main/java/io/sentry/util/Objects.java index aed1623cc..f39fa2c58 100644 --- a/sentry-core/src/main/java/io/sentry/core/util/Objects.java +++ b/sentry/src/main/java/io/sentry/util/Objects.java @@ -1,4 +1,4 @@ -package io.sentry.core.util; +package io.sentry.util; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/main/java/io/sentry/core/util/StringUtils.java b/sentry/src/main/java/io/sentry/util/StringUtils.java similarity index 97% rename from sentry-core/src/main/java/io/sentry/core/util/StringUtils.java rename to sentry/src/main/java/io/sentry/util/StringUtils.java index 652f3cb03..05b938baf 100644 --- a/sentry-core/src/main/java/io/sentry/core/util/StringUtils.java +++ b/sentry/src/main/java/io/sentry/util/StringUtils.java @@ -1,4 +1,4 @@ -package io.sentry.core.util; +package io.sentry.util; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt b/sentry/src/test/java/io/sentry/BreadcrumbTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt rename to sentry/src/test/java/io/sentry/BreadcrumbTest.kt index f7a2a9258..a1971bb72 100644 --- a/sentry-core/src/test/java/io/sentry/core/BreadcrumbTest.kt +++ b/sentry/src/test/java/io/sentry/BreadcrumbTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry/src/test/java/io/sentry/CachedEvent.kt b/sentry/src/test/java/io/sentry/CachedEvent.kt new file mode 100644 index 000000000..5afdbe5d6 --- /dev/null +++ b/sentry/src/test/java/io/sentry/CachedEvent.kt @@ -0,0 +1,5 @@ +package io.sentry + +import io.sentry.hints.Cached + +class CachedEvent : Cached diff --git a/sentry-core/src/test/java/io/sentry/core/CustomEventProcessor.kt b/sentry/src/test/java/io/sentry/CustomEventProcessor.kt similarity index 84% rename from sentry-core/src/test/java/io/sentry/core/CustomEventProcessor.kt rename to sentry/src/test/java/io/sentry/CustomEventProcessor.kt index 57dbf2acb..5845c6286 100644 --- a/sentry-core/src/test/java/io/sentry/core/CustomEventProcessor.kt +++ b/sentry/src/test/java/io/sentry/CustomEventProcessor.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry class CustomEventProcessor : EventProcessor { override fun process(event: SentryEvent, hint: Any?): SentryEvent? = null diff --git a/sentry-core/src/test/java/io/sentry/core/DateUtilsTest.kt b/sentry/src/test/java/io/sentry/DateUtilsTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/DateUtilsTest.kt rename to sentry/src/test/java/io/sentry/DateUtilsTest.kt index a4694e9ff..eeedb7e57 100644 --- a/sentry-core/src/test/java/io/sentry/core/DateUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/DateUtilsTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt b/sentry/src/test/java/io/sentry/DiagnosticLoggerTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt rename to sentry/src/test/java/io/sentry/DiagnosticLoggerTest.kt index 110a5e23d..c8af2a636 100644 --- a/sentry-core/src/test/java/io/sentry/core/DiagnosticLoggerTest.kt +++ b/sentry/src/test/java/io/sentry/DiagnosticLoggerTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt b/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt rename to sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt index 153b948a9..2c130de02 100644 --- a/sentry-core/src/test/java/io/sentry/core/DirectoryProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argWhere @@ -6,9 +6,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.hints.ApplyScopeData -import io.sentry.core.protocol.User -import io.sentry.core.util.noFlushTimeout +import io.sentry.hints.ApplyScopeData +import io.sentry.protocol.User +import io.sentry.util.noFlushTimeout import java.io.File import java.nio.file.Files import java.nio.file.Paths diff --git a/sentry-core/src/test/java/io/sentry/core/DsnTest.kt b/sentry/src/test/java/io/sentry/DsnTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/DsnTest.kt rename to sentry/src/test/java/io/sentry/DsnTest.kt index bdc2ebe6c..0d1e9c314 100644 --- a/sentry-core/src/test/java/io/sentry/core/DsnTest.kt +++ b/sentry/src/test/java/io/sentry/DsnTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt b/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt similarity index 94% rename from sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt rename to sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt index 3867fd5f5..b2e7ec0ef 100644 --- a/sentry-core/src/test/java/io/sentry/core/DuplicateEventDetectionEventProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt @@ -1,7 +1,7 @@ -package io.sentry.core +package io.sentry -import io.sentry.core.exception.ExceptionMechanismException -import io.sentry.core.protocol.Mechanism +import io.sentry.exception.ExceptionMechanismException +import io.sentry.protocol.Mechanism import java.lang.RuntimeException import kotlin.test.Test import kotlin.test.assertNotNull diff --git a/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt b/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt rename to sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt index 6ae37997f..595a2cf98 100644 --- a/sentry-core/src/test/java/io/sentry/core/EnvelopeSenderTest.kt +++ b/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.doThrow @@ -7,9 +7,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.cache.EnvelopeCache -import io.sentry.core.hints.Retryable -import io.sentry.core.util.noFlushTimeout +import io.sentry.cache.EnvelopeCache +import io.sentry.hints.Retryable +import io.sentry.util.noFlushTimeout import java.io.File import java.nio.file.Files import java.nio.file.Path diff --git a/sentry-core/src/test/java/io/sentry/core/FileFromResources.kt b/sentry/src/test/java/io/sentry/FileFromResources.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/FileFromResources.kt rename to sentry/src/test/java/io/sentry/FileFromResources.kt index 541a31c77..d9c9f78ed 100644 --- a/sentry-core/src/test/java/io/sentry/core/FileFromResources.kt +++ b/sentry/src/test/java/io/sentry/FileFromResources.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import java.io.File import java.util.Scanner diff --git a/sentry-core/src/test/java/io/sentry/core/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/GsonSerializerTest.kt rename to sentry/src/test/java/io/sentry/GsonSerializerTest.kt index bc63a0fdb..150aac161 100644 --- a/sentry-core/src/test/java/io/sentry/core/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -1,13 +1,13 @@ -package io.sentry.core +package io.sentry import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.protocol.Contexts -import io.sentry.core.protocol.Device -import io.sentry.core.protocol.SdkVersion +import io.sentry.protocol.Contexts +import io.sentry.protocol.Device +import io.sentry.protocol.SdkVersion import java.io.ByteArrayInputStream import java.io.IOException import java.io.InputStream diff --git a/sentry-core/src/test/java/io/sentry/core/HttpTransportFactoryTest.kt b/sentry/src/test/java/io/sentry/HttpTransportFactoryTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/HttpTransportFactoryTest.kt rename to sentry/src/test/java/io/sentry/HttpTransportFactoryTest.kt index ab05b1c73..2ac1a30b6 100644 --- a/sentry-core/src/test/java/io/sentry/core/HttpTransportFactoryTest.kt +++ b/sentry/src/test/java/io/sentry/HttpTransportFactoryTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertFailsWith diff --git a/sentry-core/src/test/java/io/sentry/core/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/HubTest.kt rename to sentry/src/test/java/io/sentry/HubTest.kt index 3c6fc1acf..89c6f803d 100644 --- a/sentry-core/src/test/java/io/sentry/core/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.anyOrNull @@ -12,10 +12,10 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.hints.SessionEndHint -import io.sentry.core.hints.SessionStartHint -import io.sentry.core.protocol.SentryId -import io.sentry.core.protocol.User +import io.sentry.hints.SessionEndHint +import io.sentry.hints.SessionStartHint +import io.sentry.protocol.SentryId +import io.sentry.protocol.User import java.io.File import java.nio.file.Files import java.util.Queue diff --git a/sentry-core/src/test/java/io/sentry/core/MainEventProcessorTest.kt b/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/MainEventProcessorTest.kt rename to sentry/src/test/java/io/sentry/MainEventProcessorTest.kt index 2f0cb67ed..50f932dd2 100644 --- a/sentry-core/src/test/java/io/sentry/core/MainEventProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt @@ -1,9 +1,9 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.hints.ApplyScopeData -import io.sentry.core.hints.Cached -import io.sentry.core.protocol.SdkVersion +import io.sentry.hints.ApplyScopeData +import io.sentry.hints.Cached +import io.sentry.protocol.SdkVersion import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/sentry-core/src/test/java/io/sentry/core/NoOpHubTest.kt b/sentry/src/test/java/io/sentry/NoOpHubTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/NoOpHubTest.kt rename to sentry/src/test/java/io/sentry/NoOpHubTest.kt index 5501ce062..3575a6f86 100644 --- a/sentry-core/src/test/java/io/sentry/core/NoOpHubTest.kt +++ b/sentry/src/test/java/io/sentry/NoOpHubTest.kt @@ -1,6 +1,6 @@ -package io.sentry.core +package io.sentry -import io.sentry.core.protocol.SentryId +import io.sentry.protocol.SentryId import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/sentry-core/src/test/java/io/sentry/core/NoOpSentryClientTest.kt b/sentry/src/test/java/io/sentry/NoOpSentryClientTest.kt similarity index 94% rename from sentry-core/src/test/java/io/sentry/core/NoOpSentryClientTest.kt rename to sentry/src/test/java/io/sentry/NoOpSentryClientTest.kt index eca741f62..e3949b80b 100644 --- a/sentry-core/src/test/java/io/sentry/core/NoOpSentryClientTest.kt +++ b/sentry/src/test/java/io/sentry/NoOpSentryClientTest.kt @@ -1,6 +1,6 @@ -package io.sentry.core +package io.sentry -import io.sentry.core.protocol.SentryId +import io.sentry.protocol.SentryId import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/sentry-core/src/test/java/io/sentry/core/NoOpSerializerTest.kt b/sentry/src/test/java/io/sentry/NoOpSerializerTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/NoOpSerializerTest.kt rename to sentry/src/test/java/io/sentry/NoOpSerializerTest.kt index 999349723..d7b4d0368 100644 --- a/sentry-core/src/test/java/io/sentry/core/NoOpSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/NoOpSerializerTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/OptionsContainerTest.kt b/sentry/src/test/java/io/sentry/OptionsContainerTest.kt similarity index 92% rename from sentry-core/src/test/java/io/sentry/core/OptionsContainerTest.kt rename to sentry/src/test/java/io/sentry/OptionsContainerTest.kt index 7f9f7fedf..804f239f5 100644 --- a/sentry-core/src/test/java/io/sentry/core/OptionsContainerTest.kt +++ b/sentry/src/test/java/io/sentry/OptionsContainerTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertTrue diff --git a/sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt b/sentry/src/test/java/io/sentry/OutboxSenderTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt rename to sentry/src/test/java/io/sentry/OutboxSenderTest.kt index 56e91f914..e58fee324 100644 --- a/sentry-core/src/test/java/io/sentry/core/OutboxSenderTest.kt +++ b/sentry/src/test/java/io/sentry/OutboxSenderTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argWhere @@ -7,9 +7,9 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.cache.EnvelopeCache -import io.sentry.core.hints.Retryable -import io.sentry.core.protocol.SentryId +import io.sentry.cache.EnvelopeCache +import io.sentry.hints.Retryable +import io.sentry.protocol.SentryId import java.io.File import java.io.FileNotFoundException import java.nio.file.Files @@ -140,7 +140,7 @@ class OutboxSenderTest { @Test fun `when hub is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.OutboxSender") + val clazz = Class.forName("io.sentry.OutboxSender") val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) val params = arrayOf(null, mock(), mock(), mock(), null) assertFailsWith { ctor.newInstance(params) } @@ -148,7 +148,7 @@ class OutboxSenderTest { @Test fun `when envelopeReader is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.OutboxSender") + val clazz = Class.forName("io.sentry.OutboxSender") val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) val params = arrayOf(mock(), null, mock(), mock(), 15000) assertFailsWith { ctor.newInstance(params) } @@ -156,7 +156,7 @@ class OutboxSenderTest { @Test fun `when serializer is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.OutboxSender") + val clazz = Class.forName("io.sentry.OutboxSender") val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) val params = arrayOf(mock(), mock(), null, mock(), 15000) assertFailsWith { ctor.newInstance(params) } @@ -164,7 +164,7 @@ class OutboxSenderTest { @Test fun `when logger is null, ctor throws`() { - val clazz = Class.forName("io.sentry.core.OutboxSender") + val clazz = Class.forName("io.sentry.OutboxSender") val ctor = clazz.getConstructor(IHub::class.java, IEnvelopeReader::class.java, ISerializer::class.java, ILogger::class.java, Long::class.java) val params = arrayOf(mock(), mock(), mock(), null, 15000) assertFailsWith { ctor.newInstance(params) } diff --git a/sentry-core/src/test/java/io/sentry/core/SampleDsn.kt b/sentry/src/test/java/io/sentry/SampleDsn.kt similarity index 93% rename from sentry-core/src/test/java/io/sentry/core/SampleDsn.kt rename to sentry/src/test/java/io/sentry/SampleDsn.kt index 7bd705df3..0ddabd4b6 100644 --- a/sentry-core/src/test/java/io/sentry/core/SampleDsn.kt +++ b/sentry/src/test/java/io/sentry/SampleDsn.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry // Legacy DSN includes a secret. Sentry 8 and older will require it. const val dsnStringLegacy: String = "https://d4d82fc1c2c4032a83f3a29aa3a3aff:ed0a8589a0bb4d4793ac4c70375f3d65@fake-sentry.io:65535/2147483647" diff --git a/sentry-core/src/test/java/io/sentry/core/ScopeTest.kt b/sentry/src/test/java/io/sentry/ScopeTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/ScopeTest.kt rename to sentry/src/test/java/io/sentry/ScopeTest.kt index ea37ae867..5c7cd39b8 100644 --- a/sentry-core/src/test/java/io/sentry/core/ScopeTest.kt +++ b/sentry/src/test/java/io/sentry/ScopeTest.kt @@ -1,6 +1,6 @@ -package io.sentry.core +package io.sentry -import io.sentry.core.protocol.User +import io.sentry.protocol.User import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt b/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt rename to sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt index fb32a8e08..7aa6ae716 100644 --- a/sentry-core/src/test/java/io/sentry/core/SendCachedEnvelopeFireAndForgetIntegrationTest.kt +++ b/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt b/sentry/src/test/java/io/sentry/SentryClientTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt rename to sentry/src/test/java/io/sentry/SentryClientTest.kt index b050dc592..92e355aaa 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryClientTest.kt +++ b/sentry/src/test/java/io/sentry/SentryClientTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.anyOrNull @@ -10,18 +10,18 @@ import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.hints.ApplyScopeData -import io.sentry.core.hints.Cached -import io.sentry.core.hints.DiskFlushNotification -import io.sentry.core.protocol.Mechanism -import io.sentry.core.protocol.Request -import io.sentry.core.protocol.SdkVersion -import io.sentry.core.protocol.SentryException -import io.sentry.core.protocol.SentryId -import io.sentry.core.protocol.User -import io.sentry.core.transport.AsyncConnection -import io.sentry.core.transport.HttpTransport -import io.sentry.core.transport.ITransportGate +import io.sentry.hints.ApplyScopeData +import io.sentry.hints.Cached +import io.sentry.hints.DiskFlushNotification +import io.sentry.protocol.Mechanism +import io.sentry.protocol.Request +import io.sentry.protocol.SdkVersion +import io.sentry.protocol.SentryException +import io.sentry.protocol.SentryId +import io.sentry.protocol.User +import io.sentry.transport.AsyncConnection +import io.sentry.transport.HttpTransport +import io.sentry.transport.ITransportGate import java.io.ByteArrayInputStream import java.io.IOException import java.io.InputStreamReader diff --git a/sentry-core/src/test/java/io/sentry/core/SentryEnvelopeItemTest.kt b/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt similarity index 92% rename from sentry-core/src/test/java/io/sentry/core/SentryEnvelopeItemTest.kt rename to sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt index cf19266e9..9cc15c9ae 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryEnvelopeItemTest.kt +++ b/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt @@ -1,7 +1,7 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.protocol.User +import io.sentry.protocol.User import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-core/src/test/java/io/sentry/core/SentryEnvelopeTest.kt b/sentry/src/test/java/io/sentry/SentryEnvelopeTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SentryEnvelopeTest.kt rename to sentry/src/test/java/io/sentry/SentryEnvelopeTest.kt index d6582211d..227490dd4 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryEnvelopeTest.kt +++ b/sentry/src/test/java/io/sentry/SentryEnvelopeTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt b/sentry/src/test/java/io/sentry/SentryEventTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt rename to sentry/src/test/java/io/sentry/SentryEventTest.kt index 83fdd355d..76b4afb06 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryEventTest.kt +++ b/sentry/src/test/java/io/sentry/SentryEventTest.kt @@ -1,9 +1,9 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.exception.ExceptionMechanismException -import io.sentry.core.protocol.Mechanism -import io.sentry.core.protocol.SentryId +import io.sentry.exception.ExceptionMechanismException +import io.sentry.protocol.Mechanism +import io.sentry.protocol.SentryId import java.time.Instant import java.time.OffsetDateTime import java.time.format.DateTimeFormatter diff --git a/sentry-core/src/test/java/io/sentry/core/SentryExceptionFactoryTest.kt b/sentry/src/test/java/io/sentry/SentryExceptionFactoryTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/SentryExceptionFactoryTest.kt rename to sentry/src/test/java/io/sentry/SentryExceptionFactoryTest.kt index 471680856..5e77ad01d 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryExceptionFactoryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryExceptionFactoryTest.kt @@ -1,7 +1,7 @@ -package io.sentry.core +package io.sentry -import io.sentry.core.exception.ExceptionMechanismException -import io.sentry.core.protocol.Mechanism +import io.sentry.exception.ExceptionMechanismException +import io.sentry.protocol.Mechanism import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/sentry-core/src/test/java/io/sentry/core/SentryExecutorServiceTest.kt b/sentry/src/test/java/io/sentry/SentryExecutorServiceTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SentryExecutorServiceTest.kt rename to sentry/src/test/java/io/sentry/SentryExecutorServiceTest.kt index a4b9bfffc..fc5845717 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryExecutorServiceTest.kt +++ b/sentry/src/test/java/io/sentry/SentryExecutorServiceTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/SentryItemTypeTest.kt b/sentry/src/test/java/io/sentry/SentryItemTypeTest.kt similarity index 93% rename from sentry-core/src/test/java/io/sentry/core/SentryItemTypeTest.kt rename to sentry/src/test/java/io/sentry/SentryItemTypeTest.kt index af6b47dc6..945c53ebb 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryItemTypeTest.kt +++ b/sentry/src/test/java/io/sentry/SentryItemTypeTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt similarity index 98% rename from sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt rename to sentry/src/test/java/io/sentry/SentryOptionsTest.kt index 89732b673..81d260b29 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryOptionsTest.kt +++ b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import java.io.File import kotlin.test.Test @@ -122,7 +122,7 @@ class SentryOptionsTest { assertEquals(BuildConfig.VERSION_NAME, sdkVersion.version) assertTrue(sdkVersion.packages!!.any { - it.name == "maven:sentry-core" && + it.name == "maven:sentry" && it.version == BuildConfig.VERSION_NAME }) } diff --git a/sentry-core/src/test/java/io/sentry/core/SentryStackTraceFactoryTest.kt b/sentry/src/test/java/io/sentry/SentryStackTraceFactoryTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SentryStackTraceFactoryTest.kt rename to sentry/src/test/java/io/sentry/SentryStackTraceFactoryTest.kt index 7be89bd68..29e48101f 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryStackTraceFactoryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryStackTraceFactoryTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/SentryTest.kt b/sentry/src/test/java/io/sentry/SentryTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SentryTest.kt rename to sentry/src/test/java/io/sentry/SentryTest.kt index 61b579c6f..ca5a83151 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/SentryThreadFactoryTest.kt b/sentry/src/test/java/io/sentry/SentryThreadFactoryTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/SentryThreadFactoryTest.kt rename to sentry/src/test/java/io/sentry/SentryThreadFactoryTest.kt index 1fc98bc49..fecec2b9c 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryThreadFactoryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryThreadFactoryTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/SentryValuesTest.kt b/sentry/src/test/java/io/sentry/SentryValuesTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/SentryValuesTest.kt rename to sentry/src/test/java/io/sentry/SentryValuesTest.kt index 63d7dc517..b8d4eb35a 100644 --- a/sentry-core/src/test/java/io/sentry/core/SentryValuesTest.kt +++ b/sentry/src/test/java/io/sentry/SentryValuesTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/SessionTest.kt b/sentry/src/test/java/io/sentry/SessionTest.kt similarity index 98% rename from sentry-core/src/test/java/io/sentry/core/SessionTest.kt rename to sentry/src/test/java/io/sentry/SessionTest.kt index 8c5d29245..ccae83061 100644 --- a/sentry-core/src/test/java/io/sentry/core/SessionTest.kt +++ b/sentry/src/test/java/io/sentry/SessionTest.kt @@ -1,8 +1,8 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.protocol.User +import io.sentry.protocol.User import java.util.Date import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/ShutdownHookIntegrationTest.kt b/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/ShutdownHookIntegrationTest.kt rename to sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt index 436b05a91..61c0a90bd 100644 --- a/sentry-core/src/test/java/io/sentry/core/ShutdownHookIntegrationTest.kt +++ b/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock diff --git a/sentry-core/src/test/java/io/sentry/core/StringExtensions.kt b/sentry/src/test/java/io/sentry/StringExtensions.kt similarity index 87% rename from sentry-core/src/test/java/io/sentry/core/StringExtensions.kt rename to sentry/src/test/java/io/sentry/StringExtensions.kt index 9543cfea2..e82001814 100644 --- a/sentry-core/src/test/java/io/sentry/core/StringExtensions.kt +++ b/sentry/src/test/java/io/sentry/StringExtensions.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import java.io.ByteArrayInputStream diff --git a/sentry-core/src/test/java/io/sentry/core/UncaughtExceptionHandlerIntegrationTest.kt b/sentry/src/test/java/io/sentry/UncaughtExceptionHandlerIntegrationTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/UncaughtExceptionHandlerIntegrationTest.kt rename to sentry/src/test/java/io/sentry/UncaughtExceptionHandlerIntegrationTest.kt index 7ddc0c0dc..4c5e07c31 100644 --- a/sentry-core/src/test/java/io/sentry/core/UncaughtExceptionHandlerIntegrationTest.kt +++ b/sentry/src/test/java/io/sentry/UncaughtExceptionHandlerIntegrationTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core +package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argWhere @@ -7,9 +7,9 @@ import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyZeroInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.exception.ExceptionMechanismException -import io.sentry.core.protocol.SentryId -import io.sentry.core.util.noFlushTimeout +import io.sentry.exception.ExceptionMechanismException +import io.sentry.protocol.SentryId +import io.sentry.util.noFlushTimeout import java.io.File import java.nio.file.Files import kotlin.test.AfterTest diff --git a/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt b/sentry/src/test/java/io/sentry/cache/CacheStrategyTest.kt similarity index 96% rename from sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt rename to sentry/src/test/java/io/sentry/cache/CacheStrategyTest.kt index 7eeae9f99..c5692f9b7 100644 --- a/sentry-core/src/test/java/io/sentry/core/cache/CacheStrategyTest.kt +++ b/sentry/src/test/java/io/sentry/cache/CacheStrategyTest.kt @@ -1,11 +1,11 @@ -package io.sentry.core.cache +package io.sentry.cache import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.DateUtils -import io.sentry.core.GsonSerializer -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryOptions -import io.sentry.core.Session +import io.sentry.DateUtils +import io.sentry.GsonSerializer +import io.sentry.SentryEnvelope +import io.sentry.SentryOptions +import io.sentry.Session import java.io.ByteArrayInputStream import java.io.File import java.io.InputStreamReader diff --git a/sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt similarity index 92% rename from sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt rename to sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt index fdfc1cf86..c7b4ac1e8 100644 --- a/sentry-core/src/test/java/io/sentry/core/cache/EnvelopeCacheTest.kt +++ b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt @@ -1,21 +1,21 @@ -package io.sentry.core.cache +package io.sentry.cache import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.ILogger -import io.sentry.core.ISerializer -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryLevel -import io.sentry.core.SentryOptions -import io.sentry.core.Session -import io.sentry.core.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE -import io.sentry.core.cache.EnvelopeCache.SUFFIX_CURRENT_SESSION_FILE -import io.sentry.core.hints.SessionEndHint -import io.sentry.core.hints.SessionStartHint -import io.sentry.core.protocol.User +import io.sentry.ILogger +import io.sentry.ISerializer +import io.sentry.SentryEnvelope +import io.sentry.SentryLevel +import io.sentry.SentryOptions +import io.sentry.Session +import io.sentry.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE +import io.sentry.cache.EnvelopeCache.SUFFIX_CURRENT_SESSION_FILE +import io.sentry.hints.SessionEndHint +import io.sentry.hints.SessionStartHint +import io.sentry.protocol.User import java.io.File import java.nio.file.Files import java.nio.file.Path diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/AppTest.kt b/sentry/src/test/java/io/sentry/protocol/AppTest.kt similarity index 98% rename from sentry-core/src/test/java/io/sentry/core/protocol/AppTest.kt rename to sentry/src/test/java/io/sentry/protocol/AppTest.kt index 30c53e5fe..0fb672764 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/AppTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/AppTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import java.util.Date import kotlin.test.Test diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/BrowserTest.kt b/sentry/src/test/java/io/sentry/protocol/BrowserTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/protocol/BrowserTest.kt rename to sentry/src/test/java/io/sentry/protocol/BrowserTest.kt index 2c322e062..feabd36e0 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/BrowserTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/BrowserTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/ContextsTest.kt b/sentry/src/test/java/io/sentry/protocol/ContextsTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/protocol/ContextsTest.kt rename to sentry/src/test/java/io/sentry/protocol/ContextsTest.kt index 2fe525cbc..f265a5467 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/ContextsTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/ContextsTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/DeviceTest.kt b/sentry/src/test/java/io/sentry/protocol/DeviceTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/protocol/DeviceTest.kt rename to sentry/src/test/java/io/sentry/protocol/DeviceTest.kt index bc354be1e..028b9b946 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/DeviceTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/DeviceTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import java.util.Date import java.util.TimeZone diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/GpuTest.kt b/sentry/src/test/java/io/sentry/protocol/GpuTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/protocol/GpuTest.kt rename to sentry/src/test/java/io/sentry/protocol/GpuTest.kt index 91088b465..9614111cc 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/GpuTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/GpuTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/OperatingSystemTest.kt b/sentry/src/test/java/io/sentry/protocol/OperatingSystemTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/protocol/OperatingSystemTest.kt rename to sentry/src/test/java/io/sentry/protocol/OperatingSystemTest.kt index 7ea8606b2..a59b3f43c 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/OperatingSystemTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/OperatingSystemTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/SentryRuntimeTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryRuntimeTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/protocol/SentryRuntimeTest.kt rename to sentry/src/test/java/io/sentry/protocol/SentryRuntimeTest.kt index 2b07f7e83..2389fc843 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/SentryRuntimeTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryRuntimeTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/protocol/UserTest.kt b/sentry/src/test/java/io/sentry/protocol/UserTest.kt similarity index 98% rename from sentry-core/src/test/java/io/sentry/core/protocol/UserTest.kt rename to sentry/src/test/java/io/sentry/protocol/UserTest.kt index 1fd1e8f34..5c52f57b7 100644 --- a/sentry-core/src/test/java/io/sentry/core/protocol/UserTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/UserTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.protocol +package io.sentry.protocol import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt b/sentry/src/test/java/io/sentry/transport/AsyncConnectionTest.kt similarity index 95% rename from sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt rename to sentry/src/test/java/io/sentry/transport/AsyncConnectionTest.kt index 0e54785eb..9198dbc48 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/AsyncConnectionTest.kt +++ b/sentry/src/test/java/io/sentry/transport/AsyncConnectionTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.transport +package io.sentry.transport import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.anyOrNull @@ -9,16 +9,16 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.CachedEvent -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryEnvelopeHeader -import io.sentry.core.SentryEnvelopeItem -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions -import io.sentry.core.Session -import io.sentry.core.cache.IEnvelopeCache -import io.sentry.core.dsnString -import io.sentry.core.protocol.User +import io.sentry.CachedEvent +import io.sentry.SentryEnvelope +import io.sentry.SentryEnvelopeHeader +import io.sentry.SentryEnvelopeItem +import io.sentry.SentryEvent +import io.sentry.SentryOptions +import io.sentry.Session +import io.sentry.cache.IEnvelopeCache +import io.sentry.dsnString +import io.sentry.protocol.User import java.io.IOException import java.util.concurrent.ExecutorService import kotlin.test.Test diff --git a/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt b/sentry/src/test/java/io/sentry/transport/HttpTransportTest.kt similarity index 97% rename from sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt rename to sentry/src/test/java/io/sentry/transport/HttpTransportTest.kt index 2235747db..b7b82b6d3 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/HttpTransportTest.kt +++ b/sentry/src/test/java/io/sentry/transport/HttpTransportTest.kt @@ -1,16 +1,16 @@ -package io.sentry.core.transport +package io.sentry.transport import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.core.ISerializer -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryEvent -import io.sentry.core.SentryOptions -import io.sentry.core.Session -import io.sentry.core.protocol.User +import io.sentry.ISerializer +import io.sentry.SentryEnvelope +import io.sentry.SentryEvent +import io.sentry.SentryOptions +import io.sentry.Session +import io.sentry.protocol.User import java.io.IOException import java.net.HttpURLConnection import java.net.Proxy diff --git a/sentry-core/src/test/java/io/sentry/core/transport/QueuedThreadPoolExecutorTest.kt b/sentry/src/test/java/io/sentry/transport/QueuedThreadPoolExecutorTest.kt similarity index 99% rename from sentry-core/src/test/java/io/sentry/core/transport/QueuedThreadPoolExecutorTest.kt rename to sentry/src/test/java/io/sentry/transport/QueuedThreadPoolExecutorTest.kt index f60612287..db8a85012 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/QueuedThreadPoolExecutorTest.kt +++ b/sentry/src/test/java/io/sentry/transport/QueuedThreadPoolExecutorTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.transport +package io.sentry.transport import com.nhaarman.mockitokotlin2.mock import java.util.concurrent.CountDownLatch diff --git a/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt b/sentry/src/test/java/io/sentry/transport/StdoutTransportTest.kt similarity index 85% rename from sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt rename to sentry/src/test/java/io/sentry/transport/StdoutTransportTest.kt index 5b742a14b..6fa4e1dcd 100644 --- a/sentry-core/src/test/java/io/sentry/core/transport/StdoutTransportTest.kt +++ b/sentry/src/test/java/io/sentry/transport/StdoutTransportTest.kt @@ -1,12 +1,12 @@ -package io.sentry.core.transport +package io.sentry.transport import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify -import io.sentry.core.ISerializer -import io.sentry.core.SentryEnvelope -import io.sentry.core.SentryEvent +import io.sentry.ISerializer +import io.sentry.SentryEnvelope +import io.sentry.SentryEvent import kotlin.test.Test import kotlin.test.assertTrue diff --git a/sentry-core/src/test/java/io/sentry/core/util/ApplyScopeUtilsTest.kt b/sentry/src/test/java/io/sentry/util/ApplyScopeUtilsTest.kt similarity index 88% rename from sentry-core/src/test/java/io/sentry/core/util/ApplyScopeUtilsTest.kt rename to sentry/src/test/java/io/sentry/util/ApplyScopeUtilsTest.kt index 1d5fd136d..7b7a774d8 100644 --- a/sentry-core/src/test/java/io/sentry/core/util/ApplyScopeUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/util/ApplyScopeUtilsTest.kt @@ -1,8 +1,8 @@ -package io.sentry.core.util +package io.sentry.util import com.nhaarman.mockitokotlin2.mock -import io.sentry.core.hints.ApplyScopeData -import io.sentry.core.hints.Cached +import io.sentry.hints.ApplyScopeData +import io.sentry.hints.Cached import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/sentry-core/src/test/java/io/sentry/core/util/Extensions.kt b/sentry/src/test/java/io/sentry/util/Extensions.kt similarity index 64% rename from sentry-core/src/test/java/io/sentry/core/util/Extensions.kt rename to sentry/src/test/java/io/sentry/util/Extensions.kt index b4391c4d8..c62b670dc 100644 --- a/sentry-core/src/test/java/io/sentry/core/util/Extensions.kt +++ b/sentry/src/test/java/io/sentry/util/Extensions.kt @@ -1,6 +1,6 @@ -package io.sentry.core.util +package io.sentry.util -import io.sentry.core.SentryOptions +import io.sentry.SentryOptions fun SentryOptions.noFlushTimeout(): SentryOptions { return this.apply { diff --git a/sentry-core/src/test/java/io/sentry/core/util/StringUtilsTest.kt b/sentry/src/test/java/io/sentry/util/StringUtilsTest.kt similarity index 98% rename from sentry-core/src/test/java/io/sentry/core/util/StringUtilsTest.kt rename to sentry/src/test/java/io/sentry/util/StringUtilsTest.kt index 553b443f0..7127a9536 100644 --- a/sentry-core/src/test/java/io/sentry/core/util/StringUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/util/StringUtilsTest.kt @@ -1,4 +1,4 @@ -package io.sentry.core.util +package io.sentry.util import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-core/src/test/resources/envelope-event-attachment.txt b/sentry/src/test/resources/envelope-event-attachment.txt similarity index 100% rename from sentry-core/src/test/resources/envelope-event-attachment.txt rename to sentry/src/test/resources/envelope-event-attachment.txt diff --git a/sentry-core/src/test/resources/envelope-session-start.txt b/sentry/src/test/resources/envelope-session-start.txt similarity index 100% rename from sentry-core/src/test/resources/envelope-session-start.txt rename to sentry/src/test/resources/envelope-session-start.txt diff --git a/sentry-core/src/test/resources/envelope_session.txt b/sentry/src/test/resources/envelope_session.txt similarity index 100% rename from sentry-core/src/test/resources/envelope_session.txt rename to sentry/src/test/resources/envelope_session.txt diff --git a/sentry-core/src/test/resources/envelope_session_sdkversion.txt b/sentry/src/test/resources/envelope_session_sdkversion.txt similarity index 100% rename from sentry-core/src/test/resources/envelope_session_sdkversion.txt rename to sentry/src/test/resources/envelope_session_sdkversion.txt diff --git a/sentry-core/src/test/resources/event.json b/sentry/src/test/resources/event.json similarity index 100% rename from sentry-core/src/test/resources/event.json rename to sentry/src/test/resources/event.json diff --git a/sentry-core/src/test/resources/event_breadcrumb_data.json b/sentry/src/test/resources/event_breadcrumb_data.json similarity index 100% rename from sentry-core/src/test/resources/event_breadcrumb_data.json rename to sentry/src/test/resources/event_breadcrumb_data.json diff --git a/sentry-core/src/test/resources/event_with_contexts.json b/sentry/src/test/resources/event_with_contexts.json similarity index 100% rename from sentry-core/src/test/resources/event_with_contexts.json rename to sentry/src/test/resources/event_with_contexts.json diff --git a/sentry-core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sentry/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker similarity index 100% rename from sentry-core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker rename to sentry/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/sentry-core/src/test/resources/session.json b/sentry/src/test/resources/session.json similarity index 100% rename from sentry-core/src/test/resources/session.json rename to sentry/src/test/resources/session.json diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a0c91aa6..4b56a066c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,10 +1,10 @@ -rootProject.name = "sentry" +rootProject.name = "sentry-root" rootProject.buildFileName = "build.gradle.kts" include("sentry-android", "sentry-android-ndk", "sentry-android-core", - "sentry-core", + "sentry", "sentry-test-support", "sentry-log4j2", "sentry-logback",