diff --git a/CHANGELOG.md b/CHANGELOG.md index f70ce5c1d5..e7d7d1fbd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - Allow setting native Android SDK name during build ([#2035](https://github.com/getsentry/sentry-java/pull/2035)) - Include application permissions in Android events ([#2018](https://github.com/getsentry/sentry-java/pull/2018)) - Automatically create transactions for UI events ([#1975](https://github.com/getsentry/sentry-java/pull/1975)) +- Hints are now used via a Hint object and passed into beforeSend and EventProcessor as @NotNull Hint object ([#2045](https://github.com/getsentry/sentry-java/pull/2045)) +- Attachments can be manipulated via hint ([#2046](https://github.com/getsentry/sentry-java/pull/2046)) ### Fixes @@ -1660,4 +1662,4 @@ Features from the current SDK like `ANR` are also available (by default triggere Packages were released on [`bintray`](https://dl.bintray.com/getsentry/sentry-android/io/sentry/), [`jcenter`](https://jcenter.bintray.com/io/sentry/sentry-android/) We'd love to get feedback and we'll work in getting the GA `2.0.0` out soon. -Until then, the [stable SDK offered by Sentry is at version 1.7.28](https://github.com/getsentry/sentry-java/releases/tag/v1.7.28) \ No newline at end of file +Until then, the [stable SDK offered by Sentry is at version 1.7.28](https://github.com/getsentry/sentry-java/releases/tag/v1.7.28) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index 6ac762a9a1..60279e1e6d 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -110,7 +110,7 @@ public final class io/sentry/android/core/ScreenshotEventProcessor : android/app public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V public fun onActivityStarted (Landroid/app/Activity;)V public fun onActivityStopped (Landroid/app/Activity;)V - public fun process (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; + public fun process (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; } public final class io/sentry/android/core/SentryAndroid { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java index fbfa173c7e..1e183e5a96 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java @@ -19,11 +19,11 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.SpanStatus; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -126,10 +126,10 @@ private void addBreadcrumb(final @NotNull Activity activity, final @NotNull Stri breadcrumb.setCategory("ui.lifecycle"); breadcrumb.setLevel(SentryLevel.INFO); - final Map hintMap = new HashMap<>(); - hintMap.put(ANDROID_ACTIVITY, activity); + final Hint hint = new Hint(); + hint.set(ANDROID_ACTIVITY, activity); - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } 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 9536ef4b26..5c1b186b4e 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 @@ -11,13 +11,12 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.android.core.internal.util.DeviceOrientations; +import io.sentry.hints.Hint; import io.sentry.protocol.Device; import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,10 +99,10 @@ public void onConfigurationChanged(@NotNull Configuration newConfig) { breadcrumb.setData("position", orientation); breadcrumb.setLevel(SentryLevel.INFO); - final Map hintMap = new HashMap<>(); - hintMap.put(ANDROID_CONFIGURATION, newConfig); + final Hint hint = new Hint(); + hint.set(ANDROID_CONFIGURATION, newConfig); - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } 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 48741231d5..c20fe06a4f 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 @@ -30,6 +30,7 @@ import io.sentry.android.core.internal.util.DeviceOrientations; import io.sentry.android.core.internal.util.MainThreadChecker; import io.sentry.android.core.internal.util.RootChecker; +import io.sentry.hints.Hint; import io.sentry.protocol.App; import io.sentry.protocol.Device; import io.sentry.protocol.OperatingSystem; @@ -118,8 +119,7 @@ public DefaultAndroidEventProcessor( } @Override - public @NotNull SentryEvent process( - final @NotNull SentryEvent event, final @Nullable Map hint) { + public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(event, hint); if (applyScopeData) { // we only set memory data if it's not a hard crash, when it's a hard crash the event is @@ -145,7 +145,7 @@ private void setCommons( } private boolean shouldApplyScopeData( - final @NotNull SentryBaseEvent event, final @Nullable Map hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { if (HintUtils.shouldApplyScopeData(hint)) { return true; } else { @@ -885,7 +885,7 @@ private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { @Override public @NotNull SentryTransaction process( - final @NotNull SentryTransaction transaction, final @Nullable Map hint) { + final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(transaction, hint); if (applyScopeData) { 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 57cadbcdd5..2723b798db 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,7 +1,6 @@ package io.sentry.android.core; import static io.sentry.SentryLevel.ERROR; -import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; import android.os.FileObserver; import io.sentry.IEnvelopeSender; @@ -10,13 +9,13 @@ import io.sentry.hints.ApplyScopeData; import io.sentry.hints.Cached; import io.sentry.hints.Flushable; +import io.sentry.hints.Hint; import io.sentry.hints.Resettable; import io.sentry.hints.Retryable; import io.sentry.hints.SubmissionResult; +import io.sentry.util.HintUtils; import io.sentry.util.Objects; import java.io.File; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; @@ -58,12 +57,11 @@ public void onEvent(int eventType, @Nullable String relativePath) { // TODO: Only some event types should be pass through? - final CachedEnvelopeHint hint = new CachedEnvelopeHint(flushTimeoutMillis, logger); + final CachedEnvelopeHint cachedHint = new CachedEnvelopeHint(flushTimeoutMillis, logger); - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, hint); + final Hint hint = HintUtils.createWithTypeCheckHint(cachedHint); - envelopeSender.processEnvelopeFile(this.rootPath + File.separator + relativePath, hintMap); + envelopeSender.processEnvelopeFile(this.rootPath + File.separator + relativePath, hint); } private static final class CachedEnvelopeHint diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/PerformanceAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/PerformanceAndroidEventProcessor.java index 708d5ecd93..ae2dffc3b0 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/PerformanceAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/PerformanceAndroidEventProcessor.java @@ -7,6 +7,7 @@ import io.sentry.EventProcessor; import io.sentry.SentryEvent; import io.sentry.SpanContext; +import io.sentry.hints.Hint; import io.sentry.protocol.MeasurementValue; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentrySpan; @@ -42,7 +43,7 @@ final class PerformanceAndroidEventProcessor implements EventProcessor { */ @Override @Nullable - public SentryEvent process(@NotNull SentryEvent event, @Nullable Map hint) { + public SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { // that's only necessary because on newer versions of Unity, if not overriding this method, it's // throwing 'java.lang.AbstractMethodError: abstract method' and the reason is probably // compilation mismatch. @@ -52,7 +53,7 @@ public SentryEvent process(@NotNull SentryEvent event, @Nullable Map hint) { + @NotNull SentryTransaction transaction, @NotNull Hint hint) { if (!options.isTracingEnabled()) { return transaction; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index e738e40060..0583235a4a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -1,7 +1,6 @@ package io.sentry.android.core; import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY; -import static io.sentry.TypeCheckHint.SENTRY_SCREENSHOT; import android.annotation.SuppressLint; import android.app.Activity; @@ -17,13 +16,12 @@ import io.sentry.EventProcessor; import io.sentry.SentryEvent; import io.sentry.SentryLevel; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -68,8 +66,7 @@ public ScreenshotEventProcessor( @SuppressWarnings("NullAway") @Override - public @NotNull SentryEvent process( - final @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { if (options.isAttachScreenshot() && event.isErrored() && currentActivity != null) { final Activity activity = currentActivity.get(); if (isActivityValid(activity) @@ -93,16 +90,10 @@ public ScreenshotEventProcessor( // Some formats, like PNG which is lossless, will ignore the quality setting. bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); - if (hint == null) { - hint = new HashMap<>(); - } - if (byteArrayOutputStream.size() > 0) { // screenshot png is around ~100-150 kb - hint.put( - SENTRY_SCREENSHOT, - Attachment.fromScreenshot(byteArrayOutputStream.toByteArray())); - hint.put(ANDROID_ACTIVITY, activity); + hint.setScreenshot(Attachment.fromScreenshot(byteArrayOutputStream.toByteArray())); + hint.set(ANDROID_ACTIVITY, activity); } else { this.options .getLogger() 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 c626debf41..36b38b8266 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 @@ -43,6 +43,7 @@ import io.sentry.Integration; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import io.sentry.util.StringUtils; import java.io.Closeable; @@ -215,10 +216,10 @@ public void onReceive(Context context, Intent intent) { } breadcrumb.setLevel(SentryLevel.INFO); - final Map hintMap = new HashMap<>(); - hintMap.put(ANDROID_INTENT, intent); + final Hint hint = new Hint(); + hint.set(ANDROID_INTENT, intent); - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } } 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 0d8877a407..edf8183abd 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 @@ -13,11 +13,10 @@ import io.sentry.Integration; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -107,10 +106,10 @@ public void onSensorChanged(final @NotNull SensorEvent event) { breadcrumb.setLevel(SentryLevel.INFO); breadcrumb.setData("degree", event.values[0]); // Celsius - final Map hintMap = new HashMap<>(); - hintMap.put(ANDROID_SENSOR_EVENT, event); + final Hint hint = new Hint(); + hint.set(ANDROID_SENSOR_EVENT, event); - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java index 253c8c1f19..6e3ca29f64 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java @@ -16,9 +16,9 @@ import io.sentry.SentryLevel; import io.sentry.SpanStatus; import io.sentry.android.core.SentryAndroidOptions; +import io.sentry.hints.Hint; import java.lang.ref.WeakReference; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -186,14 +186,14 @@ private void addBreadcrumb( className = target.getClass().getSimpleName(); } - final Map hintMap = new HashMap<>(); - hintMap.put(ANDROID_MOTION_EVENT, motionEvent); - hintMap.put(ANDROID_VIEW, target); + final Hint hint = new Hint(); + hint.set(ANDROID_MOTION_EVENT, motionEvent); + hint.set(ANDROID_VIEW, target); hub.addBreadcrumb( Breadcrumb.userInteraction( eventType, ViewUtils.getResourceIdWithFallback(target), className, additionalData), - hintMap); + hint); } private void startTracing(final @NotNull View target, final @NotNull String eventType) { 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 86acdc4773..a1cde833be 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 @@ -18,17 +18,18 @@ import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.SentryTracer import io.sentry.TransactionContext -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.android.core.DefaultAndroidEventProcessor.EMULATOR import io.sentry.android.core.DefaultAndroidEventProcessor.KERNEL_VERSION import io.sentry.android.core.DefaultAndroidEventProcessor.ROOTED import io.sentry.android.core.DefaultAndroidEventProcessor.SIDE_LOADED +import io.sentry.hints.Hint import io.sentry.protocol.OperatingSystem import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryThread import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import io.sentry.test.getCtor +import io.sentry.util.HintUtils import org.junit.runner.RunWith import java.util.Locale import kotlin.test.BeforeTest @@ -110,7 +111,7 @@ class DefaultAndroidEventProcessorTest { whenever(fixture.buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.M) val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { assertNotNull(it.contexts.app) assertNotNull(it.dist) @@ -125,7 +126,7 @@ class DefaultAndroidEventProcessorTest { whenever(fixture.buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.ICE_CREAM_SANDWICH) val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { // assert adds permissions val unknown = it.contexts.app!!.permissions assertNull(unknown) @@ -136,7 +137,12 @@ class DefaultAndroidEventProcessorTest { fun `When Transaction and hint is not Cached, data should be applied`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), null)) { + assertNotNull( + sut.process( + SentryTransaction(fixture.sentryTracer), + Hint() + ) + ) { assertNotNull(it.contexts.app) assertNotNull(it.dist) } @@ -153,7 +159,7 @@ class DefaultAndroidEventProcessorTest { threads = mutableListOf(sentryThread) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertNotNull(it.threads) { threads -> assertTrue(threads.first().isCurrent == true) } @@ -172,7 +178,7 @@ class DefaultAndroidEventProcessorTest { ) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertNotNull(it.threads) { threads -> assertFalse(threads.first().isCurrent == true) } @@ -192,7 +198,7 @@ class DefaultAndroidEventProcessorTest { ) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertNotNull(it.threads) { threads -> assertTrue(threads.first().isCurrent == true) } @@ -203,8 +209,8 @@ class DefaultAndroidEventProcessorTest { fun `When Event and hint is Cached, data should not be applied`() { val sut = fixture.getSut(context) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - assertNotNull(sut.process(SentryEvent(), hintsMap)) { + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + assertNotNull(sut.process(SentryEvent(), hints)) { assertNull(it.contexts.app) assertNull(it.debugMeta) assertNull(it.dist) @@ -215,8 +221,8 @@ class DefaultAndroidEventProcessorTest { fun `When Transaction and hint is Cached, data should not be applied`() { val sut = fixture.getSut(context) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), hintsMap)) { + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), hints)) { assertNull(it.contexts.app) assertNull(it.dist) } @@ -225,9 +231,8 @@ class DefaultAndroidEventProcessorTest { @Test fun `When Event and hint is Cached, userId is applied anyway`() { val sut = fixture.getSut(context) - - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - assertNotNull(sut.process(SentryEvent(), hintsMap)) { + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + assertNotNull(sut.process(SentryEvent(), hints)) { assertNotNull(it.user) } } @@ -236,8 +241,8 @@ class DefaultAndroidEventProcessorTest { fun `When Transaction and hint is Cached, userId is applied anyway`() { val sut = fixture.getSut(context) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), hintsMap)) { + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), hints)) { assertNotNull(it.user) } } @@ -253,7 +258,7 @@ class DefaultAndroidEventProcessorTest { setUser(user) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertNotNull(it.user) assertSame(user, it.user) } @@ -267,7 +272,7 @@ class DefaultAndroidEventProcessorTest { user = User() } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertNotNull(it.user) assertNotNull(it.user!!.id) } @@ -290,7 +295,7 @@ class DefaultAndroidEventProcessorTest { fun `Processor won't throw exception`() { val sut = fixture.getSut(context) - sut.process(SentryEvent(), null) + sut.process(SentryEvent(), Hint()) verify( (fixture.options.logger as DiagnosticLogger).logger, @@ -303,8 +308,8 @@ class DefaultAndroidEventProcessorTest { val processor = DefaultAndroidEventProcessor(context, fixture.options.logger, fixture.buildInfo, mock()) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - processor.process(SentryEvent(), hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + processor.process(SentryEvent(), hints) verify( (fixture.options.logger as DiagnosticLogger).logger, @@ -316,7 +321,7 @@ class DefaultAndroidEventProcessorTest { fun `When event is processed, sideLoaded info should be set`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { assertNotNull(it.getTag("isSideLoaded")) } } @@ -332,7 +337,7 @@ class DefaultAndroidEventProcessorTest { contexts.setOperatingSystem(osLinux) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertSame(osLinux, (it.contexts["os_linux"] as OperatingSystem)) assertEquals("Android", it.contexts.operatingSystem!!.name) } @@ -349,7 +354,7 @@ class DefaultAndroidEventProcessorTest { contexts.setOperatingSystem(osNoName) } - assertNotNull(sut.process(event, null)) { + assertNotNull(sut.process(event, Hint())) { assertSame(osNoName, (it.contexts["os_1"] as OperatingSystem)) assertEquals("Android", it.contexts.operatingSystem!!.name) } @@ -359,8 +364,8 @@ class DefaultAndroidEventProcessorTest { fun `When hint is Cached, memory data should not be applied`() { val sut = fixture.getSut(context) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - assertNotNull(sut.process(SentryEvent(), hintsMap)) { + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + assertNotNull(sut.process(SentryEvent(), hints)) { assertNull(it.contexts.device!!.freeMemory) assertNull(it.contexts.device!!.isLowMemory) } @@ -370,7 +375,7 @@ class DefaultAndroidEventProcessorTest { fun `When hint is not Cached, memory data should be applied`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { assertNotNull(it.contexts.device!!.freeMemory) assertNotNull(it.contexts.device!!.isLowMemory) } @@ -380,7 +385,12 @@ class DefaultAndroidEventProcessorTest { fun `Device's context is set on transactions`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), null)) { + assertNotNull( + sut.process( + SentryTransaction(fixture.sentryTracer), + Hint() + ) + ) { assertNotNull(it.contexts.device) } } @@ -389,7 +399,12 @@ class DefaultAndroidEventProcessorTest { fun `Device's OS is set on transactions`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), null)) { + assertNotNull( + sut.process( + SentryTransaction(fixture.sentryTracer), + Hint() + ) + ) { assertNotNull(it.contexts.operatingSystem) } } @@ -398,7 +413,12 @@ class DefaultAndroidEventProcessorTest { fun `Transaction do not set device's context that requires heavy work`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryTransaction(fixture.sentryTracer), null)) { + assertNotNull( + sut.process( + SentryTransaction(fixture.sentryTracer), + Hint() + ) + ) { val device = it.contexts.device!! assertNull(device.batteryLevel) assertNull(device.isCharging) @@ -418,7 +438,7 @@ class DefaultAndroidEventProcessorTest { fun `Event sets device's context that requires heavy work`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { val device = it.contexts.device!! assertNotNull(device.freeMemory) assertNotNull(device.isLowMemory) @@ -440,7 +460,7 @@ class DefaultAndroidEventProcessorTest { fun `Event sets language and locale`() { val sut = fixture.getSut(context) - assertNotNull(sut.process(SentryEvent(), null)) { + assertNotNull(sut.process(SentryEvent(), Hint())) { val device = it.contexts.device!! assertEquals("en", device.language) assertEquals("en_US", device.locale) 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 6a71706d1c..43338b5f96 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 @@ -74,7 +74,7 @@ class EnvelopeFileObserverTest { verify(fixture.envelopeSender).processEnvelopeFile( eq(fixture.path + File.separator + fixture.fileName), - check { it is ApplyScopeData } + check { HintUtils.hasType(it, ApplyScopeData::class.java) } ) } @@ -84,7 +84,7 @@ class EnvelopeFileObserverTest { verify(fixture.envelopeSender).processEnvelopeFile( eq(fixture.path + File.separator + fixture.fileName), - check { it is Resettable } + check { HintUtils.hasType(it, Resettable::class.java) } ) } @@ -94,15 +94,14 @@ class EnvelopeFileObserverTest { verify(fixture.envelopeSender).processEnvelopeFile( eq(fixture.path + File.separator + fixture.fileName), - check { - val hint = HintUtils.getSentrySdkHint(it) - (hint as SubmissionResult).setResult(true) - (hint as Retryable).isRetry = true + check { hints -> + HintUtils.runIfHasType(hints, SubmissionResult::class.java) { it.setResult(true) } + HintUtils.runIfHasType(hints, Retryable::class.java) { it.isRetry = true } - (hint as Resettable).reset() + HintUtils.runIfHasType(hints, Resettable::class.java) { it.reset() } - assertFalse(hint.isRetry) - assertFalse(hint.isSuccess) + assertFalse((HintUtils.getSentrySdkHint(hints) as Retryable).isRetry) + assertFalse((HintUtils.getSentrySdkHint(hints) as SubmissionResult).isSuccess) } ) } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/PerformanceAndroidEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/PerformanceAndroidEventProcessorTest.kt index 47d561e5c1..fda61660d1 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/PerformanceAndroidEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/PerformanceAndroidEventProcessorTest.kt @@ -7,6 +7,7 @@ import io.sentry.IHub import io.sentry.SentryTracer import io.sentry.TransactionContext import io.sentry.android.core.ActivityLifecycleIntegration.UI_LOAD_OP +import io.sentry.hints.Hint import io.sentry.protocol.MeasurementValue import io.sentry.protocol.SentryTransaction import java.util.Date @@ -45,7 +46,7 @@ class PerformanceAndroidEventProcessorTest { var tr = getTransaction() setAppStart() - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.containsKey("app_start_cold")) } @@ -57,7 +58,7 @@ class PerformanceAndroidEventProcessorTest { var tr = getTransaction("app.start.warm") setAppStart(false) - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.containsKey("app_start_warm")) } @@ -69,10 +70,10 @@ class PerformanceAndroidEventProcessorTest { var tr1 = getTransaction() setAppStart(false) - tr1 = sut.process(tr1, null) + tr1 = sut.process(tr1, Hint()) var tr2 = getTransaction() - tr2 = sut.process(tr2, null) + tr2 = sut.process(tr2, Hint()) assertTrue(tr1.measurements.containsKey("app_start_warm")) assertTrue(tr2.measurements.isEmpty()) @@ -84,7 +85,7 @@ class PerformanceAndroidEventProcessorTest { var tr = getTransaction() - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.isEmpty()) } @@ -95,7 +96,7 @@ class PerformanceAndroidEventProcessorTest { var tr = getTransaction() - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.isEmpty()) } @@ -106,7 +107,7 @@ class PerformanceAndroidEventProcessorTest { var tr = getTransaction("task") - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.isEmpty()) } @@ -116,7 +117,7 @@ class PerformanceAndroidEventProcessorTest { val sut = fixture.getSut() var tr = getTransaction("task") - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.isEmpty()) } @@ -126,7 +127,7 @@ class PerformanceAndroidEventProcessorTest { val sut = fixture.getSut(null) var tr = getTransaction("task") - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.isEmpty()) } @@ -141,7 +142,7 @@ class PerformanceAndroidEventProcessorTest { val metrics = mapOf("frames_total" to MeasurementValue(1f)) whenever(fixture.activityFramesTracker.takeMetrics(any())).thenReturn(metrics) - tr = sut.process(tr, null) + tr = sut.process(tr, Hint()) assertTrue(tr.measurements.containsKey("frames_total")) } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt index 65566c1f46..4665eacf0f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt @@ -14,7 +14,7 @@ import io.sentry.Attachment import io.sentry.MainEventProcessor import io.sentry.SentryEvent import io.sentry.TypeCheckHint.ANDROID_ACTIVITY -import io.sentry.TypeCheckHint.SENTRY_SCREENSHOT +import io.sentry.hints.Hint import org.junit.runner.RunWith import kotlin.test.BeforeTest import kotlin.test.Test @@ -95,99 +95,99 @@ class ScreenshotEventProcessorTest { @Test fun `when process is called and attachScreenshot is disabled, does nothing`() { val sut = fixture.getSut(false) - val hints = mutableMapOf() + val hint = Hint() sut.onActivityCreated(fixture.activity, null) - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } @Test fun `when event is not errored, does nothing`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() sut.onActivityCreated(fixture.activity, null) - val event = fixture.mainProcessor.process(SentryEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(SentryEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } @Test fun `when there is not activity, does nothing`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } @Test fun `when activity is finishing, does nothing`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() whenever(fixture.activity.isFinishing).thenReturn(true) sut.onActivityCreated(fixture.activity, null) - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } @Test fun `when view is zeroed, does nothing`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() whenever(fixture.rootView.width).thenReturn(0) whenever(fixture.rootView.height).thenReturn(0) sut.onActivityCreated(fixture.activity, null) - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } @Test fun `when process is called and attachScreenshot is enabled, add attachment to hints`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() sut.onActivityCreated(fixture.activity, null) - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - val screenshot = hints[SENTRY_SCREENSHOT] + val screenshot = hint.screenshot assertTrue(screenshot is Attachment) assertEquals("screenshot.png", screenshot.filename) assertEquals("image/png", screenshot.contentType) - assertSame(fixture.activity, hints[ANDROID_ACTIVITY]) + assertSame(fixture.activity, hint[ANDROID_ACTIVITY]) } @Test fun `when activity is destroyed, does nothing`() { val sut = fixture.getSut(true) - val hints = mutableMapOf() + val hint = Hint() sut.onActivityCreated(fixture.activity, null) sut.onActivityDestroyed(fixture.activity) - val event = fixture.mainProcessor.process(getEvent(), hints) - sut.process(event, hints) + val event = fixture.mainProcessor.process(getEvent(), hint) + sut.process(event, hint) - assertNull(hints[SENTRY_SCREENSHOT]) + assertNull(hint.screenshot) } private fun getEvent(): SentryEvent = SentryEvent(Throwable("Throwable")) diff --git a/sentry-android-fragment/src/main/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacks.kt b/sentry-android-fragment/src/main/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacks.kt index 6db16485eb..edd4e29e61 100644 --- a/sentry-android-fragment/src/main/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacks.kt +++ b/sentry-android-fragment/src/main/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacks.kt @@ -13,6 +13,7 @@ import io.sentry.ISpan import io.sentry.SentryLevel.INFO import io.sentry.SpanStatus import io.sentry.TypeCheckHint.ANDROID_FRAGMENT +import io.sentry.hints.Hint import java.util.WeakHashMap @Suppress("TooManyFunctions") @@ -118,9 +119,10 @@ class SentryFragmentLifecycleCallbacks( level = INFO } - val hintsMap = mutableMapOf(ANDROID_FRAGMENT to fragment) + val hint = Hint() + .also { it.set(ANDROID_FRAGMENT, fragment) } - hub.addBreadcrumb(breadcrumb, hintsMap) + hub.addBreadcrumb(breadcrumb, hint) } private fun getFragmentName(fragment: Fragment): String { diff --git a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt index 761a0104c5..10c7f4b2bb 100644 --- a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt +++ b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt @@ -8,6 +8,7 @@ import io.sentry.SpanStatus import io.sentry.TracingOrigins import io.sentry.TypeCheckHint.OKHTTP_REQUEST import io.sentry.TypeCheckHint.OKHTTP_RESPONSE +import io.sentry.hints.Hint import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response @@ -62,16 +63,17 @@ class SentryOkHttpInterceptor( breadcrumb.setData("request_body_size", it) } - val hintsMap = mutableMapOf(OKHTTP_REQUEST to request) + val hint = Hint() + .also { it.set(OKHTTP_REQUEST, request) } response?.let { it.body?.contentLength().ifHasValidLength { responseBodySize -> breadcrumb.setData("response_body_size", responseBodySize) } - hintsMap[OKHTTP_RESPONSE] = it + hint[OKHTTP_RESPONSE] = it } - hub.addBreadcrumb(breadcrumb, hintsMap) + hub.addBreadcrumb(breadcrumb, hint) } } diff --git a/sentry-apache-http-client-5/api/sentry-apache-http-client-5.api b/sentry-apache-http-client-5/api/sentry-apache-http-client-5.api index 8c27b45c82..b7ec1ca4a7 100644 --- a/sentry-apache-http-client-5/api/sentry-apache-http-client-5.api +++ b/sentry-apache-http-client-5/api/sentry-apache-http-client-5.api @@ -2,7 +2,7 @@ public final class io/sentry/transport/apache/ApacheHttpClientTransport : io/sen public fun (Lio/sentry/SentryOptions;Lio/sentry/RequestDetails;Lorg/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient;Lio/sentry/transport/RateLimiter;)V public fun close ()V public fun flush (J)V - public fun send (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public final class io/sentry/transport/apache/ApacheHttpClientTransportFactory : io/sentry/ITransportFactory { diff --git a/sentry-apache-http-client-5/src/main/java/io/sentry/transport/apache/ApacheHttpClientTransport.java b/sentry-apache-http-client-5/src/main/java/io/sentry/transport/apache/ApacheHttpClientTransport.java index 04d8eb22e8..0dee7688ed 100644 --- a/sentry-apache-http-client-5/src/main/java/io/sentry/transport/apache/ApacheHttpClientTransport.java +++ b/sentry-apache-http-client-5/src/main/java/io/sentry/transport/apache/ApacheHttpClientTransport.java @@ -7,6 +7,7 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.clientreport.DiscardReason; +import io.sentry.hints.Hint; import io.sentry.hints.Retryable; import io.sentry.transport.ITransport; import io.sentry.transport.RateLimiter; @@ -28,7 +29,6 @@ import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.util.TimeValue; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * {@link ITransport} implementation that executes request asynchronously in a non-blocking manner @@ -66,11 +66,10 @@ public ApacheHttpClientTransport( @Override @SuppressWarnings("FutureReturnValueIgnored") - public void send(final @NotNull SentryEnvelope envelope, final @Nullable Map hint) + public void send(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) throws IOException { if (isSchedulingAllowed()) { - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - final SentryEnvelope filteredEnvelope = rateLimiter.filter(envelope, sentrySdkHint); + final SentryEnvelope filteredEnvelope = rateLimiter.filter(envelope, hint); if (filteredEnvelope != null) { final SentryEnvelope envelopeWithClientReport = @@ -111,7 +110,7 @@ public void completed(SimpleHttpResponse response) { .log(ERROR, "Request failed, API returned %s", response.getCode()); if (response.getCode() >= 400 && response.getCode() != 429) { - if (!(sentrySdkHint instanceof Retryable)) { + if (!HintUtils.hasType(hint, Retryable.class)) { options .getClientReportRecorder() .recordLostEnvelope( @@ -133,7 +132,7 @@ public void completed(SimpleHttpResponse response) { @Override public void failed(Exception ex) { options.getLogger().log(ERROR, "Error while sending an envelope", ex); - if (!(sentrySdkHint instanceof Retryable)) { + if (!HintUtils.hasType(hint, Retryable.class)) { options .getClientReportRecorder() .recordLostEnvelope( @@ -145,7 +144,7 @@ public void failed(Exception ex) { @Override public void cancelled() { options.getLogger().log(WARNING, "Request cancelled"); - if (!(sentrySdkHint instanceof Retryable)) { + if (!HintUtils.hasType(hint, Retryable.class)) { options .getClientReportRecorder() .recordLostEnvelope( @@ -156,7 +155,7 @@ public void cancelled() { }); } catch (Throwable e) { options.getLogger().log(ERROR, "Error when sending envelope", e); - if (!(sentrySdkHint instanceof Retryable)) { + if (!HintUtils.hasType(hint, Retryable.class)) { options .getClientReportRecorder() .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelopeWithClientReport); diff --git a/sentry-apache-http-client-5/src/test/kotlin/io/sentry/transport/apache/ApacheHttpClientTransportClientReportTest.kt b/sentry-apache-http-client-5/src/test/kotlin/io/sentry/transport/apache/ApacheHttpClientTransportClientReportTest.kt index 8fc1b6de8b..2dc23399ea 100644 --- a/sentry-apache-http-client-5/src/test/kotlin/io/sentry/transport/apache/ApacheHttpClientTransportClientReportTest.kt +++ b/sentry-apache-http-client-5/src/test/kotlin/io/sentry/transport/apache/ApacheHttpClientTransportClientReportTest.kt @@ -18,12 +18,12 @@ import io.sentry.SentryEvent import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.SentryOptionsManipulator -import io.sentry.TypeCheckHint import io.sentry.clientreport.DiscardReason import io.sentry.clientreport.IClientReportRecorder import io.sentry.hints.Retryable import io.sentry.transport.RateLimiter import io.sentry.transport.ReusableCountLatch +import io.sentry.util.HintUtils import org.apache.hc.client5.http.async.methods.SimpleHttpResponse import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient import org.apache.hc.core5.concurrent.FutureCallback @@ -209,7 +209,7 @@ class ApacheHttpClientTransportClientReportTest { verifyNoMoreInteractions(fixture.clientReportRecorder) } - private fun retryableHint() = mutableMapOf(TypeCheckHint.SENTRY_TYPE_CHECK_HINT to TestRetryable()) + private fun retryableHint() = HintUtils.createWithTypeCheckHint(TestRetryable()) } class TestRetryable : Retryable { diff --git a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt index d0f53c6291..63ef1209dc 100644 --- a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt +++ b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt @@ -19,6 +19,7 @@ import io.sentry.SentryLevel import io.sentry.SpanStatus import io.sentry.TypeCheckHint.APOLLO_REQUEST import io.sentry.TypeCheckHint.APOLLO_RESPONSE +import io.sentry.hints.Hint import java.util.concurrent.Executor class SentryApolloInterceptor( @@ -115,8 +116,11 @@ class SentryApolloInterceptor( breadcrumb.setData("response_body_size", contentLength) } - val hintsMap = mutableMapOf(APOLLO_REQUEST to httpRequest, APOLLO_RESPONSE to httpResponse) - hub.addBreadcrumb(breadcrumb, hintsMap) + val hint = Hint().also { + it.set(APOLLO_REQUEST, httpRequest) + it.set(APOLLO_RESPONSE, httpResponse) + } + hub.addBreadcrumb(breadcrumb, hint) } } } diff --git a/sentry-graphql/src/main/java/io/sentry/graphql/SentryDataFetcherExceptionHandler.java b/sentry-graphql/src/main/java/io/sentry/graphql/SentryDataFetcherExceptionHandler.java index d0f64a1442..b9526a3a63 100644 --- a/sentry-graphql/src/main/java/io/sentry/graphql/SentryDataFetcherExceptionHandler.java +++ b/sentry-graphql/src/main/java/io/sentry/graphql/SentryDataFetcherExceptionHandler.java @@ -7,9 +7,8 @@ import graphql.execution.DataFetcherExceptionHandlerResult; import io.sentry.HubAdapter; import io.sentry.IHub; +import io.sentry.hints.Hint; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; /** @@ -34,10 +33,10 @@ public SentryDataFetcherExceptionHandler(final @NotNull DataFetcherExceptionHand @SuppressWarnings("deprecation") public DataFetcherExceptionHandlerResult onException( final @NotNull DataFetcherExceptionHandlerParameters handlerParameters) { - final Map hintMap = new HashMap<>(); - hintMap.put(GRAPHQL_HANDLER_PARAMETERS, handlerParameters); + final Hint hint = new Hint(); + hint.set(GRAPHQL_HANDLER_PARAMETERS, handlerParameters); - hub.captureException(handlerParameters.getException(), hintMap); + hub.captureException(handlerParameters.getException(), hint); return delegate.onException(handlerParameters); } } diff --git a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java index b1b2be0dba..b4cbc23483 100644 --- a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java +++ b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java @@ -9,13 +9,13 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import io.sentry.hints.Hint; import io.sentry.protocol.Message; import io.sentry.protocol.SdkVersion; import io.sentry.util.CollectionUtils; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.ErrorManager; @@ -81,16 +81,16 @@ public void publish(final @NotNull LogRecord record) { } try { if (record.getLevel().intValue() >= minimumEventLevel.intValue()) { - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_SYNTHETIC_EXCEPTION, record); + final Hint hint = new Hint(); + hint.set(SENTRY_SYNTHETIC_EXCEPTION, record); - Sentry.captureEvent(createEvent(record), hintMap); + Sentry.captureEvent(createEvent(record), hint); } if (record.getLevel().intValue() >= minimumBreadcrumbLevel.intValue()) { - final Map hintMap = new HashMap<>(); - hintMap.put(JUL_LOG_RECORD, record); + final Hint hint = new Hint(); + hint.set(JUL_LOG_RECORD, record); - Sentry.addBreadcrumb(createBreadcrumb(record), hintMap); + Sentry.addBreadcrumb(createBreadcrumb(record), hint); } } catch (RuntimeException e) { reportError( 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 9d04b401ce..93ede9f59e 100644 --- a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java +++ b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java @@ -13,12 +13,12 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import io.sentry.hints.Hint; import io.sentry.protocol.Message; import io.sentry.protocol.SdkVersion; import io.sentry.util.CollectionUtils; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -139,16 +139,16 @@ public void start() { @Override public void append(final @NotNull LogEvent eventObject) { if (eventObject.getLevel().isMoreSpecificThan(minimumEventLevel)) { - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_SYNTHETIC_EXCEPTION, eventObject); + final Hint hint = new Hint(); + hint.set(SENTRY_SYNTHETIC_EXCEPTION, eventObject); - hub.captureEvent(createEvent(eventObject), hintMap); + hub.captureEvent(createEvent(eventObject), hint); } if (eventObject.getLevel().isMoreSpecificThan(minimumBreadcrumbLevel)) { - final Map hintMap = new HashMap<>(); - hintMap.put(LOG4J_LOG_EVENT, eventObject); + final Hint hint = new Hint(); + hint.set(LOG4J_LOG_EVENT, eventObject); - hub.addBreadcrumb(createBreadcrumb(eventObject), hintMap); + hub.addBreadcrumb(createBreadcrumb(eventObject), hint); } } 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 b6cf879620..941f139aa9 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -15,12 +15,12 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import io.sentry.hints.Hint; import io.sentry.protocol.Message; import io.sentry.protocol.SdkVersion; import io.sentry.util.CollectionUtils; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -63,16 +63,16 @@ public void start() { @Override protected void append(@NotNull ILoggingEvent eventObject) { if (eventObject.getLevel().isGreaterOrEqual(minimumEventLevel)) { - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_SYNTHETIC_EXCEPTION, eventObject); + final Hint hint = new Hint(); + hint.set(SENTRY_SYNTHETIC_EXCEPTION, eventObject); - Sentry.captureEvent(createEvent(eventObject), hintMap); + Sentry.captureEvent(createEvent(eventObject), hint); } if (eventObject.getLevel().isGreaterOrEqual(minimumBreadcrumbLevel)) { - final Map hintMap = new HashMap<>(); - hintMap.put(LOGBACK_LOGGING_EVENT, eventObject); + final Hint hint = new Hint(); + hint.set(LOGBACK_LOGGING_EVENT, eventObject); - Sentry.addBreadcrumb(createBreadcrumb(eventObject), hintMap); + Sentry.addBreadcrumb(createBreadcrumb(eventObject), hint); } } diff --git a/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java b/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java index 121ac287e0..361b743340 100644 --- a/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java +++ b/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java @@ -11,11 +11,11 @@ import io.sentry.ISpan; import io.sentry.SentryTraceHeader; import io.sentry.SpanStatus; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.IOException; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.jetbrains.annotations.NotNull; @@ -92,13 +92,13 @@ private void addBreadcrumb(final @NotNull Request request, final @Nullable Respo breadcrumb.setData("response_body_size", response.body().length()); } - final Map hintMap = new HashMap<>(); - hintMap.put(OPEN_FEIGN_REQUEST, request); + final Hint hint = new Hint(); + hint.set(OPEN_FEIGN_REQUEST, request); if (response != null) { - hintMap.put(OPEN_FEIGN_RESPONSE, response); + hint.set(OPEN_FEIGN_RESPONSE, response); } - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } static final class RequestWrapper { 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 0d963e0f9b..29d3ca0271 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 @@ -8,11 +8,10 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.SpanStatus; +import io.sentry.hints.Hint; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; public class Main { @@ -137,9 +136,9 @@ public static void main(String[] args) throws InterruptedException { SentryEvent event = new SentryEvent(); event.setMessage(message); - final Map hintsMap = new HashMap<>(); - hintsMap.put("level", SentryLevel.DEBUG); - Sentry.captureEvent(event, hintsMap); + final Hint hint = new Hint(); + hint.set("level", SentryLevel.DEBUG); + Sentry.captureEvent(event, hint); } // Performance feature @@ -171,7 +170,7 @@ public static void main(String[] args) throws InterruptedException { private static class SomeEventProcessor implements EventProcessor { @Override - public SentryEvent process(SentryEvent event, Map hint) { + public SentryEvent process(SentryEvent event, Hint hint) { // Here you can modify the event as you need if (event.getLevel() != null && event.getLevel().ordinal() > SentryLevel.INFO.ordinal()) { event.addBreadcrumb(new Breadcrumb("Processed by " + SomeEventProcessor.class)); 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 c21763cc00..1ef69b9671 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 @@ -2,10 +2,9 @@ import io.sentry.EventProcessor; import io.sentry.SentryEvent; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryRuntime; -import java.util.Map; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.springframework.boot.SpringBootVersion; import org.springframework.stereotype.Component; @@ -26,8 +25,7 @@ public CustomEventProcessor() { } @Override - public @NotNull SentryEvent process( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { final SentryRuntime runtime = new SentryRuntime(); runtime.setVersion(springBootVersion); runtime.setName("Spring Boot"); diff --git a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessor.java b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessor.java index bebfc36412..101bd8585b 100644 --- a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessor.java @@ -2,6 +2,7 @@ import io.sentry.EventProcessor; import io.sentry.SentryEvent; +import io.sentry.hints.Hint; import io.sentry.protocol.Request; import io.sentry.util.Objects; import jakarta.servlet.http.HttpServletRequest; @@ -29,8 +30,7 @@ public SentryRequestHttpServletRequestProcessor(@NotNull HttpServletRequest http // httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class. @SuppressWarnings("JdkObsolete") @Override - public @NotNull SentryEvent process( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { final Request sentryRequest = new Request(); sentryRequest.setMethod(httpRequest.getMethod()); sentryRequest.setQueryString(httpRequest.getQueryString()); diff --git a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletRequestListener.java b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletRequestListener.java index fc7f516a44..e3c759bc96 100644 --- a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletRequestListener.java +++ b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletRequestListener.java @@ -6,13 +6,12 @@ import io.sentry.Breadcrumb; import io.sentry.HubAdapter; import io.sentry.IHub; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletRequestEvent; import jakarta.servlet.ServletRequestListener; import jakarta.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; /** @@ -45,11 +44,11 @@ public void requestInitialized(@NotNull ServletRequestEvent servletRequestEvent) if (servletRequest instanceof HttpServletRequest) { final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; - final Map hintMap = new HashMap<>(); - hintMap.put(SERVLET_REQUEST, httpRequest); + final Hint hint = new Hint(); + hint.set(SERVLET_REQUEST, httpRequest); hub.addBreadcrumb( - Breadcrumb.http(httpRequest.getRequestURI(), httpRequest.getMethod()), hintMap); + Breadcrumb.http(httpRequest.getRequestURI(), httpRequest.getMethod()), hint); hub.configureScope( scope -> { diff --git a/sentry-servlet-jakarta/src/test/kotlin/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-servlet-jakarta/src/test/kotlin/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessorTest.kt index 20b47ae0fb..e696a621a7 100644 --- a/sentry-servlet-jakarta/src/test/kotlin/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-servlet-jakarta/src/test/kotlin/io/sentry/servlet/jakarta/SentryRequestHttpServletRequestProcessorTest.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever import io.sentry.SentryEvent import io.sentry.SentryOptions +import io.sentry.hints.Hint import jakarta.servlet.http.HttpServletRequest import java.net.URI import java.util.Collections @@ -29,7 +30,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) val eventRequest = event.request!! @@ -56,7 +57,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { assertEquals( @@ -81,7 +82,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { assertNull(it.cookies) @@ -105,7 +106,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { req -> assertNotNull(req.headers) { diff --git a/sentry-servlet/src/main/java/io/sentry/servlet/SentryRequestHttpServletRequestProcessor.java b/sentry-servlet/src/main/java/io/sentry/servlet/SentryRequestHttpServletRequestProcessor.java index 5b6c53c464..aa87abccde 100644 --- a/sentry-servlet/src/main/java/io/sentry/servlet/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-servlet/src/main/java/io/sentry/servlet/SentryRequestHttpServletRequestProcessor.java @@ -2,6 +2,7 @@ import io.sentry.EventProcessor; import io.sentry.SentryEvent; +import io.sentry.hints.Hint; import io.sentry.protocol.Request; import io.sentry.util.Objects; import java.util.Arrays; @@ -29,8 +30,7 @@ public SentryRequestHttpServletRequestProcessor(@NotNull HttpServletRequest http // httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class. @SuppressWarnings("JdkObsolete") @Override - public @NotNull SentryEvent process( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { final Request sentryRequest = new Request(); sentryRequest.setMethod(httpRequest.getMethod()); sentryRequest.setQueryString(httpRequest.getQueryString()); diff --git a/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletRequestListener.java b/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletRequestListener.java index 2050b78e14..cf82fd853f 100644 --- a/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletRequestListener.java +++ b/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletRequestListener.java @@ -6,9 +6,8 @@ import io.sentry.Breadcrumb; import io.sentry.HubAdapter; import io.sentry.IHub; +import io.sentry.hints.Hint; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; @@ -45,11 +44,11 @@ public void requestInitialized(@NotNull ServletRequestEvent servletRequestEvent) if (servletRequest instanceof HttpServletRequest) { final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; - final Map hintMap = new HashMap<>(); - hintMap.put(SERVLET_REQUEST, httpRequest); + final Hint hint = new Hint(); + hint.set(SERVLET_REQUEST, httpRequest); hub.addBreadcrumb( - Breadcrumb.http(httpRequest.getRequestURI(), httpRequest.getMethod()), hintMap); + Breadcrumb.http(httpRequest.getRequestURI(), httpRequest.getMethod()), hint); hub.configureScope( scope -> { diff --git a/sentry-servlet/src/test/kotlin/io/sentry/servlet/SentryRequestHttpServletRequestProcessorTest.kt b/sentry-servlet/src/test/kotlin/io/sentry/servlet/SentryRequestHttpServletRequestProcessorTest.kt index c4a1f568f3..8d8174c202 100644 --- a/sentry-servlet/src/test/kotlin/io/sentry/servlet/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-servlet/src/test/kotlin/io/sentry/servlet/SentryRequestHttpServletRequestProcessorTest.kt @@ -2,6 +2,7 @@ package io.sentry.servlet import io.sentry.SentryEvent import io.sentry.SentryOptions +import io.sentry.hints.Hint import org.springframework.mock.web.MockServletContext import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import java.net.URI @@ -24,7 +25,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) val eventRequest = event.request!! @@ -50,7 +51,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { assertEquals( @@ -73,7 +74,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { assertNull(it.cookies) @@ -95,7 +96,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = SentryRequestHttpServletRequestProcessor(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.request) { req -> assertNotNull(req.headers) { 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 00a7135a7f..898c362f5f 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 @@ -19,6 +19,7 @@ import io.sentry.SentryEvent import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.checkEvent +import io.sentry.hints.Hint import io.sentry.protocol.User import io.sentry.spring.HttpServletRequestSentryUserProvider import io.sentry.spring.SentryExceptionResolver @@ -661,7 +662,7 @@ class SentryAutoConfigurationTest { } class CustomBeforeSendCallback : SentryOptions.BeforeSendCallback { - override fun execute(event: SentryEvent, hint: Map?): SentryEvent? = null + override fun execute(event: SentryEvent, hint: Hint): SentryEvent? = null } @Configuration(proxyBeanMethods = false) @@ -672,7 +673,7 @@ class SentryAutoConfigurationTest { } class CustomBeforeBreadcrumbCallback : SentryOptions.BeforeBreadcrumbCallback { - override fun execute(breadcrumb: Breadcrumb, hint: Map?): Breadcrumb? = null + override fun execute(breadcrumb: Breadcrumb, hint: Hint): Breadcrumb? = null } @Configuration(proxyBeanMethods = false) @@ -683,7 +684,7 @@ class SentryAutoConfigurationTest { } class CustomEventProcessor : EventProcessor { - override fun process(event: SentryEvent, hint: Map?) = null + override fun process(event: SentryEvent, hint: Hint) = null } @Configuration(proxyBeanMethods = false) diff --git a/sentry-spring/api/sentry-spring.api b/sentry-spring/api/sentry-spring.api index dfe84709bc..1a185dee21 100644 --- a/sentry-spring/api/sentry-spring.api +++ b/sentry-spring/api/sentry-spring.api @@ -36,7 +36,7 @@ public class io/sentry/spring/SentryInitBeanPostProcessor : org/springframework/ public class io/sentry/spring/SentryRequestHttpServletRequestProcessor : io/sentry/EventProcessor { public fun (Lio/sentry/spring/tracing/TransactionNameProvider;Ljavax/servlet/http/HttpServletRequest;)V - public fun process (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; + public fun process (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; } public class io/sentry/spring/SentryRequestResolver { 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 1c8cc9d241..d1ac9d0521 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryExceptionResolver.java @@ -8,11 +8,10 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.exception.ExceptionMechanismException; +import io.sentry.hints.Hint; import io.sentry.protocol.Mechanism; import io.sentry.spring.tracing.TransactionNameProvider; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; @@ -60,11 +59,11 @@ public SentryExceptionResolver( event.setLevel(SentryLevel.FATAL); event.setTransaction(transactionNameProvider.provideTransactionName(request)); - final Map hintMap = new HashMap<>(); - hintMap.put(SPRING_RESOLVER_REQUEST, request); - hintMap.put(SPRING_RESOLVER_RESPONSE, response); + final Hint hint = new Hint(); + hint.set(SPRING_RESOLVER_REQUEST, request); + hint.set(SPRING_RESOLVER_RESPONSE, response); - hub.captureEvent(event, hintMap); + hub.captureEvent(event, hint); // null = run other HandlerExceptionResolvers to actually handle the exception return null; 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 4d62dbd3ac..34f7e5a0eb 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryRequestHttpServletRequestProcessor.java @@ -3,12 +3,11 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.EventProcessor; import io.sentry.SentryEvent; +import io.sentry.hints.Hint; import io.sentry.spring.tracing.TransactionNameProvider; import io.sentry.util.Objects; -import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** Attaches transaction name from the HTTP request to {@link SentryEvent}. */ @Open @@ -25,8 +24,7 @@ public SentryRequestHttpServletRequestProcessor( } @Override - public @NotNull SentryEvent process( - final @NotNull SentryEvent event, final @Nullable Map hint) { + public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) { if (event.getTransaction() == null) { event.setTransaction(transactionNameProvider.provideTransactionName(request)); } diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentrySpringFilter.java b/sentry-spring/src/main/java/io/sentry/spring/SentrySpringFilter.java index a33d2103d0..791936a8f3 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentrySpringFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentrySpringFilter.java @@ -13,18 +13,16 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.SentryOptions.RequestSize; +import io.sentry.hints.Hint; import io.sentry.spring.tracing.SpringMvcTransactionNameProvider; import io.sentry.spring.tracing.TransactionNameProvider; import io.sentry.util.Objects; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; 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.jetbrains.annotations.Nullable; import org.springframework.http.MediaType; import org.springframework.util.MimeType; import org.springframework.web.filter.OncePerRequestFilter; @@ -64,11 +62,11 @@ protected void doFilterInternal( final HttpServletRequest request = resolveHttpServletRequest(servletRequest); hub.pushScope(); try { - final Map hintMap = new HashMap<>(); - hintMap.put(SPRING_REQUEST_FILTER_REQUEST, servletRequest); - hintMap.put(SPRING_REQUEST_FILTER_RESPONSE, response); + final Hint hint = new Hint(); + hint.set(SPRING_REQUEST_FILTER_REQUEST, servletRequest); + hint.set(SPRING_REQUEST_FILTER_RESPONSE, response); - hub.addBreadcrumb(Breadcrumb.http(request.getRequestURI(), request.getMethod()), hintMap); + hub.addBreadcrumb(Breadcrumb.http(request.getRequestURI(), request.getMethod()), hint); configureScope(request); filterChain.doFilter(request, response); } finally { @@ -150,8 +148,7 @@ public RequestBodyExtractingEventProcessor( } @Override - public @NotNull SentryEvent process( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { if (event.getRequest() != null) { event.getRequest().setData(requestPayloadExtractor.extract(request, options)); } diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java index ad8fc1682a..d12da58998 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java @@ -11,10 +11,9 @@ import io.sentry.SentryTraceHeader; import io.sentry.SpanStatus; import io.sentry.TracingOrigins; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.http.HttpRequest; @@ -81,13 +80,13 @@ private void addBreadcrumb( Breadcrumb.http(request.getURI().toString(), request.getMethodValue(), responseStatusCode); breadcrumb.setData("request_body_size", body.length); - final Map hintMap = new HashMap<>(); - hintMap.put(SPRING_REQUEST_INTERCEPTOR_REQUEST, request); - hintMap.put(SPRING_REQUEST_INTERCEPTOR_REQUEST_BODY, body); + final Hint hint = new Hint(); + hint.set(SPRING_REQUEST_INTERCEPTOR_REQUEST, request); + hint.set(SPRING_REQUEST_INTERCEPTOR_REQUEST_BODY, body); if (response != null) { - hintMap.put(SPRING_REQUEST_INTERCEPTOR_RESPONSE, response); + hint.set(SPRING_REQUEST_INTERCEPTOR_RESPONSE, response); } - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java index 17a8650a27..8c8525ad1b 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java @@ -10,9 +10,8 @@ import io.sentry.SentryTraceHeader; import io.sentry.SpanStatus; import io.sentry.TracingOrigins; +import io.sentry.hints.Hint; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.reactive.function.client.ClientRequest; @@ -77,12 +76,12 @@ private void addBreadcrumb( request.method().name(), response != null ? response.rawStatusCode() : null); - final Map hintMap = new HashMap<>(); - hintMap.put(SPRING_EXCHANGE_FILTER_REQUEST, request); + final Hint hint = new Hint(); + hint.set(SPRING_EXCHANGE_FILTER_REQUEST, request); if (response != null) { - hintMap.put(SPRING_EXCHANGE_FILTER_RESPONSE, response); + hint.set(SPRING_EXCHANGE_FILTER_RESPONSE, response); } - hub.addBreadcrumb(breadcrumb, hintMap); + hub.addBreadcrumb(breadcrumb, hint); } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebExceptionHandler.java b/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebExceptionHandler.java index 38d7750d81..ba71d8eb56 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebExceptionHandler.java +++ b/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebExceptionHandler.java @@ -7,10 +7,9 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.exception.ExceptionMechanismException; +import io.sentry.hints.Hint; import io.sentry.protocol.Mechanism; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.springframework.core.annotation.Order; @@ -44,11 +43,11 @@ public SentryWebExceptionHandler(final @NotNull IHub hub) { event.setLevel(SentryLevel.FATAL); event.setTransaction(TransactionNameProvider.provideTransactionName(serverWebExchange)); - final Map hintMap = new HashMap<>(); - hintMap.put(WEBFLUX_EXCEPTION_HANDLER_REQUEST, serverWebExchange.getRequest()); - hintMap.put(WEBFLUX_EXCEPTION_HANDLER_RESPONSE, serverWebExchange.getResponse()); + final Hint hint = new Hint(); + hint.set(WEBFLUX_EXCEPTION_HANDLER_REQUEST, serverWebExchange.getRequest()); + hint.set(WEBFLUX_EXCEPTION_HANDLER_RESPONSE, serverWebExchange.getResponse()); - hub.captureEvent(event, hintMap); + hub.captureEvent(event, hint); } return Mono.error(ex); } diff --git a/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebFilter.java b/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebFilter.java index 8cd060779a..6613252c4b 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/webflux/SentryWebFilter.java @@ -5,9 +5,8 @@ import io.sentry.Breadcrumb; import io.sentry.IHub; +import io.sentry.hints.Hint; import io.sentry.util.Objects; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -44,12 +43,12 @@ public Mono filter( final ServerHttpRequest request = serverWebExchange.getRequest(); final ServerHttpResponse response = serverWebExchange.getResponse(); - final Map hintMap = new HashMap<>(); - hintMap.put(WEBFLUX_FILTER_REQUEST, request); - hintMap.put(WEBFLUX_FILTER_RESPONSE, response); + final Hint hint = new Hint(); + hint.set(WEBFLUX_FILTER_REQUEST, request); + hint.set(WEBFLUX_FILTER_RESPONSE, response); hub.addBreadcrumb( - Breadcrumb.http(request.getURI().toString(), request.getMethodValue()), hintMap); + Breadcrumb.http(request.getURI().toString(), request.getMethodValue()), hint); hub.configureScope( scope -> scope.setRequest(sentryRequestResolver.resolveSentryRequest(request))); }); 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 360d505fb0..370fbc1ffc 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/SentryRequestHttpServletRequestProcessorTest.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockitokotlin2.whenever import io.sentry.IHub import io.sentry.SentryEvent import io.sentry.SentryOptions +import io.sentry.hints.Hint import io.sentry.spring.tracing.SpringMvcTransactionNameProvider import org.springframework.mock.web.MockServletContext import org.springframework.test.web.servlet.request.MockMvcRequestBuilders @@ -37,7 +38,7 @@ class SentryRequestHttpServletRequestProcessorTest { val eventProcessor = fixture.getSut(request) val event = SentryEvent() - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.transaction) assertEquals("GET /some-path", event.transaction) @@ -53,7 +54,7 @@ class SentryRequestHttpServletRequestProcessorTest { val event = SentryEvent() event.transaction = "some-transaction" - eventProcessor.process(event, null) + eventProcessor.process(event, Hint()) assertNotNull(event.transaction) assertEquals("some-transaction", event.transaction) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 2971e31750..c9519a4812 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -119,7 +119,7 @@ public final class io/sentry/DiagnosticLogger : io/sentry/ILogger { public final class io/sentry/DuplicateEventDetectionEventProcessor : io/sentry/EventProcessor { public fun (Lio/sentry/SentryOptions;)V - public fun process (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; + public fun process (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; } public final class io/sentry/EnvelopeReader : io/sentry/IEnvelopeReader { @@ -130,12 +130,12 @@ public final class io/sentry/EnvelopeReader : io/sentry/IEnvelopeReader { public final class io/sentry/EnvelopeSender : io/sentry/IEnvelopeSender { public fun (Lio/sentry/IHub;Lio/sentry/ISerializer;Lio/sentry/ILogger;J)V public synthetic fun processDirectory (Ljava/io/File;)V - public fun processEnvelopeFile (Ljava/lang/String;Ljava/util/Map;)V + public fun processEnvelopeFile (Ljava/lang/String;Lio/sentry/hints/Hint;)V } public abstract interface class io/sentry/EventProcessor { - public fun process (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; - public fun process (Lio/sentry/protocol/SentryTransaction;Ljava/util/Map;)Lio/sentry/protocol/SentryTransaction; + public fun process (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; + public fun process (Lio/sentry/protocol/SentryTransaction;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryTransaction; } public final class io/sentry/ExternalOptions { @@ -187,13 +187,13 @@ public final class io/sentry/ExternalOptions { public final class io/sentry/Hub : io/sentry/IHub { public fun (Lio/sentry/SentryOptions;)V - public fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public fun bindClient (Lio/sentry/ISentryClient;)V - public fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun clearBreadcrumbs ()V public fun clone ()Lio/sentry/IHub; @@ -227,13 +227,13 @@ public final class io/sentry/Hub : io/sentry/IHub { } public final class io/sentry/HubAdapter : io/sentry/IHub { - public fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public fun bindClient (Lio/sentry/ISentryClient;)V - public fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun clearBreadcrumbs ()V public fun clone ()Lio/sentry/IHub; @@ -273,27 +273,27 @@ public abstract interface class io/sentry/IEnvelopeReader { } public abstract interface class io/sentry/IEnvelopeSender { - public abstract fun processEnvelopeFile (Ljava/lang/String;Ljava/util/Map;)V + public abstract fun processEnvelopeFile (Ljava/lang/String;Lio/sentry/hints/Hint;)V } public abstract interface class io/sentry/IHub { public fun addBreadcrumb (Lio/sentry/Breadcrumb;)V - public abstract fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public abstract fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public fun addBreadcrumb (Ljava/lang/String;)V public fun addBreadcrumb (Ljava/lang/String;Ljava/lang/String;)V public abstract fun bindClient (Lio/sentry/ISentryClient;)V public fun captureEnvelope (Lio/sentry/SentryEnvelope;)Lio/sentry/protocol/SentryId; - public abstract fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public abstract fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureEvent (Lio/sentry/SentryEvent;)Lio/sentry/protocol/SentryId; - public abstract fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public abstract fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureException (Ljava/lang/Throwable;)Lio/sentry/protocol/SentryId; - public abstract fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public abstract fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;)Lio/sentry/protocol/SentryId; public abstract fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public abstract fun captureUserFeedback (Lio/sentry/UserFeedback;)V public abstract fun clearBreadcrumbs ()V public abstract fun clone ()Lio/sentry/IHub; @@ -352,24 +352,24 @@ public abstract interface class io/sentry/IScopeObserver { public abstract interface class io/sentry/ISentryClient { public fun captureEnvelope (Lio/sentry/SentryEnvelope;)Lio/sentry/protocol/SentryId; - public abstract fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public abstract fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureEvent (Lio/sentry/SentryEvent;)Lio/sentry/protocol/SentryId; public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;)Lio/sentry/protocol/SentryId; - public abstract fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public abstract fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureException (Ljava/lang/Throwable;)Lio/sentry/protocol/SentryId; public fun captureException (Ljava/lang/Throwable;Lio/sentry/Scope;)Lio/sentry/protocol/SentryId; - public fun captureException (Ljava/lang/Throwable;Lio/sentry/Scope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureException (Ljava/lang/Throwable;Lio/sentry/Scope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/Scope;)Lio/sentry/protocol/SentryId; public fun captureSession (Lio/sentry/Session;)V - public abstract fun captureSession (Lio/sentry/Session;Ljava/util/Map;)V + public abstract fun captureSession (Lio/sentry/Session;Lio/sentry/hints/Hint;)V public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Scope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Scope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; public abstract fun captureUserFeedback (Lio/sentry/UserFeedback;)V public abstract fun close ()V public abstract fun flush (J)V @@ -508,8 +508,8 @@ public abstract interface class io/sentry/JsonUnknown { public final class io/sentry/MainEventProcessor : io/sentry/EventProcessor, java/io/Closeable { public fun (Lio/sentry/SentryOptions;)V public fun close ()V - public fun process (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; - public fun process (Lio/sentry/protocol/SentryTransaction;Ljava/util/Map;)Lio/sentry/protocol/SentryTransaction; + public fun process (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; + public fun process (Lio/sentry/protocol/SentryTransaction;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryTransaction; } public final class io/sentry/NoOpEnvelopeReader : io/sentry/IEnvelopeReader { @@ -518,13 +518,13 @@ public final class io/sentry/NoOpEnvelopeReader : io/sentry/IEnvelopeReader { } public final class io/sentry/NoOpHub : io/sentry/IHub { - public fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public fun bindClient (Lio/sentry/ISentryClient;)V - public fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun clearBreadcrumbs ()V public fun clone ()Lio/sentry/IHub; @@ -645,7 +645,7 @@ public final class io/sentry/OptionsContainer { public final class io/sentry/OutboxSender : io/sentry/IEnvelopeSender { public fun (Lio/sentry/IHub;Lio/sentry/IEnvelopeReader;Lio/sentry/ISerializer;Lio/sentry/ILogger;J)V public synthetic fun processDirectory (Ljava/io/File;)V - public fun processEnvelopeFile (Ljava/lang/String;Ljava/util/Map;)V + public fun processEnvelopeFile (Ljava/lang/String;Lio/sentry/hints/Hint;)V } public final class io/sentry/ProfilingTraceData : io/sentry/JsonSerializable, io/sentry/JsonUnknown { @@ -745,7 +745,7 @@ public final class io/sentry/Scope { public fun (Lio/sentry/SentryOptions;)V public fun addAttachment (Lio/sentry/Attachment;)V public fun addBreadcrumb (Lio/sentry/Breadcrumb;)V - public fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public fun addEventProcessor (Lio/sentry/EventProcessor;)V public fun clear ()V public fun clearAttachments ()V @@ -819,14 +819,14 @@ public final class io/sentry/SendFireAndForgetOutboxSender : io/sentry/SendCache public final class io/sentry/Sentry { public static fun addBreadcrumb (Lio/sentry/Breadcrumb;)V - public static fun addBreadcrumb (Lio/sentry/Breadcrumb;Ljava/util/Map;)V + public static fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)V public static fun addBreadcrumb (Ljava/lang/String;)V public static fun addBreadcrumb (Ljava/lang/String;Ljava/lang/String;)V public static fun bindClient (Lio/sentry/ISentryClient;)V public static fun captureEvent (Lio/sentry/SentryEvent;)Lio/sentry/protocol/SentryId; - public static fun captureEvent (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public static fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public static fun captureException (Ljava/lang/Throwable;)Lio/sentry/protocol/SentryId; - public static fun captureException (Ljava/lang/Throwable;Ljava/util/Map;)Lio/sentry/protocol/SentryId; + public static fun captureException (Ljava/lang/Throwable;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; public static fun captureMessage (Ljava/lang/String;)Lio/sentry/protocol/SentryId; public static fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; public static fun captureUserFeedback (Lio/sentry/UserFeedback;)V @@ -948,10 +948,10 @@ public final class io/sentry/SentryBaseEvent$Serializer { } public final class io/sentry/SentryClient : io/sentry/ISentryClient { - public fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;Ljava/util/Map;)Lio/sentry/protocol/SentryId; - public fun captureSession (Lio/sentry/Session;Ljava/util/Map;)V - public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Ljava/util/Map;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; + public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;Lio/sentry/hints/Hint;)Lio/sentry/protocol/SentryId; + public fun captureSession (Lio/sentry/Session;Lio/sentry/hints/Hint;)V + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceState;Lio/sentry/Scope;Lio/sentry/hints/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun close ()V public fun flush (J)V @@ -1263,11 +1263,11 @@ public class io/sentry/SentryOptions { } public abstract interface class io/sentry/SentryOptions$BeforeBreadcrumbCallback { - public abstract fun execute (Lio/sentry/Breadcrumb;Ljava/util/Map;)Lio/sentry/Breadcrumb; + public abstract fun execute (Lio/sentry/Breadcrumb;Lio/sentry/hints/Hint;)Lio/sentry/Breadcrumb; } public abstract interface class io/sentry/SentryOptions$BeforeSendCallback { - public abstract fun execute (Lio/sentry/SentryEvent;Ljava/util/Map;)Lio/sentry/SentryEvent; + public abstract fun execute (Lio/sentry/SentryEvent;Lio/sentry/hints/Hint;)Lio/sentry/SentryEvent; } public final class io/sentry/SentryOptions$Proxy { @@ -1645,7 +1645,6 @@ public final class io/sentry/TypeCheckHint { public static final field OKHTTP_RESPONSE Ljava/lang/String; public static final field OPEN_FEIGN_REQUEST Ljava/lang/String; public static final field OPEN_FEIGN_RESPONSE Ljava/lang/String; - public static final field SENTRY_SCREENSHOT Ljava/lang/String; public static final field SENTRY_SYNTHETIC_EXCEPTION Ljava/lang/String; public static final field SENTRY_TYPE_CHECK_HINT Ljava/lang/String; public static final field SERVLET_REQUEST Ljava/lang/String; @@ -1711,13 +1710,13 @@ public final class io/sentry/cache/EnvelopeCache : io/sentry/cache/IEnvelopeCach public static fun create (Lio/sentry/SentryOptions;)Lio/sentry/cache/IEnvelopeCache; public fun discard (Lio/sentry/SentryEnvelope;)V public fun iterator ()Ljava/util/Iterator; - public fun store (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public abstract interface class io/sentry/cache/IEnvelopeCache : java/lang/Iterable { public abstract fun discard (Lio/sentry/SentryEnvelope;)V public fun store (Lio/sentry/SentryEnvelope;)V - public abstract fun store (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public abstract fun store (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public final class io/sentry/clientreport/ClientReport : io/sentry/JsonSerializable, io/sentry/JsonUnknown { @@ -1854,6 +1853,23 @@ public abstract interface class io/sentry/hints/Flushable { public abstract fun waitFlush ()Z } +public final class io/sentry/hints/Hint { + public fun ()V + public fun addAttachment (Lio/sentry/Attachment;)V + public fun addAttachments (Ljava/util/List;)V + public fun clearAttachments ()V + public fun get (Ljava/lang/String;)Ljava/lang/Object; + public fun getAs (Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object; + public fun getAttachments ()Ljava/util/List; + public fun getScreenshot ()Lio/sentry/Attachment; + public fun remove (Ljava/lang/String;)V + public fun replaceAttachments (Ljava/util/List;)V + public fun set (Ljava/lang/String;Ljava/lang/Object;)V + public fun setScreenshot (Lio/sentry/Attachment;)V + public static fun withAttachment (Lio/sentry/Attachment;)Lio/sentry/hints/Hint; + public static fun withAttachments (Ljava/util/List;)Lio/sentry/hints/Hint; +} + public abstract interface class io/sentry/hints/Resettable { public abstract fun reset ()V } @@ -2836,7 +2852,7 @@ public final class io/sentry/transport/AsyncHttpTransport : io/sentry/transport/ public fun (Lio/sentry/transport/QueuedThreadPoolExecutor;Lio/sentry/SentryOptions;Lio/sentry/transport/RateLimiter;Lio/sentry/transport/ITransportGate;Lio/sentry/transport/HttpConnection;)V public fun close ()V public fun flush (J)V - public fun send (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public final class io/sentry/transport/CurrentDateProvider : io/sentry/transport/ICurrentDateProvider { @@ -2851,7 +2867,7 @@ public abstract interface class io/sentry/transport/ICurrentDateProvider { public abstract interface class io/sentry/transport/ITransport : java/io/Closeable { public abstract fun flush (J)V public fun send (Lio/sentry/SentryEnvelope;)V - public abstract fun send (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public abstract fun send (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public abstract interface class io/sentry/transport/ITransportGate { @@ -2863,14 +2879,14 @@ public final class io/sentry/transport/NoOpEnvelopeCache : io/sentry/cache/IEnve public fun discard (Lio/sentry/SentryEnvelope;)V public static fun getInstance ()Lio/sentry/transport/NoOpEnvelopeCache; public fun iterator ()Ljava/util/Iterator; - public fun store (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public final class io/sentry/transport/NoOpTransport : io/sentry/transport/ITransport { public fun close ()V public fun flush (J)V public static fun getInstance ()Lio/sentry/transport/NoOpTransport; - public fun send (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public final class io/sentry/transport/NoOpTransportGate : io/sentry/transport/ITransportGate { @@ -2881,7 +2897,7 @@ public final class io/sentry/transport/NoOpTransportGate : io/sentry/transport/I public final class io/sentry/transport/RateLimiter { public fun (Lio/sentry/SentryOptions;)V public fun (Lio/sentry/transport/ICurrentDateProvider;Lio/sentry/SentryOptions;)V - public fun filter (Lio/sentry/SentryEnvelope;Ljava/lang/Object;)Lio/sentry/SentryEnvelope; + public fun filter (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)Lio/sentry/SentryEnvelope; public fun updateRetryAfterLimits (Ljava/lang/String;Ljava/lang/String;I)V } @@ -2899,7 +2915,7 @@ public final class io/sentry/transport/StdoutTransport : io/sentry/transport/ITr public fun (Lio/sentry/ISerializer;)V public fun close ()V public fun flush (J)V - public fun send (Lio/sentry/SentryEnvelope;Ljava/util/Map;)V + public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/hints/Hint;)V } public abstract class io/sentry/transport/TransportResult { @@ -2934,14 +2950,32 @@ public final class io/sentry/util/FileUtils { } public final class io/sentry/util/HintUtils { - public static fun getSentrySdkHint (Ljava/util/Map;)Ljava/lang/Object; - public static fun shouldApplyScopeData (Ljava/util/Map;)Z + public static fun createWithTypeCheckHint (Ljava/lang/Object;)Lio/sentry/hints/Hint; + public static fun getSentrySdkHint (Lio/sentry/hints/Hint;)Ljava/lang/Object; + public static fun hasType (Lio/sentry/hints/Hint;Ljava/lang/Class;)Z + public static fun runIfDoesNotHaveType (Lio/sentry/hints/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryNullableConsumer;)V + public static fun runIfHasType (Lio/sentry/hints/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryConsumer;)V + public static fun runIfHasType (Lio/sentry/hints/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryConsumer;Lio/sentry/util/HintUtils$SentryHintFallback;)V + public static fun runIfHasTypeLogIfNot (Lio/sentry/hints/Hint;Ljava/lang/Class;Lio/sentry/ILogger;Lio/sentry/util/HintUtils$SentryConsumer;)V + public static fun setTypeCheckHint (Lio/sentry/hints/Hint;Ljava/lang/Object;)V + public static fun shouldApplyScopeData (Lio/sentry/hints/Hint;)Z +} + +public abstract interface class io/sentry/util/HintUtils$SentryConsumer { + public abstract fun accept (Ljava/lang/Object;)V +} + +public abstract interface class io/sentry/util/HintUtils$SentryHintFallback { + public abstract fun accept (Ljava/lang/Object;Ljava/lang/Class;)V +} + +public abstract interface class io/sentry/util/HintUtils$SentryNullableConsumer { + public abstract fun accept (Ljava/lang/Object;)V } public final class io/sentry/util/LogUtils { public fun ()V - public static fun logIfNotFlushable (Lio/sentry/ILogger;Ljava/lang/Object;)V - public static fun logIfNotRetryable (Lio/sentry/ILogger;Ljava/lang/Object;)V + public static fun logNotInstanceOf (Ljava/lang/Class;Ljava/lang/Object;Lio/sentry/ILogger;)V } public final class io/sentry/util/Objects { diff --git a/sentry/src/main/java/io/sentry/DirectoryProcessor.java b/sentry/src/main/java/io/sentry/DirectoryProcessor.java index 3277715021..3777a966f0 100644 --- a/sentry/src/main/java/io/sentry/DirectoryProcessor.java +++ b/sentry/src/main/java/io/sentry/DirectoryProcessor.java @@ -1,19 +1,17 @@ package io.sentry; import static io.sentry.SentryLevel.ERROR; -import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; import io.sentry.hints.Cached; import io.sentry.hints.Flushable; +import io.sentry.hints.Hint; import io.sentry.hints.Retryable; import io.sentry.hints.SubmissionResult; +import io.sentry.util.HintUtils; import java.io.File; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; abstract class DirectoryProcessor { @@ -65,20 +63,19 @@ public void processDirectory(final @NotNull File directory) { logger.log(SentryLevel.DEBUG, "Processing file: %s", file.getAbsolutePath()); - final SendCachedEnvelopeHint hint = new SendCachedEnvelopeHint(flushTimeoutMillis, logger); + final SendCachedEnvelopeHint cachedHint = + new SendCachedEnvelopeHint(flushTimeoutMillis, logger); - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, hint); + final Hint hint = HintUtils.createWithTypeCheckHint(cachedHint); - processFile(file, hintMap); + processFile(file, hint); } } catch (Throwable e) { logger.log(SentryLevel.ERROR, e, "Failed processing '%s'", directory.getAbsolutePath()); } } - protected abstract void processFile( - final @NotNull File file, final @Nullable Map hint); + protected abstract void processFile(final @NotNull File file, final @NotNull Hint hint); protected abstract boolean isRelevantFileName(String fileName); diff --git a/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java b/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java index a5baa3c5fc..896b5d8dd3 100644 --- a/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java +++ b/sentry/src/main/java/io/sentry/DuplicateEventDetectionEventProcessor.java @@ -1,5 +1,6 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.util.ArrayList; import java.util.Collections; @@ -20,8 +21,7 @@ public DuplicateEventDetectionEventProcessor(final @NotNull SentryOptions option } @Override - public @Nullable SentryEvent process( - final @NotNull SentryEvent event, final @Nullable Map hint) { + public @Nullable SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) { if (options.isEnableDeduplication()) { final Throwable throwable = event.getThrowable(); if (throwable != null) { diff --git a/sentry/src/main/java/io/sentry/EnvelopeSender.java b/sentry/src/main/java/io/sentry/EnvelopeSender.java index bae79a6997..4b41b31db6 100644 --- a/sentry/src/main/java/io/sentry/EnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/EnvelopeSender.java @@ -2,9 +2,9 @@ import io.sentry.cache.EnvelopeCache; import io.sentry.hints.Flushable; +import io.sentry.hints.Hint; import io.sentry.hints.Retryable; import io.sentry.util.HintUtils; -import io.sentry.util.LogUtils; import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.File; @@ -12,10 +12,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; @ApiStatus.Internal public final class EnvelopeSender extends DirectoryProcessor implements IEnvelopeSender { @@ -36,7 +34,7 @@ public EnvelopeSender( } @Override - protected void processFile(final @NotNull File file, final @Nullable Map hint) { + protected void processFile(final @NotNull File file, final @NotNull Hint hint) { if (!file.isFile()) { logger.log(SentryLevel.DEBUG, "'%s' is not a file.", file.getAbsolutePath()); return; @@ -56,8 +54,6 @@ protected void processFile(final @NotNull File file, final @Nullable Map { + if (!flushable.waitFlush()) { + logger.log(SentryLevel.WARNING, "Timed out waiting for envelope submission."); + } + }); } catch (FileNotFoundException e) { logger.log(SentryLevel.ERROR, e, "File '%s' cannot be found.", file.getAbsolutePath()); } catch (IOException e) { @@ -81,27 +79,31 @@ protected void processFile(final @NotNull File file, final @Nullable Map { + retryable.setRetry(false); + logger.log(SentryLevel.INFO, e, "File '%s' won't retry.", file.getAbsolutePath()); + }); } finally { // Unless the transport marked this to be retried, it'll be deleted. - if (sentrySdkHint instanceof Retryable) { - if (!((Retryable) sentrySdkHint).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, sentrySdkHint); - } + HintUtils.runIfHasTypeLogIfNot( + hint, + Retryable.class, + logger, + (retryable) -> { + if (!retryable.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()); + } + }); } } @@ -111,8 +113,7 @@ protected boolean isRelevantFileName(final @NotNull String fileName) { } @Override - public void processEnvelopeFile( - final @NotNull String path, final @Nullable Map hint) { + public void processEnvelopeFile(final @NotNull String path, final @NotNull Hint hint) { Objects.requireNonNull(path, "Path is required."); processFile(new File(path), hint); diff --git a/sentry/src/main/java/io/sentry/EventProcessor.java b/sentry/src/main/java/io/sentry/EventProcessor.java index 8f4a3b2cd4..1030af9e98 100644 --- a/sentry/src/main/java/io/sentry/EventProcessor.java +++ b/sentry/src/main/java/io/sentry/EventProcessor.java @@ -1,7 +1,7 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryTransaction; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,7 +18,7 @@ public interface EventProcessor { * @return the event itself, a mutated SentryEvent or null */ @Nullable - default SentryEvent process(@NotNull SentryEvent event, @Nullable Map hint) { + default SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) { return event; } @@ -30,8 +30,7 @@ default SentryEvent process(@NotNull SentryEvent event, @Nullable Map hint) { + default SentryTransaction process(@NotNull SentryTransaction transaction, @NotNull Hint hint) { return transaction; } } diff --git a/sentry/src/main/java/io/sentry/Hub.java b/sentry/src/main/java/io/sentry/Hub.java index 996a7c0fd3..a93ecc989e 100644 --- a/sentry/src/main/java/io/sentry/Hub.java +++ b/sentry/src/main/java/io/sentry/Hub.java @@ -1,21 +1,20 @@ package io.sentry; -import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; - import io.sentry.Stack.StackItem; import io.sentry.clientreport.DiscardReason; +import io.sentry.hints.Hint; import io.sentry.hints.SessionEndHint; import io.sentry.hints.SessionStartHint; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import io.sentry.util.ExceptionUtils; +import io.sentry.util.HintUtils; import io.sentry.util.Objects; import io.sentry.util.Pair; import java.io.Closeable; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -77,7 +76,7 @@ public boolean isEnabled() { @Override public @NotNull SentryId captureEvent( - final @NotNull SentryEvent event, final @Nullable Map hint) { + final @NotNull SentryEvent event, final @Nullable Hint hint) { SentryId sentryId = SentryId.EMPTY_ID; if (!isEnabled()) { options @@ -129,7 +128,7 @@ public boolean isEnabled() { @ApiStatus.Internal @Override public @NotNull SentryId captureEnvelope( - final @NotNull SentryEnvelope envelope, final @Nullable Map hint) { + final @NotNull SentryEnvelope envelope, final @Nullable Hint hint) { Objects.requireNonNull(envelope, "SentryEnvelope is required."); SentryId sentryId = SentryId.EMPTY_ID; @@ -155,7 +154,7 @@ public boolean isEnabled() { @Override public @NotNull SentryId captureException( - final @NotNull Throwable throwable, final @Nullable Map hint) { + final @NotNull Throwable throwable, final @Nullable Hint hint) { SentryId sentryId = SentryId.EMPTY_ID; if (!isEnabled()) { options @@ -237,16 +236,14 @@ public void startSession() { // single envelope // Or create the envelope here with both items and call `captureEnvelope` if (pair.getPrevious() != null) { - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, new SessionEndHint()); + final Hint hint = HintUtils.createWithTypeCheckHint(new SessionEndHint()); - item.getClient().captureSession(pair.getPrevious(), hintMap); + item.getClient().captureSession(pair.getPrevious(), hint); } - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, new SessionStartHint()); + final Hint hint = HintUtils.createWithTypeCheckHint(new SessionStartHint()); - item.getClient().captureSession(pair.getCurrent(), hintMap); + item.getClient().captureSession(pair.getCurrent(), hint); } else { options.getLogger().log(SentryLevel.WARNING, "Session could not be started."); } @@ -263,10 +260,9 @@ public void endSession() { final StackItem item = this.stack.peek(); final Session previousSession = item.getScope().endSession(); if (previousSession != null) { - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, new SessionEndHint()); + final Hint hint = HintUtils.createWithTypeCheckHint(new SessionEndHint()); - item.getClient().captureSession(previousSession, hintMap); + item.getClient().captureSession(previousSession, hint); } } } @@ -298,8 +294,7 @@ public void close() { } @Override - public void addBreadcrumb( - final @NotNull Breadcrumb breadcrumb, final @Nullable Map hint) { + public void addBreadcrumb(final @NotNull Breadcrumb breadcrumb, final @Nullable Hint hint) { if (!isEnabled()) { options .getLogger() @@ -552,7 +547,7 @@ public void flush(long timeoutMillis) { public @NotNull SentryId captureTransaction( final @NotNull SentryTransaction transaction, final @Nullable TraceState traceState, - final @Nullable Map hint, + final @Nullable Hint hint, final @Nullable ProfilingTraceData profilingTraceData) { Objects.requireNonNull(transaction, "transaction is required"); diff --git a/sentry/src/main/java/io/sentry/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java index 0833cc5daf..9266c336c4 100644 --- a/sentry/src/main/java/io/sentry/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -1,11 +1,11 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.Date; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,8 +26,7 @@ public boolean isEnabled() { } @Override - public @NotNull SentryId captureEvent( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryId captureEvent(@NotNull SentryEvent event, @Nullable Hint hint) { return Sentry.captureEvent(event, hint); } @@ -38,14 +37,12 @@ public boolean isEnabled() { @ApiStatus.Internal @Override - public @NotNull SentryId captureEnvelope( - @NotNull SentryEnvelope envelope, @Nullable Map hint) { + public @NotNull SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint) { return Sentry.getCurrentHub().captureEnvelope(envelope, hint); } @Override - public @NotNull SentryId captureException( - @NotNull Throwable throwable, @Nullable Map hint) { + public @NotNull SentryId captureException(@NotNull Throwable throwable, @Nullable Hint hint) { return Sentry.captureException(throwable, hint); } @@ -70,7 +67,7 @@ public void close() { } @Override - public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Map hint) { + public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint) { Sentry.addBreadcrumb(breadcrumb, hint); } @@ -163,7 +160,7 @@ public void flush(long timeoutMillis) { public @NotNull SentryId captureTransaction( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, - @Nullable Map hint, + @Nullable Hint hint, @Nullable ProfilingTraceData profilingTraceData) { return Sentry.getCurrentHub() .captureTransaction(transaction, traceState, hint, profilingTraceData); diff --git a/sentry/src/main/java/io/sentry/IEnvelopeSender.java b/sentry/src/main/java/io/sentry/IEnvelopeSender.java index 2a346e7400..b37307fa5b 100644 --- a/sentry/src/main/java/io/sentry/IEnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/IEnvelopeSender.java @@ -1,9 +1,8 @@ package io.sentry; -import java.util.Map; +import io.sentry.hints.Hint; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public interface IEnvelopeSender { - void processEnvelopeFile(@NotNull String path, @Nullable Map hint); + void processEnvelopeFile(@NotNull String path, @NotNull Hint hint); } diff --git a/sentry/src/main/java/io/sentry/IHub.java b/sentry/src/main/java/io/sentry/IHub.java index 237d16387c..57946ae2cc 100644 --- a/sentry/src/main/java/io/sentry/IHub.java +++ b/sentry/src/main/java/io/sentry/IHub.java @@ -1,11 +1,11 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.Date; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,7 +28,7 @@ public interface IHub { * @return The Id (SentryId object) of the event */ @NotNull - SentryId captureEvent(@NotNull SentryEvent event, @Nullable Map hint); + SentryId captureEvent(@NotNull SentryEvent event, @Nullable Hint hint); /** * Captures the event. @@ -68,7 +68,7 @@ public interface IHub { * @return The Id (SentryId object) of the event */ @NotNull - SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Map hint); + SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint); /** * Captures an envelope. @@ -77,7 +77,7 @@ public interface IHub { * @return The Id (SentryId object) of the event */ default @NotNull SentryId captureEnvelope(@NotNull SentryEnvelope envelope) { - return captureEnvelope(envelope, null); + return captureEnvelope(envelope, new Hint()); } /** @@ -88,7 +88,7 @@ public interface IHub { * @return The Id (SentryId object) of the event */ @NotNull - SentryId captureException(@NotNull Throwable throwable, @Nullable Map hint); + SentryId captureException(@NotNull Throwable throwable, @Nullable Hint hint); /** * Captures the exception. @@ -122,7 +122,7 @@ public interface IHub { * @param breadcrumb the breadcrumb * @param hint SDK specific but provides high level information about the origin of the event */ - void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Map hint); + void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint); /** * Adds a breadcrumb to the current Scope @@ -130,7 +130,7 @@ public interface IHub { * @param breadcrumb the breadcrumb */ default void addBreadcrumb(@NotNull Breadcrumb breadcrumb) { - addBreadcrumb(breadcrumb, null); + addBreadcrumb(breadcrumb, new Hint()); } /** @@ -272,7 +272,7 @@ default void addBreadcrumb(@NotNull String message, @NotNull String category) { * * @param transaction the transaction * @param traceState the trace state - * @param hint the hint + * @param hint the hints * @param profilingTraceData the profiling trace data * @return transaction's id */ @@ -281,7 +281,7 @@ default void addBreadcrumb(@NotNull String message, @NotNull String category) { SentryId captureTransaction( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, - @Nullable Map hint, + @Nullable Hint hint, final @Nullable ProfilingTraceData profilingTraceData); /** @@ -289,7 +289,7 @@ SentryId captureTransaction( * * @param transaction the transaction * @param traceState the trace state - * @param hint the hint + * @param hint the hints * @return transaction's id */ @ApiStatus.Internal @@ -297,14 +297,13 @@ SentryId captureTransaction( default SentryId captureTransaction( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, - @Nullable Map hint) { + @Nullable Hint hint) { return captureTransaction(transaction, traceState, hint, null); } @ApiStatus.Internal @NotNull - default SentryId captureTransaction( - @NotNull SentryTransaction transaction, @Nullable Map hint) { + default SentryId captureTransaction(@NotNull SentryTransaction transaction, @Nullable Hint hint) { return captureTransaction(transaction, null, hint); } diff --git a/sentry/src/main/java/io/sentry/ISentryClient.java b/sentry/src/main/java/io/sentry/ISentryClient.java index 3c6c1a9e13..30ca742838 100644 --- a/sentry/src/main/java/io/sentry/ISentryClient.java +++ b/sentry/src/main/java/io/sentry/ISentryClient.java @@ -1,9 +1,9 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.Message; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,8 +27,7 @@ public interface ISentryClient { * @return The Id (SentryId object) of the event. */ @NotNull - SentryId captureEvent( - @NotNull SentryEvent event, @Nullable Scope scope, @Nullable Map hint); + SentryId captureEvent(@NotNull SentryEvent event, @Nullable Scope scope, @Nullable Hint hint); /** Flushes out the queue for up to timeout seconds and disable the client. */ void close(); @@ -68,8 +67,7 @@ SentryId captureEvent( * @param hint SDK specific but provides high level information about the origin of the event. * @return The Id (SentryId object) of the event. */ - default @NotNull SentryId captureEvent( - @NotNull SentryEvent event, @Nullable Map hint) { + default @NotNull SentryId captureEvent(@NotNull SentryEvent event, @Nullable Hint hint) { return captureEvent(event, null, hint); } @@ -122,7 +120,7 @@ SentryId captureEvent( * @return The Id (SentryId object) of the event */ default @NotNull SentryId captureException( - @NotNull Throwable throwable, @Nullable Scope scope, @Nullable Map hint) { + @NotNull Throwable throwable, @Nullable Scope scope, @Nullable Hint hint) { SentryEvent event = new SentryEvent(throwable); return captureEvent(event, scope, hint); } @@ -134,8 +132,7 @@ SentryId captureEvent( * @param hint SDK specific but provides high level information about the origin of the event * @return The Id (SentryId object) of the event */ - default @NotNull SentryId captureException( - @NotNull Throwable throwable, @Nullable Map hint) { + default @NotNull SentryId captureException(@NotNull Throwable throwable, @Nullable Hint hint) { return captureException(throwable, null, hint); } @@ -164,7 +161,7 @@ SentryId captureEvent( * @param hint SDK specific but provides high level information about the origin of the event * @param session the Session */ - void captureSession(@NotNull Session session, @Nullable Map hint); + void captureSession(@NotNull Session session, @Nullable Hint hint); /** * Captures a session. This method transform a session to an envelope and forwards to @@ -184,7 +181,7 @@ default void captureSession(@NotNull Session session) { * @return The Id (SentryId object) of the event */ @Nullable - SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Map hint); + SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint); /** * Captures an envelope. @@ -206,9 +203,7 @@ default void captureSession(@NotNull Session session) { */ @NotNull default SentryId captureTransaction( - @NotNull SentryTransaction transaction, - @Nullable Scope scope, - @Nullable Map hint) { + @NotNull SentryTransaction transaction, @Nullable Scope scope, @Nullable Hint hint) { return captureTransaction(transaction, null, scope, hint); } @@ -227,7 +222,7 @@ default SentryId captureTransaction( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, @Nullable Scope scope, - @Nullable Map hint) { + @Nullable Hint hint) { return captureTransaction(transaction, traceState, scope, hint, null); } @@ -247,7 +242,7 @@ SentryId captureTransaction( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, @Nullable Scope scope, - @Nullable Map hint, + @Nullable Hint hint, @Nullable ProfilingTraceData profilingTraceData); /** diff --git a/sentry/src/main/java/io/sentry/MainEventProcessor.java b/sentry/src/main/java/io/sentry/MainEventProcessor.java index d17450d892..83c0b56be0 100644 --- a/sentry/src/main/java/io/sentry/MainEventProcessor.java +++ b/sentry/src/main/java/io/sentry/MainEventProcessor.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.hints.Cached; +import io.sentry.hints.Hint; import io.sentry.protocol.DebugImage; import io.sentry.protocol.DebugMeta; import io.sentry.protocol.SentryException; @@ -64,8 +65,7 @@ public MainEventProcessor(final @NotNull SentryOptions options) { } @Override - public @NotNull SentryEvent process( - final @NotNull SentryEvent event, final @Nullable Map hint) { + public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) { setCommons(event); setExceptions(event); setDebugMeta(event); @@ -100,7 +100,7 @@ private void setDebugMeta(final @NotNull SentryEvent event) { } private boolean shouldApplyScopeData( - final @NotNull SentryBaseEvent event, final @Nullable Map hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { if (HintUtils.shouldApplyScopeData(hint)) { return true; } else { @@ -126,7 +126,7 @@ private void processNonCachedEvent(final @NotNull SentryBaseEvent event) { @Override public @NotNull SentryTransaction process( - final @NotNull SentryTransaction transaction, final @Nullable Map hint) { + final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { setCommons(transaction); if (shouldApplyScopeData(transaction, hint)) { @@ -213,8 +213,7 @@ private void setExceptions(final @NotNull SentryEvent event) { } } - private void setThreads( - final @NotNull SentryEvent event, final @Nullable Map hint) { + private void setThreads(final @NotNull SentryEvent event, final @NotNull Hint hint) { if (event.getThreads() == null) { // collecting threadIds that came from the exception mechanism, so we can mark threads as // crashed properly @@ -233,12 +232,11 @@ private void setThreads( } } - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); if (options.isAttachThreads()) { event.setThreads(sentryThreadFactory.getCurrentThreads(mechanismThreadIds)); } else if (options.isAttachStacktrace() && (eventExceptions == null || eventExceptions.isEmpty()) - && !isCachedHint(sentrySdkHint)) { + && !isCachedHint(hint)) { // when attachStacktrace is enabled, we attach only the current thread and its stack traces, // if there are no exceptions, exceptions have its own stack traces. event.setThreads(sentryThreadFactory.getCurrentThread()); @@ -250,11 +248,11 @@ private void setThreads( * If the event has a Cached Hint, it means that it came from the EnvelopeFileObserver. We don't * want to append the current thread to the event. * - * @param sentrySdkHint the Hint + * @param hint the Hints * @return true if Cached or false otherwise */ - private boolean isCachedHint(final @Nullable Object sentrySdkHint) { - return (sentrySdkHint instanceof Cached); + private boolean isCachedHint(final @NotNull Hint hint) { + return HintUtils.hasType(hint, Cached.class); } @Override diff --git a/sentry/src/main/java/io/sentry/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java index 29388043b6..4d9a5b3c2e 100644 --- a/sentry/src/main/java/io/sentry/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -1,11 +1,11 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.Date; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,8 +27,7 @@ public boolean isEnabled() { } @Override - public @NotNull SentryId captureEvent( - @NotNull SentryEvent event, @Nullable Map hint) { + public @NotNull SentryId captureEvent(@NotNull SentryEvent event, @Nullable Hint hint) { return SentryId.EMPTY_ID; } @@ -38,14 +37,12 @@ public boolean isEnabled() { } @Override - public @NotNull SentryId captureEnvelope( - @NotNull SentryEnvelope envelope, @Nullable Map hint) { + public @NotNull SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint) { return SentryId.EMPTY_ID; } @Override - public @NotNull SentryId captureException( - @NotNull Throwable throwable, @Nullable Map hint) { + public @NotNull SentryId captureException(@NotNull Throwable throwable, @Nullable Hint hint) { return SentryId.EMPTY_ID; } @@ -62,7 +59,7 @@ public void endSession() {} public void close() {} @Override - public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Map hint) {} + public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint) {} @Override public void setLevel(@Nullable SentryLevel level) {} @@ -123,7 +120,7 @@ public void flush(long timeoutMillis) {} public @NotNull SentryId captureTransaction( final @NotNull SentryTransaction transaction, final @Nullable TraceState traceState, - final @Nullable Map hint, + final @Nullable Hint hint, final @Nullable ProfilingTraceData profilingTraceData) { return SentryId.EMPTY_ID; } diff --git a/sentry/src/main/java/io/sentry/NoOpSentryClient.java b/sentry/src/main/java/io/sentry/NoOpSentryClient.java index b8eb1d598b..7916c1b899 100644 --- a/sentry/src/main/java/io/sentry/NoOpSentryClient.java +++ b/sentry/src/main/java/io/sentry/NoOpSentryClient.java @@ -1,8 +1,8 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +23,7 @@ public boolean isEnabled() { @Override public @NotNull SentryId captureEvent( - @NotNull SentryEvent event, @Nullable Scope scope, @Nullable Map hint) { + @NotNull SentryEvent event, @Nullable Scope scope, @Nullable Hint hint) { return SentryId.EMPTY_ID; } @@ -37,11 +37,10 @@ public void flush(long timeoutMillis) {} public void captureUserFeedback(@NotNull UserFeedback userFeedback) {} @Override - public void captureSession(@NotNull Session session, @Nullable Map hint) {} + public void captureSession(@NotNull Session session, @Nullable Hint hint) {} @Override - public SentryId captureEnvelope( - @NotNull SentryEnvelope envelope, @Nullable Map hint) { + public SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint) { return SentryId.EMPTY_ID; } @@ -50,7 +49,7 @@ public SentryId captureEnvelope( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, @Nullable Scope scope, - @Nullable Map hint, + @Nullable Hint hint, @Nullable ProfilingTraceData profilingTraceData) { return SentryId.EMPTY_ID; } diff --git a/sentry/src/main/java/io/sentry/OutboxSender.java b/sentry/src/main/java/io/sentry/OutboxSender.java index 5f9529292c..e653f170f8 100644 --- a/sentry/src/main/java/io/sentry/OutboxSender.java +++ b/sentry/src/main/java/io/sentry/OutboxSender.java @@ -4,6 +4,7 @@ import static io.sentry.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE; import io.sentry.hints.Flushable; +import io.sentry.hints.Hint; import io.sentry.hints.Resettable; import io.sentry.hints.Retryable; import io.sentry.hints.SubmissionResult; @@ -23,7 +24,6 @@ import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.Charset; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,7 +53,7 @@ public OutboxSender( } @Override - protected void processFile(final @NotNull File file, @Nullable Map hint) { + protected void processFile(final @NotNull File file, @NotNull Hint hint) { Objects.requireNonNull(file, "File is required."); if (!isRelevantFileName(file.getName())) { @@ -61,8 +61,6 @@ protected void processFile(final @NotNull File file, @Nullable Map { + if (!retryable.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()); + } } - } catch (RuntimeException e) { - logger.log(SentryLevel.ERROR, e, "Failed to delete: %s", file.getAbsolutePath()); - } - } - } else { - LogUtils.logIfNotRetryable(logger, sentrySdkHint); - } + }); } } @@ -101,14 +101,13 @@ protected boolean isRelevantFileName(final @Nullable String fileName) { } @Override - public void processEnvelopeFile(@NotNull String path, @Nullable Map hint) { + public void processEnvelopeFile(@NotNull String path, @NotNull Hint hint) { Objects.requireNonNull(path, "Path is required."); processFile(new File(path), hint); } - private void processEnvelope( - final @NotNull SentryEnvelope envelope, final @Nullable Map hint) + private void processEnvelope(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) throws IOException { logger.log( SentryLevel.DEBUG, @@ -116,8 +115,6 @@ private void processEnvelope( CollectionUtils.size(envelope.getItems())); int currentItem = 0; - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - for (final SentryEnvelopeItem item : envelope.getItems()) { currentItem++; @@ -141,7 +138,7 @@ private void processEnvelope( hub.captureEvent(event, hint); logItemCaptured(currentItem); - if (!waitFlush(sentrySdkHint)) { + if (!waitFlush(hint)) { logTimeout(event.getEventId()); break; } @@ -173,7 +170,7 @@ private void processEnvelope( hub.captureTransaction(transaction, envelope.getHeader().getTrace(), hint); logItemCaptured(currentItem); - if (!waitFlush(sentrySdkHint)) { + if (!waitFlush(hint)) { logTimeout(transaction.getEventId()); break; } @@ -193,7 +190,7 @@ private void processEnvelope( item.getHeader().getType().getItemType(), currentItem); - if (!waitFlush(sentrySdkHint)) { + if (!waitFlush(hint)) { logger.log( SentryLevel.WARNING, "Timed out waiting for item type submission: %s", @@ -202,6 +199,7 @@ private void processEnvelope( } } + final Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); if (sentrySdkHint instanceof SubmissionResult) { if (!((SubmissionResult) sentrySdkHint).isSuccess()) { // Failed to send an item of the envelope: Stop attempting to send the rest (an attachment @@ -215,9 +213,7 @@ private void processEnvelope( } // reset the Hint to its initial state as we use it multiple times. - if (sentrySdkHint instanceof Resettable) { - ((Resettable) sentrySdkHint).reset(); - } + HintUtils.runIfHasType(hint, Resettable.class, (resettable) -> resettable.reset()); } } @@ -247,11 +243,12 @@ private void logTimeout(final @Nullable SentryId eventId) { logger.log(SentryLevel.WARNING, "Timed out waiting for event id submission: %s", eventId); } - private boolean waitFlush(final @Nullable Object sentrySdkHint) { + private boolean waitFlush(final @NotNull Hint hint) { + @Nullable Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); if (sentrySdkHint instanceof Flushable) { return ((Flushable) sentrySdkHint).waitFlush(); } else { - LogUtils.logIfNotFlushable(logger, sentrySdkHint); + LogUtils.logNotInstanceOf(Flushable.class, sentrySdkHint, logger); } return true; } diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 6ee070f6c8..b2b60a699c 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -1,5 +1,6 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.Contexts; import io.sentry.protocol.Request; import io.sentry.protocol.User; @@ -288,13 +289,13 @@ Queue getBreadcrumbs() { * * @param callback the BeforeBreadcrumb callback * @param breadcrumb the breadcrumb - * @param hint the hint + * @param hint the hints * @return the mutated breadcrumb or null if dropped */ private @Nullable Breadcrumb executeBeforeBreadcrumb( final @NotNull SentryOptions.BeforeBreadcrumbCallback callback, @NotNull Breadcrumb breadcrumb, - final @Nullable Map hint) { + final @NotNull Hint hint) { try { breadcrumb = callback.execute(breadcrumb, hint); } catch (Throwable e) { @@ -319,11 +320,13 @@ Queue getBreadcrumbs() { * @param breadcrumb the breadcrumb * @param hint the hint */ - public void addBreadcrumb( - @NotNull Breadcrumb breadcrumb, final @Nullable Map hint) { + public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint) { if (breadcrumb == null) { return; } + if (hint == null) { + hint = new Hint(); + } SentryOptions.BeforeBreadcrumbCallback callback = options.getBeforeBreadcrumb(); if (callback != null) { diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 0da7d241db..6c63269664 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -2,6 +2,7 @@ import io.sentry.cache.EnvelopeCache; import io.sentry.config.PropertiesProviderFactory; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryId; import io.sentry.protocol.User; import io.sentry.util.FileUtils; @@ -9,7 +10,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.Date; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -285,7 +285,7 @@ public static synchronized void close() { * @return The Id (SentryId object) of the event */ public static @NotNull SentryId captureEvent( - final @NotNull SentryEvent event, final @Nullable Map hint) { + final @NotNull SentryEvent event, final @Nullable Hint hint) { return getCurrentHub().captureEvent(event, hint); } @@ -329,7 +329,7 @@ public static synchronized void close() { * @return The Id (SentryId object) of the event */ public static @NotNull SentryId captureException( - final @NotNull Throwable throwable, final @Nullable Map hint) { + final @NotNull Throwable throwable, final @Nullable Hint hint) { return getCurrentHub().captureException(throwable, hint); } @@ -349,7 +349,7 @@ public static void captureUserFeedback(final @NotNull UserFeedback userFeedback) * @param hint SDK specific but provides high level information about the origin of the event */ public static void addBreadcrumb( - final @NotNull Breadcrumb breadcrumb, final @Nullable Map hint) { + final @NotNull Breadcrumb breadcrumb, final @Nullable Hint hint) { getCurrentHub().addBreadcrumb(breadcrumb, hint); } diff --git a/sentry/src/main/java/io/sentry/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java index 269574ca64..4d8f4476b7 100644 --- a/sentry/src/main/java/io/sentry/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -1,10 +1,9 @@ package io.sentry; -import static io.sentry.TypeCheckHint.SENTRY_SCREENSHOT; - import io.sentry.clientreport.DiscardReason; import io.sentry.exception.SentryEnvelopeException; import io.sentry.hints.DiskFlushNotification; +import io.sentry.hints.Hint; import io.sentry.protocol.Contexts; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -59,7 +58,7 @@ public boolean isEnabled() { } private boolean shouldApplyScopeData( - final @NotNull SentryBaseEvent event, final @NotNull Map hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { if (HintUtils.shouldApplyScopeData(hint)) { return true; } else { @@ -72,11 +71,15 @@ private boolean shouldApplyScopeData( @Override public @NotNull SentryId captureEvent( - @NotNull SentryEvent event, final @Nullable Scope scope, @Nullable Map hint) { + @NotNull SentryEvent event, final @Nullable Scope scope, @Nullable Hint hint) { Objects.requireNonNull(event, "SentryEvent is required."); if (hint == null) { - hint = new HashMap<>(); + hint = new Hint(); + } + + if (shouldApplyScopeData(event, hint)) { + addScopeAttachmentsToHint(scope, hint); } options.getLogger().log(SentryLevel.DEBUG, "Capturing event: %s", event.getEventId()); @@ -172,7 +175,7 @@ private boolean shouldApplyScopeData( ? scope.getTransaction().traceState() : null; final boolean shouldSendAttachments = event != null; - List attachments = shouldSendAttachments ? getAttachments(scope, hint) : null; + List attachments = shouldSendAttachments ? getAttachments(hint) : null; final SentryEnvelope envelope = buildEnvelope(event, attachments, session, traceState, null); if (envelope != null) { @@ -188,6 +191,12 @@ private boolean shouldApplyScopeData( return sentryId; } + private void addScopeAttachmentsToHint(@Nullable Scope scope, @NotNull Hint hint) { + if (scope != null) { + hint.addAttachments(scope.getAttachments()); + } + } + private boolean shouldSendSessionUpdateForDroppedEvent( @Nullable Session sessionBeforeUpdate, @Nullable Session sessionAfterUpdate) { if (sessionAfterUpdate == null) { @@ -214,21 +223,12 @@ private boolean shouldSendSessionUpdateForDroppedEvent( return false; } - private @Nullable List getAttachments( - final @Nullable Scope scope, final @NotNull Map hint) { - List attachments = null; - if (scope != null) { - attachments = scope.getAttachments(); - } - - final Object screenshotAttachment = hint.get(SENTRY_SCREENSHOT); - if (screenshotAttachment instanceof Attachment) { + private @Nullable List getAttachments(final @NotNull Hint hint) { + @NotNull final List attachments = hint.getAttachments(); - if (attachments == null) { - attachments = new ArrayList<>(); - } - - attachments.add((Attachment) screenshotAttachment); + @Nullable final Attachment screenshot = hint.getScreenshot(); + if (screenshot != null) { + attachments.add(screenshot); } return attachments; @@ -285,7 +285,7 @@ private boolean shouldSendSessionUpdateForDroppedEvent( @Nullable private SentryEvent processEvent( @NotNull SentryEvent event, - final @NotNull Map hint, + final @NotNull Hint hint, final @NotNull List eventProcessors) { for (final EventProcessor processor : eventProcessors) { try { @@ -319,7 +319,7 @@ private SentryEvent processEvent( @Nullable private SentryTransaction processTransaction( @NotNull SentryTransaction transaction, - final @NotNull Map hint, + final @NotNull Hint hint, final @NotNull List eventProcessors) { for (final EventProcessor processor : eventProcessors) { try { @@ -399,9 +399,7 @@ public void captureUserFeedback(final @NotNull UserFeedback userFeedback) { @TestOnly @Nullable Session updateSessionData( - final @NotNull SentryEvent event, - final @Nullable Map hint, - final @Nullable Scope scope) { + final @NotNull SentryEvent event, final @NotNull Hint hint, final @Nullable Scope scope) { Session clonedSession = null; if (HintUtils.shouldApplyScopeData(hint)) { @@ -428,10 +426,9 @@ Session updateSessionData( } if (session.update(status, userAgent, crashedOrErrored)) { - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); // if hint is DiskFlushNotification, it means we have an uncaughtException // and we can end the session. - if (sentrySdkHint instanceof DiskFlushNotification) { + if (HintUtils.hasType(hint, DiskFlushNotification.class)) { session.end(); } } @@ -450,8 +447,7 @@ Session updateSessionData( @ApiStatus.Internal @Override - public void captureSession( - final @NotNull Session session, final @Nullable Map hint) { + public void captureSession(final @NotNull Session session, final @Nullable Hint hint) { Objects.requireNonNull(session, "Session is required."); if (session.getRelease() == null || session.getRelease().isEmpty()) { @@ -475,9 +471,13 @@ public void captureSession( @ApiStatus.Internal @Override public @NotNull SentryId captureEnvelope( - final @NotNull SentryEnvelope envelope, final @Nullable Map hint) { + final @NotNull SentryEnvelope envelope, @Nullable Hint hint) { Objects.requireNonNull(envelope, "SentryEnvelope is required."); + if (hint == null) { + hint = new Hint(); + } + try { transport.send(envelope, hint); } catch (IOException e) { @@ -497,12 +497,16 @@ public void captureSession( @NotNull SentryTransaction transaction, @Nullable TraceState traceState, final @Nullable Scope scope, - @Nullable Map hint, + @Nullable Hint hint, final @Nullable ProfilingTraceData profilingTraceData) { Objects.requireNonNull(transaction, "Transaction is required."); if (hint == null) { - hint = new HashMap<>(); + hint = new Hint(); + } + + if (shouldApplyScopeData(transaction, hint)) { + addScopeAttachmentsToHint(scope, hint); } options @@ -539,7 +543,7 @@ public void captureSession( final SentryEnvelope envelope = buildEnvelope( transaction, - filterForTransaction(getAttachments(scope, hint)), + filterForTransaction(getAttachments(hint)), null, traceState, profilingTraceData); @@ -574,9 +578,7 @@ public void captureSession( } private @Nullable SentryEvent applyScope( - @NotNull SentryEvent event, - final @Nullable Scope scope, - final @NotNull Map hint) { + @NotNull SentryEvent event, final @Nullable Scope scope, final @NotNull Hint hint) { if (scope != null) { applyScope(event, scope); @@ -654,7 +656,7 @@ private void sortBreadcrumbsByDate( } private @Nullable SentryEvent executeBeforeSend( - @NotNull SentryEvent event, final @NotNull Map hint) { + @NotNull SentryEvent event, final @NotNull Hint hint) { final SentryOptions.BeforeSendCallback beforeSend = options.getBeforeSend(); if (beforeSend != null) { try { diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 9c8eff7472..e36f06cad9 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -5,6 +5,7 @@ import io.sentry.clientreport.ClientReportRecorder; import io.sentry.clientreport.IClientReportRecorder; import io.sentry.clientreport.NoOpClientReportRecorder; +import io.sentry.hints.Hint; import io.sentry.protocol.SdkVersion; import io.sentry.transport.ITransportGate; import io.sentry.transport.NoOpEnvelopeCache; @@ -1624,11 +1625,11 @@ public interface BeforeSendCallback { * Mutates or drop an event before being sent * * @param event the event - * @param hint the hint, usually the source of the event + * @param hint the hints * @return the original event or the mutated event or null if event was dropped */ @Nullable - SentryEvent execute(@NotNull SentryEvent event, @Nullable Map hint); + SentryEvent execute(@NotNull SentryEvent event, @NotNull Hint hint); } /** The BeforeBreadcrumb callback */ @@ -1638,11 +1639,11 @@ public interface BeforeBreadcrumbCallback { * Mutates or drop a callback before being added * * @param breadcrumb the breadcrumb - * @param hint the hint, usually the source of the breadcrumb + * @param hint the hints, usually the source of the breadcrumb * @return the original breadcrumb or the mutated breadcrumb of null if breadcrumb was dropped */ @Nullable - Breadcrumb execute(@NotNull Breadcrumb breadcrumb, @Nullable Map hint); + Breadcrumb execute(@NotNull Breadcrumb breadcrumb, @NotNull Hint hint); } /** The traces sampler callback. */ diff --git a/sentry/src/main/java/io/sentry/SentryRuntimeEventProcessor.java b/sentry/src/main/java/io/sentry/SentryRuntimeEventProcessor.java index d031f0a61d..43cbea7824 100644 --- a/sentry/src/main/java/io/sentry/SentryRuntimeEventProcessor.java +++ b/sentry/src/main/java/io/sentry/SentryRuntimeEventProcessor.java @@ -1,8 +1,8 @@ package io.sentry; +import io.sentry.hints.Hint; import io.sentry.protocol.SentryRuntime; import io.sentry.protocol.SentryTransaction; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,14 +22,13 @@ public SentryRuntimeEventProcessor() { } @Override - public @NotNull SentryEvent process( - final @NotNull SentryEvent event, final @Nullable Map hint) { + public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @Nullable Hint hint) { return process(event); } @Override public @NotNull SentryTransaction process( - final @NotNull SentryTransaction transaction, final @Nullable Map hint) { + final @NotNull SentryTransaction transaction, final @Nullable Hint hint) { return process(transaction); } diff --git a/sentry/src/main/java/io/sentry/TypeCheckHint.java b/sentry/src/main/java/io/sentry/TypeCheckHint.java index 417e848943..a1631234cc 100644 --- a/sentry/src/main/java/io/sentry/TypeCheckHint.java +++ b/sentry/src/main/java/io/sentry/TypeCheckHint.java @@ -24,8 +24,6 @@ public final class TypeCheckHint { public static final String ANDROID_VIEW = "android:view"; /** Used for Fragment breadcrumbs. */ public static final String ANDROID_FRAGMENT = "android:fragment"; - /** Used for screenshots. */ - public static final String SENTRY_SCREENSHOT = "sentry:screenshot"; /** Used for OkHttp response breadcrumbs. */ public static final String OKHTTP_RESPONSE = "okHttp:response"; diff --git a/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java index 08671dd61a..965b3ff17b 100644 --- a/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java +++ b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java @@ -1,17 +1,16 @@ package io.sentry; import static io.sentry.SentryLevel.ERROR; -import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; import io.sentry.exception.ExceptionMechanismException; import io.sentry.hints.DiskFlushNotification; import io.sentry.hints.Flushable; +import io.sentry.hints.Hint; import io.sentry.hints.SessionEnd; import io.sentry.protocol.Mechanism; +import io.sentry.util.HintUtils; import io.sentry.util.Objects; import java.io.Closeable; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; @@ -91,18 +90,17 @@ public void uncaughtException(Thread thread, Throwable thrown) { options.getLogger().log(SentryLevel.INFO, "Uncaught exception received."); try { - final UncaughtExceptionHint hint = + final UncaughtExceptionHint exceptionHint = new UncaughtExceptionHint(options.getFlushTimeoutMillis(), options.getLogger()); final Throwable throwable = getUnhandledThrowable(thread, thrown); final SentryEvent event = new SentryEvent(throwable); event.setLevel(SentryLevel.FATAL); - final Map hintMap = new HashMap<>(); - hintMap.put(SENTRY_TYPE_CHECK_HINT, hint); + final Hint hint = HintUtils.createWithTypeCheckHint(exceptionHint); - hub.captureEvent(event, hintMap); + hub.captureEvent(event, hint); // Block until the event is flushed to disk - if (!hint.waitFlush()) { + if (!exceptionHint.waitFlush()) { options .getLogger() .log( diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index ad268702d5..5be26bf8a8 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -15,6 +15,7 @@ import io.sentry.SentryOptions; import io.sentry.Session; import io.sentry.hints.DiskFlushNotification; +import io.sentry.hints.Hint; import io.sentry.hints.SessionEnd; import io.sentry.hints.SessionStart; import io.sentry.transport.NoOpEnvelopeCache; @@ -78,22 +79,20 @@ private EnvelopeCache( } @Override - public void store( - final @NotNull SentryEnvelope envelope, final @Nullable Map hint) { + public void store(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) { Objects.requireNonNull(envelope, "Envelope is required."); rotateCacheIfNeeded(allEnvelopeFiles()); final File currentSessionFile = getCurrentSessionFile(); - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - if (sentrySdkHint instanceof SessionEnd) { + if (HintUtils.hasType(hint, SessionEnd.class)) { if (!currentSessionFile.delete()) { options.getLogger().log(WARNING, "Current envelope doesn't exist."); } } - if (sentrySdkHint instanceof SessionStart) { + if (HintUtils.hasType(hint, SessionStart.class)) { boolean crashedLastRun = false; // TODO: should we move this to AppLifecycleIntegration? and do on SDK init? but it's too much @@ -201,7 +200,7 @@ public void store( writeEnvelopeToDisk(envelopeFile, envelope); // write file to the disk when its about to crash so crashedLastRun can be marked on restart - if (sentrySdkHint instanceof DiskFlushNotification) { + if (HintUtils.hasType(hint, DiskFlushNotification.class)) { writeCrashMarkerFile(); } } diff --git a/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java index 0ada72ea86..9a6e7056cd 100644 --- a/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/IEnvelopeCache.java @@ -1,16 +1,15 @@ package io.sentry.cache; import io.sentry.SentryEnvelope; -import java.util.Map; +import io.sentry.hints.Hint; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public interface IEnvelopeCache extends Iterable { - void store(@NotNull SentryEnvelope envelope, @Nullable Map hint); + void store(@NotNull SentryEnvelope envelope, @NotNull Hint hint); default void store(@NotNull SentryEnvelope envelope) { - store(envelope, null); + store(envelope, new Hint()); } void discard(@NotNull SentryEnvelope envelope); diff --git a/sentry/src/main/java/io/sentry/hints/Hint.java b/sentry/src/main/java/io/sentry/hints/Hint.java new file mode 100644 index 0000000000..1e40302a83 --- /dev/null +++ b/sentry/src/main/java/io/sentry/hints/Hint.java @@ -0,0 +1,108 @@ +package io.sentry.hints; + +import io.sentry.Attachment; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class Hint { + + private static final @NotNull Map> PRIMITIVE_MAPPINGS; + + static { + PRIMITIVE_MAPPINGS = new HashMap<>(); + PRIMITIVE_MAPPINGS.put("boolean", Boolean.class); + PRIMITIVE_MAPPINGS.put("char", Character.class); + PRIMITIVE_MAPPINGS.put("byte", Byte.class); + PRIMITIVE_MAPPINGS.put("short", Short.class); + PRIMITIVE_MAPPINGS.put("int", Integer.class); + PRIMITIVE_MAPPINGS.put("long", Long.class); + PRIMITIVE_MAPPINGS.put("float", Float.class); + PRIMITIVE_MAPPINGS.put("double", Double.class); + } + + private final @NotNull Map internalStorage = new HashMap(); + private final @NotNull List attachments = new ArrayList<>(); + private @Nullable Attachment screenshot = null; + + public static @NotNull Hint withAttachment(@Nullable Attachment attachment) { + @NotNull final Hint hint = new Hint(); + hint.addAttachment(attachment); + return hint; + } + + public static @NotNull Hint withAttachments(@Nullable List attachments) { + @NotNull final Hint hint = new Hint(); + hint.addAttachments(attachments); + return hint; + } + + public void set(@NotNull String name, @Nullable Object hint) { + internalStorage.put(name, hint); + } + + public @Nullable Object get(@NotNull String name) { + return internalStorage.get(name); + } + + @SuppressWarnings("unchecked") + public @Nullable T getAs(@NotNull String name, @NotNull Class clazz) { + Object hintValue = internalStorage.get(name); + + if (clazz.isInstance(hintValue)) { + return (T) hintValue; + } else if (isCastablePrimitive(hintValue, clazz)) { + return (T) hintValue; + } else { + return null; + } + } + + public void remove(@NotNull String name) { + internalStorage.remove(name); + } + + public void addAttachment(@Nullable Attachment attachment) { + if (attachment != null) { + attachments.add(attachment); + } + } + + public void addAttachments(@Nullable List attachments) { + if (attachments != null) { + this.attachments.addAll(attachments); + } + } + + public @NotNull List getAttachments() { + return new ArrayList<>(attachments); + } + + public void replaceAttachments(@Nullable List attachments) { + clearAttachments(); + addAttachments(attachments); + } + + public void clearAttachments() { + attachments.clear(); + } + + public void setScreenshot(@Nullable Attachment screenshot) { + this.screenshot = screenshot; + } + + public @Nullable Attachment getScreenshot() { + return screenshot; + } + + private boolean isCastablePrimitive(@Nullable Object hintValue, @NotNull Class clazz) { + Class nonPrimitiveClass = PRIMITIVE_MAPPINGS.get(clazz.getCanonicalName()); + return hintValue != null + && clazz.isPrimitive() + && nonPrimitiveClass != null + && nonPrimitiveClass.isInstance(hintValue); + } +} diff --git a/sentry/src/main/java/io/sentry/transport/AsyncHttpTransport.java b/sentry/src/main/java/io/sentry/transport/AsyncHttpTransport.java index 32f5774813..e472cde84a 100644 --- a/sentry/src/main/java/io/sentry/transport/AsyncHttpTransport.java +++ b/sentry/src/main/java/io/sentry/transport/AsyncHttpTransport.java @@ -9,19 +9,18 @@ import io.sentry.clientreport.DiscardReason; import io.sentry.hints.Cached; import io.sentry.hints.DiskFlushNotification; +import io.sentry.hints.Hint; import io.sentry.hints.Retryable; import io.sentry.hints.SubmissionResult; import io.sentry.util.HintUtils; import io.sentry.util.LogUtils; import io.sentry.util.Objects; import java.io.IOException; -import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * {@link ITransport} implementation that executes request asynchronously in a blocking manner using @@ -66,19 +65,18 @@ public AsyncHttpTransport( } @Override - public void send(final @NotNull SentryEnvelope envelope, final @Nullable Map hint) + public void send(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) throws IOException { // For now no caching on envelopes IEnvelopeCache currentEnvelopeCache = envelopeCache; boolean cached = false; - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - if (sentrySdkHint instanceof Cached) { + if (HintUtils.hasType(hint, Cached.class)) { currentEnvelopeCache = NoOpEnvelopeCache.getInstance(); cached = true; options.getLogger().log(SentryLevel.DEBUG, "Captured Envelope is already cached"); } - final SentryEnvelope filteredEnvelope = rateLimiter.filter(envelope, sentrySdkHint); + final SentryEnvelope filteredEnvelope = rateLimiter.filter(envelope, hint); if (filteredEnvelope == null) { if (cached) { @@ -86,7 +84,7 @@ public void send(final @NotNull SentryEnvelope envelope, final @Nullable Map result.setResult(false)); + HintUtils.runIfHasType(hint, Retryable.class, retryable -> retryable.setRetry(retry)); } private static final class AsyncConnectionThreadFactory implements ThreadFactory { @@ -185,13 +177,13 @@ private static final class AsyncConnectionThreadFactory implements ThreadFactory private final class EnvelopeSender implements Runnable { private final @NotNull SentryEnvelope envelope; - private final @Nullable Map hint; + private final @NotNull Hint hint; private final @NotNull IEnvelopeCache envelopeCache; private final TransportResult failedResult = TransportResult.error(); EnvelopeSender( final @NotNull SentryEnvelope envelope, - final @Nullable Map hint, + final @NotNull Hint hint, final @NotNull IEnvelopeCache envelopeCache) { this.envelope = Objects.requireNonNull(envelope, "Envelope is required."); this.hint = hint; @@ -208,13 +200,19 @@ public void run() { options.getLogger().log(SentryLevel.ERROR, e, "Envelope submission failed"); throw e; } finally { - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - if (sentrySdkHint instanceof SubmissionResult) { - options - .getLogger() - .log(SentryLevel.DEBUG, "Marking envelope submission result: %s", result.isSuccess()); - ((SubmissionResult) sentrySdkHint).setResult(result.isSuccess()); - } + final TransportResult finalResult = result; + HintUtils.runIfHasType( + hint, + SubmissionResult.class, + (submissionResult) -> { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Marking envelope submission result: %s", + finalResult.isSuccess()); + submissionResult.setResult(finalResult.isSuccess()); + }); } } @@ -223,11 +221,13 @@ public void run() { envelopeCache.store(envelope, hint); - Object sentrySdkHint = HintUtils.getSentrySdkHint(hint); - if (sentrySdkHint instanceof DiskFlushNotification) { - ((DiskFlushNotification) sentrySdkHint).markFlushed(); - options.getLogger().log(SentryLevel.DEBUG, "Disk flush envelope fired"); - } + HintUtils.runIfHasType( + hint, + DiskFlushNotification.class, + (diskFlushNotification) -> { + diskFlushNotification.markFlushed(); + options.getLogger().log(SentryLevel.DEBUG, "Disk flush envelope fired"); + }); if (transportGate.isConnected()) { final SentryEnvelope envelopeWithClientReport = @@ -245,37 +245,48 @@ public void run() { // ignore e.g. 429 as we're not the ones actively dropping if (result.getResponseCode() >= 400 && result.getResponseCode() != 429) { - if (!(sentrySdkHint instanceof Retryable)) { - options - .getClientReportRecorder() - .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelopeWithClientReport); - } + HintUtils.runIfDoesNotHaveType( + hint, + Retryable.class, + (hint) -> { + options + .getClientReportRecorder() + .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelopeWithClientReport); + }); } throw new IllegalStateException(message); } } catch (IOException e) { // Failure due to IO is allowed to retry the event - if (sentrySdkHint instanceof Retryable) { - ((Retryable) sentrySdkHint).setRetry(true); - } else { - LogUtils.logIfNotRetryable(options.getLogger(), sentrySdkHint); - options - .getClientReportRecorder() - .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelopeWithClientReport); - } + HintUtils.runIfHasType( + hint, + Retryable.class, + (retryable) -> { + retryable.setRetry(true); + }, + (hint, clazz) -> { + LogUtils.logNotInstanceOf(clazz, hint, options.getLogger()); + options + .getClientReportRecorder() + .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelopeWithClientReport); + }); throw new IllegalStateException("Sending the event failed.", e); } } else { // If transportGate is blocking from sending, allowed to retry - if (sentrySdkHint instanceof Retryable) { - ((Retryable) sentrySdkHint).setRetry(true); - } else { - LogUtils.logIfNotRetryable(options.getLogger(), sentrySdkHint); - options - .getClientReportRecorder() - .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelope); - } + HintUtils.runIfHasType( + hint, + Retryable.class, + (retryable) -> { + retryable.setRetry(true); + }, + (hint, clazz) -> { + LogUtils.logNotInstanceOf(clazz, hint, options.getLogger()); + options + .getClientReportRecorder() + .recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelope); + }); } return result; } diff --git a/sentry/src/main/java/io/sentry/transport/ITransport.java b/sentry/src/main/java/io/sentry/transport/ITransport.java index b528e575f3..d2f755b8f4 100644 --- a/sentry/src/main/java/io/sentry/transport/ITransport.java +++ b/sentry/src/main/java/io/sentry/transport/ITransport.java @@ -1,19 +1,17 @@ package io.sentry.transport; import io.sentry.SentryEnvelope; +import io.sentry.hints.Hint; import java.io.Closeable; import java.io.IOException; -import java.util.Map; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** A transport is in charge of sending the event to the Sentry server. */ public interface ITransport extends Closeable { - void send(@NotNull SentryEnvelope envelope, @Nullable Map hint) - throws IOException; + void send(@NotNull SentryEnvelope envelope, @NotNull Hint hint) throws IOException; default void send(@NotNull SentryEnvelope envelope) throws IOException { - send(envelope, null); + send(envelope, new Hint()); } /** diff --git a/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java b/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java index 736cccb4af..7d638f5d6e 100644 --- a/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/transport/NoOpEnvelopeCache.java @@ -2,11 +2,10 @@ import io.sentry.SentryEnvelope; import io.sentry.cache.IEnvelopeCache; +import io.sentry.hints.Hint; import java.util.ArrayList; import java.util.Iterator; -import java.util.Map; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public final class NoOpEnvelopeCache implements IEnvelopeCache { private static final NoOpEnvelopeCache instance = new NoOpEnvelopeCache(); @@ -16,7 +15,7 @@ public static NoOpEnvelopeCache getInstance() { } @Override - public void store(@NotNull SentryEnvelope envelope, @Nullable Map hint) {} + public void store(@NotNull SentryEnvelope envelope, @NotNull Hint hint) {} @Override public void discard(@NotNull SentryEnvelope envelope) {} diff --git a/sentry/src/main/java/io/sentry/transport/NoOpTransport.java b/sentry/src/main/java/io/sentry/transport/NoOpTransport.java index 435e0edd50..fce2d7aefe 100644 --- a/sentry/src/main/java/io/sentry/transport/NoOpTransport.java +++ b/sentry/src/main/java/io/sentry/transport/NoOpTransport.java @@ -1,11 +1,10 @@ package io.sentry.transport; import io.sentry.SentryEnvelope; +import io.sentry.hints.Hint; import java.io.IOException; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; @ApiStatus.Internal public final class NoOpTransport implements ITransport { @@ -19,7 +18,7 @@ public final class NoOpTransport implements ITransport { private NoOpTransport() {} @Override - public void send(final @NotNull SentryEnvelope envelope, final @Nullable Map hint) + public void send(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) throws IOException {} @Override diff --git a/sentry/src/main/java/io/sentry/transport/RateLimiter.java b/sentry/src/main/java/io/sentry/transport/RateLimiter.java index 57203b6197..deec4326b3 100644 --- a/sentry/src/main/java/io/sentry/transport/RateLimiter.java +++ b/sentry/src/main/java/io/sentry/transport/RateLimiter.java @@ -9,8 +9,10 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.clientreport.DiscardReason; +import io.sentry.hints.Hint; import io.sentry.hints.Retryable; import io.sentry.hints.SubmissionResult; +import io.sentry.util.HintUtils; import io.sentry.util.StringUtils; import java.util.ArrayList; import java.util.Date; @@ -42,7 +44,7 @@ public RateLimiter(final @NotNull SentryOptions options) { } public @Nullable SentryEnvelope filter( - final @NotNull SentryEnvelope envelope, final @Nullable Object sentrySdkHint) { + final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) { // Optimize for/No allocations if no items are under 429 List dropItems = null; for (SentryEnvelopeItem item : envelope.getItems()) { @@ -76,7 +78,7 @@ public RateLimiter(final @NotNull SentryOptions options) { if (toSend.isEmpty()) { options.getLogger().log(SentryLevel.INFO, "Envelope discarded due all items rate limited."); - markHintWhenSendingFailed(sentrySdkHint, false); + markHintWhenSendingFailed(hint, false); return null; } @@ -86,19 +88,14 @@ public RateLimiter(final @NotNull SentryOptions options) { } /** - * It marks the hints when sending has failed, so it's not necessary to wait the timeout + * It marks the hint when sending has failed, so it's not necessary to wait the timeout * - * @param sentrySdkHint the Hint + * @param hint the Hints * @param retry if event should be retried or not */ - private static void markHintWhenSendingFailed( - final @Nullable Object sentrySdkHint, final boolean retry) { - if (sentrySdkHint instanceof SubmissionResult) { - ((SubmissionResult) sentrySdkHint).setResult(false); - } - if (sentrySdkHint instanceof Retryable) { - ((Retryable) sentrySdkHint).setRetry(retry); - } + private static void markHintWhenSendingFailed(final @NotNull Hint hint, final boolean retry) { + HintUtils.runIfHasType(hint, SubmissionResult.class, result -> result.setResult(false)); + HintUtils.runIfHasType(hint, Retryable.class, retryable -> retryable.setRetry(retry)); } /** diff --git a/sentry/src/main/java/io/sentry/transport/StdoutTransport.java b/sentry/src/main/java/io/sentry/transport/StdoutTransport.java index 2f3783f72b..1f035e0e34 100644 --- a/sentry/src/main/java/io/sentry/transport/StdoutTransport.java +++ b/sentry/src/main/java/io/sentry/transport/StdoutTransport.java @@ -2,11 +2,10 @@ import io.sentry.ISerializer; import io.sentry.SentryEnvelope; +import io.sentry.hints.Hint; import io.sentry.util.Objects; import java.io.IOException; -import java.util.Map; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public final class StdoutTransport implements ITransport { @@ -17,7 +16,7 @@ public StdoutTransport(final @NotNull ISerializer serializer) { } @Override - public void send(final @NotNull SentryEnvelope envelope, final @Nullable Map hint) + public void send(final @NotNull SentryEnvelope envelope, final @NotNull Hint hint) throws IOException { Objects.requireNonNull(envelope, "SentryEnvelope is required"); diff --git a/sentry/src/main/java/io/sentry/util/HintUtils.java b/sentry/src/main/java/io/sentry/util/HintUtils.java index ce6c36632c..73067c1568 100644 --- a/sentry/src/main/java/io/sentry/util/HintUtils.java +++ b/sentry/src/main/java/io/sentry/util/HintUtils.java @@ -2,34 +2,111 @@ import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; +import io.sentry.ILogger; import io.sentry.hints.ApplyScopeData; import io.sentry.hints.Cached; -import java.util.Map; +import io.sentry.hints.Hint; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -/** Util class for Applying or not scope's data to an event */ +/** Util class dealing with Hint as not to pollute the Hint API with internal functionality */ @ApiStatus.Internal public final class HintUtils { private HintUtils() {} + @ApiStatus.Internal + public static Hint createWithTypeCheckHint(Object typeCheckHint) { + Hint hint = new Hint(); + setTypeCheckHint(hint, typeCheckHint); + return hint; + } + + @ApiStatus.Internal + public static void setTypeCheckHint(@NotNull Hint hint, Object typeCheckHint) { + hint.set(SENTRY_TYPE_CHECK_HINT, typeCheckHint); + } + + @ApiStatus.Internal + public static @Nullable Object getSentrySdkHint(@NotNull Hint hint) { + return hint.get(SENTRY_TYPE_CHECK_HINT); + } + + @ApiStatus.Internal + public static boolean hasType(@NotNull Hint hint, @NotNull Class clazz) { + final Object sentrySdkHint = getSentrySdkHint(hint); + return clazz.isInstance(sentrySdkHint); + } + + @ApiStatus.Internal + public static void runIfDoesNotHaveType( + @NotNull Hint hint, @NotNull Class clazz, SentryNullableConsumer lambda) { + runIfHasType( + hint, + clazz, + (ignored) -> {}, + (value, clazz2) -> { + lambda.accept(value); + }); + } + + @ApiStatus.Internal + public static void runIfHasType( + @NotNull Hint hint, @NotNull Class clazz, SentryConsumer lambda) { + runIfHasType(hint, clazz, lambda, (value, clazz2) -> {}); + } + + @ApiStatus.Internal + public static void runIfHasTypeLogIfNot( + @NotNull Hint hint, @NotNull Class clazz, ILogger logger, SentryConsumer lambda) { + runIfHasType( + hint, + clazz, + lambda, + (sentrySdkHint, expectedClass) -> { + LogUtils.logNotInstanceOf(expectedClass, sentrySdkHint, logger); + }); + } + + @SuppressWarnings("unchecked") + @ApiStatus.Internal + public static void runIfHasType( + @NotNull Hint hint, + @NotNull Class clazz, + SentryConsumer lambda, + SentryHintFallback fallbackLambda) { + Object sentrySdkHint = getSentrySdkHint(hint); + if (hasType(hint, clazz) && sentrySdkHint != null) { + lambda.accept((T) sentrySdkHint); + } else { + fallbackLambda.accept(sentrySdkHint, clazz); + } + } + /** * Scope's data should be applied if: Hint is of the type ApplyScopeData or Hint is not Cached * (this includes a null hint) * - * @param hint the hint * @return true if it should apply scope's data or false otherwise */ - public static boolean shouldApplyScopeData(final @Nullable Map hint) { - Object SentrySdkHint = getSentrySdkHint(hint); - return (!(SentrySdkHint instanceof Cached) || (SentrySdkHint instanceof ApplyScopeData)); + @ApiStatus.Internal + public static boolean shouldApplyScopeData(@NotNull Hint hint) { + return !hasType(hint, Cached.class) || hasType(hint, ApplyScopeData.class); } - public static @Nullable Object getSentrySdkHint(final @Nullable Map hint) { - if (hint == null) { - return null; - } - return hint.get(SENTRY_TYPE_CHECK_HINT); + @FunctionalInterface + public interface SentryConsumer { + void accept(@NotNull T t); + } + + @FunctionalInterface + public interface SentryNullableConsumer { + void accept(@Nullable T t); + } + + @FunctionalInterface + public interface SentryHintFallback { + void accept(@Nullable Object sentrySdkHint, @NotNull Class clazz); } } diff --git a/sentry/src/main/java/io/sentry/util/LogUtils.java b/sentry/src/main/java/io/sentry/util/LogUtils.java index c594ec1d12..3316b1dce7 100644 --- a/sentry/src/main/java/io/sentry/util/LogUtils.java +++ b/sentry/src/main/java/io/sentry/util/LogUtils.java @@ -9,19 +9,14 @@ @ApiStatus.Internal public final class LogUtils { - public static void logIfNotFlushable( - final @NotNull ILogger logger, final @Nullable Object sentrySdkHint) { + public static void logNotInstanceOf( + final @NotNull Class expectedClass, + final @Nullable Object sentrySdkHint, + final @NotNull ILogger logger) { logger.log( SentryLevel.DEBUG, - "%s is not Flushable", - sentrySdkHint != null ? sentrySdkHint.getClass().getCanonicalName() : "Hint"); - } - - public static void logIfNotRetryable( - final @NotNull ILogger logger, final @Nullable Object sentrySdkHint) { - logger.log( - SentryLevel.DEBUG, - "%s is not Retryable", - sentrySdkHint != null ? sentrySdkHint.getClass().getCanonicalName() : "Hint"); + "%s is not %s", + sentrySdkHint != null ? sentrySdkHint.getClass().getCanonicalName() : "Hint", + expectedClass.getCanonicalName()); } } diff --git a/sentry/src/test/java/io/sentry/CustomEventProcessor.kt b/sentry/src/test/java/io/sentry/CustomEventProcessor.kt index a519c9983f..a6ed0afc07 100644 --- a/sentry/src/test/java/io/sentry/CustomEventProcessor.kt +++ b/sentry/src/test/java/io/sentry/CustomEventProcessor.kt @@ -1,5 +1,7 @@ package io.sentry +import io.sentry.hints.Hint + class CustomEventProcessor : EventProcessor { - override fun process(event: SentryEvent, hint: Map?): SentryEvent? = null + override fun process(event: SentryEvent, hint: Hint): SentryEvent? = null } diff --git a/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt b/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt index 42783d5bfa..0f9fee4d37 100644 --- a/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/DirectoryProcessorTest.kt @@ -9,6 +9,7 @@ import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import io.sentry.hints.ApplyScopeData import io.sentry.protocol.User +import io.sentry.util.HintUtils import io.sentry.util.noFlushTimeout import java.io.File import java.nio.file.Files @@ -66,7 +67,7 @@ class DirectoryProcessorTest { whenever(fixture.serializer.deserialize(any(), eq(SentryEvent::class.java))).thenReturn(event) fixture.getSut().processDirectory(file) - verify(fixture.hub).captureEvent(any(), argWhere { it !is ApplyScopeData }) + verify(fixture.hub).captureEvent(any(), argWhere { !HintUtils.hasType(it, ApplyScopeData::class.java) }) } @Test diff --git a/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt b/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt index 22e569cc6a..e8fb213a5f 100644 --- a/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/DuplicateEventDetectionEventProcessorTest.kt @@ -1,6 +1,7 @@ package io.sentry import io.sentry.exception.ExceptionMechanismException +import io.sentry.hints.Hint import io.sentry.protocol.Mechanism import java.lang.RuntimeException import kotlin.test.Test @@ -25,9 +26,12 @@ class DuplicateEventDetectionEventProcessorTest { @Test fun `does not drop event if no previous event with same exception was processed`() { val processor = fixture.getSut() - processor.process(SentryEvent(), null) + processor.process(SentryEvent(), Hint()) - val result = processor.process(SentryEvent(RuntimeException()), null) + val result = processor.process( + SentryEvent(RuntimeException()), + Hint() + ) assertNotNull(result) } @@ -36,9 +40,9 @@ class DuplicateEventDetectionEventProcessorTest { fun `drops event with the same exception`() { val processor = fixture.getSut() val event = SentryEvent(RuntimeException()) - processor.process(event, null) + processor.process(event, Hint()) - val result = processor.process(event, null) + val result = processor.process(event, Hint()) assertNull(result) } @@ -46,9 +50,12 @@ class DuplicateEventDetectionEventProcessorTest { fun `drops event with mechanism exception having an exception that has already been processed`() { val processor = fixture.getSut() val event = SentryEvent(RuntimeException()) - processor.process(event, null) + processor.process(event, Hint()) - val result = processor.process(SentryEvent(ExceptionMechanismException(Mechanism(), event.throwable!!, Thread.currentThread())), null) + val result = processor.process( + SentryEvent(ExceptionMechanismException(Mechanism(), event.throwable!!, Thread.currentThread())), + Hint() + ) assertNull(result) } @@ -56,9 +63,12 @@ class DuplicateEventDetectionEventProcessorTest { fun `drops event with exception that has already been processed with event with mechanism exception`() { val processor = fixture.getSut() val sentryEvent = SentryEvent(ExceptionMechanismException(Mechanism(), RuntimeException(), Thread.currentThread())) - processor.process(sentryEvent, null) + processor.process(sentryEvent, Hint()) - val result = processor.process(SentryEvent((sentryEvent.throwable as ExceptionMechanismException).throwable), null) + val result = processor.process( + SentryEvent((sentryEvent.throwable as ExceptionMechanismException).throwable), + Hint() + ) assertNull(result) } @@ -67,9 +77,12 @@ class DuplicateEventDetectionEventProcessorTest { fun `drops event with the cause equal to exception in already processed event`() { val processor = fixture.getSut() val event = SentryEvent(RuntimeException()) - processor.process(event, null) + processor.process(event, Hint()) - val result = processor.process(SentryEvent(RuntimeException(event.throwable)), null) + val result = processor.process( + SentryEvent(RuntimeException(event.throwable)), + Hint() + ) assertNull(result) } @@ -78,9 +91,12 @@ class DuplicateEventDetectionEventProcessorTest { fun `drops event with any of the causes has been already processed`() { val processor = fixture.getSut() val event = SentryEvent(RuntimeException()) - processor.process(event, null) + processor.process(event, Hint()) - val result = processor.process(SentryEvent(RuntimeException(RuntimeException(event.throwable))), null) + val result = processor.process( + SentryEvent(RuntimeException(RuntimeException(event.throwable))), + Hint() + ) assertNull(result) } @@ -89,7 +105,7 @@ class DuplicateEventDetectionEventProcessorTest { fun `does not deduplicate is deduplication is disabled`() { val processor = fixture.getSut(enableDeduplication = false) val event = SentryEvent(RuntimeException()) - assertNotNull(processor.process(event, null)) - assertNotNull(processor.process(event, null)) + assertNotNull(processor.process(event, Hint())) + assertNotNull(processor.process(event, Hint())) } } diff --git a/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt b/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt index f9451945a7..d141a0afec 100644 --- a/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt +++ b/sentry/src/test/java/io/sentry/EnvelopeSenderTest.kt @@ -7,9 +7,10 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.cache.EnvelopeCache +import io.sentry.hints.Hint import io.sentry.hints.Retryable +import io.sentry.util.HintUtils import io.sentry.util.noFlushTimeout import java.io.File import java.nio.file.Files @@ -97,8 +98,8 @@ class EnvelopeSenderTest { val testFile = File(Files.createTempFile(tempDirectory, "send-cached-event-test", EnvelopeCache.SUFFIX_ENVELOPE_FILE).toUri()) testFile.deleteOnExit() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processFile(testFile, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processFile(testFile, hints) 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()) @@ -111,7 +112,7 @@ class EnvelopeSenderTest { 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()) + sut.processFile(testFile, Hint()) 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/src/test/java/io/sentry/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt index 05c12363be..22b260d790 100644 --- a/sentry/src/test/java/io/sentry/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -14,11 +14,11 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.cache.EnvelopeCache import io.sentry.clientreport.ClientReportTestHelper.Companion.assertClientReport import io.sentry.clientreport.DiscardReason import io.sentry.clientreport.DiscardedEvent +import io.sentry.hints.Hint import io.sentry.hints.SessionEndHint import io.sentry.hints.SessionStartHint import io.sentry.protocol.SentryId @@ -266,7 +266,7 @@ class HubTest { sut.close() sut.captureEvent(SentryEvent()) - verify(mockClient, never()).captureEvent(any(), any>()) + verify(mockClient, never()).captureEvent(any(), any()) } @Test @@ -274,9 +274,9 @@ class HubTest { val (sut, mockClient) = getEnabledHub() val event = SentryEvent() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } @Test @@ -284,11 +284,11 @@ class HubTest { val (sut, mockClient) = getEnabledHub() whenever(mockClient.captureEvent(any(), any(), anyOrNull())).thenReturn(SentryId(UUID.randomUUID())) val event = SentryEvent() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) val lastEventId = sut.lastEventId sut.close() - sut.captureEvent(event, hintsMap) + sut.captureEvent(event, hints) assertEquals(lastEventId, sut.lastEventId) } @@ -297,9 +297,9 @@ class HubTest { val (sut, mockClient) = getEnabledHub() val event = SentryEvent() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) verify(mockClient, never()).captureSession(any(), any()) } @@ -308,9 +308,9 @@ class HubTest { val (sut, mockClient) = getEnabledHub() val event = SentryEvent() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) verify(mockClient, never()).captureSession(any(), any()) } @@ -324,10 +324,10 @@ class HubTest { val event = SentryEvent(exception) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) assertEquals(span.spanContext, event.contexts.trace) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } @Test @@ -340,10 +340,10 @@ class HubTest { val event = SentryEvent(RuntimeException(rootCause)) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) assertEquals(span.spanContext, event.contexts.trace) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } @Test @@ -357,10 +357,10 @@ class HubTest { val event = SentryEvent(RuntimeException(exceptionAssignedToSpan)) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) assertEquals(span.spanContext, event.contexts.trace) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } @Test @@ -375,10 +375,10 @@ class HubTest { val originalSpanContext = SpanContext("op") event.contexts.trace = originalSpanContext - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) assertEquals(originalSpanContext, event.contexts.trace) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } @Test @@ -387,10 +387,10 @@ class HubTest { val event = SentryEvent(RuntimeException()) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to { }) - sut.captureEvent(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureEvent(event, hints) assertNull(event.contexts.trace) - verify(mockClient).captureEvent(eq(event), any(), eq(hintsMap)) + verify(mockClient).captureEvent(eq(event), any(), eq(hints)) } //endregion @@ -456,8 +456,8 @@ class HubTest { fun `when captureException is called with a valid argument and hint, captureEvent on the client should be called`() { val (sut, mockClient) = getEnabledHub() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to Object()) - sut.captureException(Throwable(), hintsMap) + val hints = HintUtils.createWithTypeCheckHint({}) + sut.captureException(Throwable(), hints) verify(mockClient).captureEvent(any(), any(), any()) } @@ -974,7 +974,7 @@ class HubTest { sut.bindClient(mockClient) sut.startSession() - verify(mockClient).captureSession(any(), argWhere { HintUtils.getSentrySdkHint(it) is SessionStartHint }) + verify(mockClient).captureSession(any(), argWhere { HintUtils.hasType(it, SessionStartHint::class.java) }) } @Test @@ -990,8 +990,8 @@ class HubTest { sut.startSession() sut.startSession() - verify(mockClient).captureSession(any(), argWhere { HintUtils.getSentrySdkHint(it) is SessionEndHint }) - verify(mockClient, times(2)).captureSession(any(), argWhere { HintUtils.getSentrySdkHint(it) is SessionStartHint }) + verify(mockClient).captureSession(any(), argWhere { HintUtils.hasType(it, SessionEndHint::class.java) }) + verify(mockClient, times(2)).captureSession(any(), argWhere { HintUtils.hasType(it, SessionStartHint::class.java) }) } //endregion @@ -1040,8 +1040,8 @@ class HubTest { sut.startSession() sut.endSession() - verify(mockClient).captureSession(any(), argWhere { HintUtils.getSentrySdkHint(it) is SessionStartHint }) - verify(mockClient).captureSession(any(), argWhere { HintUtils.getSentrySdkHint(it) is SessionEndHint }) + verify(mockClient).captureSession(any(), argWhere { HintUtils.hasType(it, SessionStartHint::class.java) }) + verify(mockClient).captureSession(any(), argWhere { HintUtils.hasType(it, SessionEndHint::class.java) }) } @Test diff --git a/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt b/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt index 8ad57d829e..970eb936d6 100644 --- a/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt +++ b/sentry/src/test/java/io/sentry/MainEventProcessorTest.kt @@ -5,12 +5,13 @@ import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.hints.ApplyScopeData +import io.sentry.hints.Hint import io.sentry.protocol.DebugMeta import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User +import io.sentry.util.HintUtils import org.awaitility.kotlin.await import java.lang.RuntimeException import java.net.InetAddress @@ -64,7 +65,7 @@ class MainEventProcessorTest { val crashedThread = Thread.currentThread() var event = generateCrashedEvent(crashedThread) - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.exceptions) { assertSame(crashedThread.id, it.first().threadId) @@ -85,7 +86,7 @@ class MainEventProcessorTest { val crashedThread = Thread() var event = generateCrashedEvent(crashedThread) - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.threads) { threads -> assertTrue(threads.any { it.isCrashed == true }) @@ -97,7 +98,7 @@ class MainEventProcessorTest { val sut = fixture.getSut() val crashedThread = Thread.currentThread() var event = generateCrashedEvent(crashedThread) - event = sut.process(event, null) + event = sut.process(event, Hint()) assertEquals("release", event.release) assertEquals("environment", event.environment) @@ -113,8 +114,8 @@ class MainEventProcessorTest { val sut = fixture.getSut() val crashedThread = Thread.currentThread() var event = generateCrashedEvent(crashedThread) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - event = sut.process(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + event = sut.process(event, hints) assertEquals("release", event.release) assertEquals("environment", event.environment) @@ -134,7 +135,7 @@ class MainEventProcessorTest { event.release = "eventRelease" event.serverName = "eventServerName" - event = sut.process(event, null) + event = sut.process(event, Hint()) assertEquals("eventRelease", event.release) assertEquals("eventEnvironment", event.environment) @@ -148,8 +149,8 @@ class MainEventProcessorTest { val crashedThread = Thread.currentThread() var event = generateCrashedEvent(crashedThread) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - event = sut.process(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + event = sut.process(event, hints) assertNull(event.release) assertNull(event.environment) @@ -164,8 +165,8 @@ class MainEventProcessorTest { val crashedThread = Thread.currentThread() var event = generateCrashedEvent(crashedThread) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CustomCachedApplyScopeDataHint()) - event = sut.process(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CustomCachedApplyScopeDataHint()) + event = sut.process(event, hints) assertEquals("release", event.release) assertEquals("environment", event.environment) @@ -181,7 +182,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(attachThreads = false, attachStackTrace = false) var event = SentryEvent() - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNull(event.threads) } @@ -191,7 +192,7 @@ class MainEventProcessorTest { val sut = fixture.getSut() var event = SentryEvent() - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.threads) } @@ -201,7 +202,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(attachThreads = false, attachStackTrace = true) var event = SentryEvent() - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.threads) { assertEquals(1, it.count()) @@ -213,7 +214,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(attachThreads = false, attachStackTrace = true) var event = SentryEvent(RuntimeException("error")) - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNull(event.threads) } @@ -222,7 +223,7 @@ class MainEventProcessorTest { fun `sets sdkVersion in the event`() { val sut = fixture.getSut() val event = SentryEvent() - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.sdk) { assertEquals(it.name, "test") assertEquals(it.version, "1.2.3") @@ -233,7 +234,7 @@ class MainEventProcessorTest { fun `when event and SentryOptions do not have environment set, sets production as environment`() { val sut = fixture.getSut(environment = null) val event = SentryEvent() - sut.process(event, null) + sut.process(event, Hint()) assertEquals("production", event.environment) } @@ -241,7 +242,7 @@ class MainEventProcessorTest { fun `when event does not have ip address set and sendDefaultPii is set to true, sets {{auto}} as the ip address`() { val sut = fixture.getSut(sendDefaultPii = true) val event = SentryEvent() - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.user) { assertEquals("{{auto}}", it.ipAddress) } @@ -254,7 +255,7 @@ class MainEventProcessorTest { event.user = User().apply { ipAddress = "192.168.0.1" } - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.user) { assertEquals("192.168.0.1", it.ipAddress) } @@ -265,7 +266,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(sendDefaultPii = false) val event = SentryEvent() event.user = User() - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.user) { assertNull(it.ipAddress) } @@ -276,7 +277,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(environment = null) val event = SentryEvent() event.environment = "staging" - sut.process(event, null) + sut.process(event, Hint()) assertEquals("staging", event.environment) } @@ -284,7 +285,7 @@ class MainEventProcessorTest { fun `when event does not have environment set and SentryOptions have environment set, uses environment from SentryOptions`() { val sut = fixture.getSut(environment = "custom") val event = SentryEvent() - sut.process(event, null) + sut.process(event, Hint()) assertEquals("custom", event.environment) } @@ -292,7 +293,7 @@ class MainEventProcessorTest { fun `sets tags from SentryOptions`() { val sut = fixture.getSut(tags = mapOf("tag1" to "value1", "tag2" to "value2")) val event = SentryEvent() - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.tags) { assertEquals("value1", it["tag1"]) assertEquals("value2", it["tag2"]) @@ -304,7 +305,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(tags = mapOf("tag1" to "value1", "tag2" to "value2")) val event = SentryEvent() event.setTag("tag2", "event-tag-value") - sut.process(event, null) + sut.process(event, Hint()) assertNotNull(event.tags) { assertEquals("value1", it["tag1"]) assertEquals("event-tag-value", it["tag2"]) @@ -315,7 +316,7 @@ class MainEventProcessorTest { fun `sets servername retrieved from the local address`() { val processor = fixture.getSut(serverName = null, host = "aHost") val event = SentryEvent() - processor.process(event, null) + processor.process(event, Hint()) assertEquals("aHost", event.serverName) } @@ -323,7 +324,7 @@ class MainEventProcessorTest { fun `sets servername to null if retrieving takes longer time`() { val processor = fixture.getSut(serverName = null, host = "aHost", resolveHostDelay = 2000) val event = SentryEvent() - processor.process(event, null) + processor.process(event, Hint()) assertNull(event.serverName) } @@ -331,10 +332,10 @@ class MainEventProcessorTest { fun `uses cache to retrieve servername for subsequent events`() { val processor = fixture.getSut(serverName = null, host = "aHost", hostnameCacheDuration = 1000) val firstEvent = SentryEvent() - processor.process(firstEvent, null) + processor.process(firstEvent, Hint()) assertEquals("aHost", firstEvent.serverName) val secondEvent = SentryEvent() - processor.process(secondEvent, null) + processor.process(secondEvent, Hint()) assertEquals("aHost", secondEvent.serverName) verify(fixture.getLocalhost, times(1)).canonicalHostName } @@ -343,7 +344,7 @@ class MainEventProcessorTest { fun `when cache expires, retrieves new host name from the local address`() { val processor = fixture.getSut(serverName = null, host = "aHost") val firstEvent = SentryEvent() - processor.process(firstEvent, null) + processor.process(firstEvent, Hint()) assertEquals("aHost", firstEvent.serverName) reset(fixture.getLocalhost) @@ -351,7 +352,7 @@ class MainEventProcessorTest { await.untilAsserted { val secondEvent = SentryEvent() - processor.process(secondEvent, null) + processor.process(secondEvent, Hint()) assertEquals("newHost", secondEvent.serverName) } } @@ -361,7 +362,7 @@ class MainEventProcessorTest { val processor = fixture.getSut(serverName = null, host = "aHost") val event = SentryEvent() event.serverName = "eventHost" - processor.process(event, null) + processor.process(event, Hint()) assertEquals("eventHost", event.serverName) } @@ -369,7 +370,7 @@ class MainEventProcessorTest { fun `does not set serverName on events if serverName is set on SentryOptions`() { val processor = fixture.getSut(serverName = "optionsHost", host = "aHost") val event = SentryEvent() - processor.process(event, null) + processor.process(event, Hint()) assertEquals("optionsHost", event.serverName) } @@ -378,7 +379,7 @@ class MainEventProcessorTest { val processor = fixture.getSut(serverName = "optionsHost") var transaction = SentryTransaction(fixture.sentryTracer) - transaction = processor.process(transaction, null) + transaction = processor.process(transaction, Hint()) assertEquals("optionsHost", transaction.serverName) } @@ -388,7 +389,7 @@ class MainEventProcessorTest { val processor = fixture.getSut() var transaction = SentryTransaction(fixture.sentryTracer) - transaction = processor.process(transaction, null) + transaction = processor.process(transaction, Hint()) assertEquals("dist", transaction.dist) } @@ -398,7 +399,7 @@ class MainEventProcessorTest { val processor = fixture.getSut(sendDefaultPii = true) var transaction = SentryTransaction(fixture.sentryTracer) - transaction = processor.process(transaction, null) + transaction = processor.process(transaction, Hint()) assertNotNull(transaction.user) } @@ -409,8 +410,8 @@ class MainEventProcessorTest { var event = SentryEvent() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CustomCachedApplyScopeDataHint()) - event = sut.process(event, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CustomCachedApplyScopeDataHint()) + event = sut.process(event, hints) assertNull(event.threads) } @@ -420,7 +421,7 @@ class MainEventProcessorTest { val sut = fixture.getSut(proguardUuid = "id1") var event = SentryEvent() - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.debugMeta) { assertNotNull(it.images) { images -> @@ -436,7 +437,7 @@ class MainEventProcessorTest { var event = SentryEvent() event.debugMeta = DebugMeta() - event = sut.process(event, null) + event = sut.process(event, Hint()) assertNotNull(event.debugMeta) { assertNotNull(it.images) { images -> diff --git a/sentry/src/test/java/io/sentry/NoOpHubTest.kt b/sentry/src/test/java/io/sentry/NoOpHubTest.kt index 75529bd173..0c9c904e16 100644 --- a/sentry/src/test/java/io/sentry/NoOpHubTest.kt +++ b/sentry/src/test/java/io/sentry/NoOpHubTest.kt @@ -1,6 +1,7 @@ package io.sentry import com.nhaarman.mockitokotlin2.mock +import io.sentry.hints.Hint import io.sentry.protocol.SentryId import kotlin.test.Test import kotlin.test.assertEquals @@ -29,7 +30,7 @@ class NoOpHubTest { @Test fun `captureTransaction returns empty SentryId`() = - assertEquals(SentryId.EMPTY_ID, sut.captureTransaction(mock(), mock>())) + assertEquals(SentryId.EMPTY_ID, sut.captureTransaction(mock(), mock())) @Test fun `captureException returns empty SentryId`() = diff --git a/sentry/src/test/java/io/sentry/OutboxSenderTest.kt b/sentry/src/test/java/io/sentry/OutboxSenderTest.kt index 00a91e66bf..acc5ccce53 100644 --- a/sentry/src/test/java/io/sentry/OutboxSenderTest.kt +++ b/sentry/src/test/java/io/sentry/OutboxSenderTest.kt @@ -9,11 +9,11 @@ import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.spy import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.cache.EnvelopeCache import io.sentry.hints.Retryable import io.sentry.protocol.SentryId import io.sentry.protocol.SentryTransaction +import io.sentry.util.HintUtils import java.io.File import java.io.FileNotFoundException import java.nio.file.Files @@ -62,8 +62,8 @@ class OutboxSenderTest { val path = getTempEnvelope() assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) assertFalse(File(path).exists()) // Additionally make sure we have a error logged verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) @@ -78,8 +78,8 @@ class OutboxSenderTest { val path = getTempEnvelope() assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) verify(fixture.hub).captureEvent(eq(expected), any()) assertFalse(File(path).exists()) @@ -115,8 +115,8 @@ class OutboxSenderTest { val path = getTempEnvelope(fileName = "envelope-transaction.txt") assertTrue(File(path).exists()) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) verify(fixture.hub).captureTransaction( check { @@ -144,8 +144,8 @@ class OutboxSenderTest { val path = getTempEnvelope() assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) verify(fixture.hub).captureEvent(any(), any()) assertFalse(File(path).exists()) @@ -162,8 +162,8 @@ class OutboxSenderTest { val path = getTempEnvelope(fileName = "envelope_attachment.txt") assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) verify(fixture.hub).captureEnvelope(any(), any()) assertFalse(File(path).exists()) @@ -180,8 +180,8 @@ class OutboxSenderTest { val path = getTempEnvelope() assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) // Additionally make sure we have no errors logged verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) @@ -198,8 +198,8 @@ class OutboxSenderTest { val path = getTempEnvelope() assertTrue(File(path).exists()) // sanity check - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(path, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(path, hints) // Additionally make sure we have no errors logged verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), any()) @@ -211,8 +211,8 @@ class OutboxSenderTest { fun `when processEnvelopeFile is called with a invalid path, logs error`() { val sut = fixture.getSut() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.processEnvelopeFile(File.separator + "i-hope-it-doesnt-exist" + File.separator + "file.txt", hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.processEnvelopeFile(File.separator + "i-hope-it-doesnt-exist" + File.separator + "file.txt", hints) verify(fixture.logger).log(eq(SentryLevel.ERROR), any(), argWhere { it is FileNotFoundException }) } diff --git a/sentry/src/test/java/io/sentry/ScopeTest.kt b/sentry/src/test/java/io/sentry/ScopeTest.kt index 3b65bb065d..bb1fb37b4f 100644 --- a/sentry/src/test/java/io/sentry/ScopeTest.kt +++ b/sentry/src/test/java/io/sentry/ScopeTest.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify +import io.sentry.hints.Hint import io.sentry.protocol.Request import io.sentry.protocol.User import io.sentry.test.callMethod @@ -858,7 +859,7 @@ class ScopeTest { private fun eventProcessor(): EventProcessor { return object : EventProcessor { - override fun process(event: SentryEvent, hint: MutableMap?): SentryEvent? { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { return event } } diff --git a/sentry/src/test/java/io/sentry/SentryClientTest.kt b/sentry/src/test/java/io/sentry/SentryClientTest.kt index 853f4de4b7..41f85ced34 100644 --- a/sentry/src/test/java/io/sentry/SentryClientTest.kt +++ b/sentry/src/test/java/io/sentry/SentryClientTest.kt @@ -14,8 +14,6 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import io.sentry.TypeCheckHint.SENTRY_SCREENSHOT -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.clientreport.ClientReportTestHelper.Companion.assertClientReport import io.sentry.clientreport.DiscardReason import io.sentry.clientreport.DiscardedEvent @@ -24,6 +22,7 @@ import io.sentry.exception.SentryEnvelopeException import io.sentry.hints.ApplyScopeData import io.sentry.hints.Cached import io.sentry.hints.DiskFlushNotification +import io.sentry.hints.Hint import io.sentry.protocol.Mechanism import io.sentry.protocol.Request import io.sentry.protocol.SdkVersion @@ -34,6 +33,7 @@ import io.sentry.protocol.User import io.sentry.test.callMethod import io.sentry.transport.ITransport import io.sentry.transport.ITransportGate +import io.sentry.util.HintUtils import org.junit.Assert.assertArrayEquals import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream @@ -83,6 +83,8 @@ class SentryClientTest { } var attachment = Attachment("hello".toByteArray(), "hello.txt", "text/plain", true) + var attachment2 = Attachment("hello2".toByteArray(), "hello2.txt", "text/plain", true) + var attachment3 = Attachment("hello3".toByteArray(), "hello3.txt", "text/plain", true) val profilingTraceFile = Files.createTempFile("trace", ".trace").toFile() var profilingTraceData = ProfilingTraceData(profilingTraceFile, sentryTracer) var profilingNonExistingTraceData = ProfilingTraceData(File("non_existent.trace"), sentryTracer) @@ -212,9 +214,9 @@ class SentryClientTest { fixture.sentryOptions.environment = "not to be applied" val sut = fixture.getSut() - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to Object()) - sut.captureEvent(event, hintsMap) - verify(fixture.transport).send(any(), eq(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint(Object()) + sut.captureEvent(event, hints) + verify(fixture.transport).send(any(), eq(hints)) } @Test @@ -531,8 +533,8 @@ class SentryClientTest { val scope = Scope(SentryOptions()) scope.level = SentryLevel.FATAL - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.captureEvent(event, scope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.captureEvent(event, scope, hints) assertNotEquals(scope.level, event.level) } @@ -545,8 +547,8 @@ class SentryClientTest { val scope = Scope(SentryOptions()) scope.level = SentryLevel.FATAL - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to Object()) - sut.captureEvent(event, scope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(Object()) + sut.captureEvent(event, scope, hints) assertEquals(scope.level, event.level) } @@ -559,8 +561,8 @@ class SentryClientTest { val scope = Scope(SentryOptions()) scope.level = SentryLevel.FATAL - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - sut.captureEvent(event, scope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(mock()) + sut.captureEvent(event, scope, hints) assertEquals(scope.level, event.level) } @@ -573,8 +575,8 @@ class SentryClientTest { val scope = Scope(SentryOptions()) scope.level = SentryLevel.FATAL - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CustomCachedApplyScopeDataHint()) - sut.captureEvent(event, scope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CustomCachedApplyScopeDataHint()) + sut.captureEvent(event, scope, hints) assertEquals(scope.level, event.level) } @@ -786,7 +788,7 @@ class SentryClientTest { val event = SentryEvent().apply { exceptions = createNonHandledException() } - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData(event, Hint(), scope) scope.withSession { assertEquals(Session.State.Crashed, it!!.status) } @@ -800,7 +802,10 @@ class SentryClientTest { val session = it.current val level = session.status val event = SentryEvent() - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData( + event, + Hint(), scope + ) assertEquals(level, session.status) } } @@ -812,7 +817,7 @@ class SentryClientTest { val event = SentryEvent().apply { exceptions = createNonHandledException() } - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData(event, Hint(), scope) scope.withSession { assertEquals(1, it!!.errorCount()) } @@ -827,7 +832,7 @@ class SentryClientTest { val event = SentryEvent().apply { setExceptions(exceptions) } - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData(event, Hint(), scope) scope.withSession { assertEquals(1, it!!.errorCount()) } @@ -841,7 +846,10 @@ class SentryClientTest { val session = it.current val errorCount = session.errorCount() val event = SentryEvent() - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData( + event, + Hint(), scope + ) assertEquals(errorCount, session.errorCount()) } } @@ -856,7 +864,10 @@ class SentryClientTest { headers = mutableMapOf("user-agent" to "jamesBond") } } - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData( + event, + Hint(), scope + ) scope.withSession { assertEquals("jamesBond", it!!.userAgent) } @@ -875,7 +886,10 @@ class SentryClientTest { headers = mutableMapOf() } } - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData( + event, + Hint(), scope + ) assertEquals(userAgent, session.userAgent) } } @@ -884,7 +898,7 @@ class SentryClientTest { fun `When capture an event and there's no session, do nothing`() { val scope = Scope(fixture.sentryOptions) val event = SentryEvent() - fixture.getSut().updateSessionData(event, null, scope) + fixture.getSut().updateSessionData(event, Hint(), scope) scope.withSession { assertNull(it) } @@ -1281,9 +1295,9 @@ class SentryClientTest { fun `screenshot is added to the envelope from the hint`() { val sut = fixture.getSut() val attachment = Attachment.fromScreenshot(byteArrayOf()) - val hints = mapOf(SENTRY_SCREENSHOT to attachment) + val hint = Hint().also { it.screenshot = attachment } - sut.captureEvent(SentryEvent(), hints) + sut.captureEvent(SentryEvent(), hint) verify(fixture.transport).send( check { envelope -> @@ -1301,9 +1315,9 @@ class SentryClientTest { fixture.sentryOptions.beforeSend = CustomBeforeSendCallback() val sut = fixture.getSut() val attachment = Attachment.fromScreenshot(byteArrayOf()) - val hints = mutableMapOf(SENTRY_SCREENSHOT to attachment) + val hint = Hint().also { it.screenshot = attachment } - sut.captureEvent(SentryEvent(), hints) + sut.captureEvent(SentryEvent(), hint) verify(fixture.transport).send( check { envelope -> @@ -1591,6 +1605,234 @@ class SentryClientTest { ) } + @Test + fun `can pass an attachment via hints`() { + val sut = fixture.getSut() + + sut.captureException(IllegalStateException(), Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 0, attachmentCount = 1) + } + + @Test + fun `an attachment passed via hint is used with scope attachments`() { + val sut = fixture.getSut() + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + sut.captureException(IllegalStateException(), scope, Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 2) + } + + @Test + fun `can add to attachments in beforeSend`() { + val sut = fixture.getSut { options -> + options.setBeforeSend { event, hints -> + assertEquals(listOf(fixture.attachment, fixture.attachment2), hints.attachments) + hints.addAttachment(fixture.attachment3) + event + } + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + sut.captureException(IllegalStateException(), scope, Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 3) + } + + @Test + fun `can replace attachments in beforeSend`() { + val sut = fixture.getSut { options -> + options.setBeforeSend { event, hints -> + hints.replaceAttachments(listOf(fixture.attachment3)) + event + } + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + sut.captureException(IllegalStateException(), scope, Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 1) + } + + @Test + fun `can add to attachments in eventProcessor`() { + val sut = fixture.getSut { options -> + options.addEventProcessor(object : EventProcessor { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { + assertEquals(listOf(fixture.attachment, fixture.attachment2), hint.attachments) + hint.addAttachment(fixture.attachment3) + return event + } + + override fun process( + transaction: SentryTransaction, + hint: Hint + ): SentryTransaction? { + return transaction + } + }) + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + sut.captureException(IllegalStateException(), scope, Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 3) + } + + @Test + fun `can replace attachments in eventProcessor`() { + val sut = fixture.getSut { options -> + options.addEventProcessor(object : EventProcessor { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { + hint.replaceAttachments(listOf(fixture.attachment3)) + return event + } + + override fun process( + transaction: SentryTransaction, + hint: Hint + ): SentryTransaction? { + return transaction + } + }) + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + sut.captureException(IllegalStateException(), scope, Hint.withAttachment(fixture.attachment)) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 1) + } + + @Test + fun `can pass an attachment via hints for transactions`() { + val sut = fixture.getSut() + val scope = createScope() + + sut.captureTransaction( + SentryTransaction(fixture.sentryTracer), + scope, + Hint.withAttachment(fixture.attachment) + ) + + thenEnvelopeIsSentWith(eventCount = 0, sessionCount = 0, attachmentCount = 1, transactionCount = 1) + } + + @Test + fun `an attachment passed via hint is used with scope attachments for transactions`() { + val sut = fixture.getSut() + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + + sut.captureTransaction( + SentryTransaction(fixture.sentryTracer), + scope, + Hint.withAttachment(fixture.attachment) + ) + + thenEnvelopeIsSentWith(eventCount = 0, sessionCount = 0, attachmentCount = 2, transactionCount = 1) + } + + @Test + fun `can add to attachments in eventProcessor for transactions`() { + val sut = fixture.getSut { options -> + options.addEventProcessor(object : EventProcessor { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { + return event + } + + override fun process( + transaction: SentryTransaction, + hint: Hint + ): SentryTransaction? { + assertEquals(listOf(fixture.attachment, fixture.attachment2), hint.attachments) + hint.addAttachment(fixture.attachment3) + return transaction + } + }) + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + + sut.captureTransaction( + SentryTransaction(fixture.sentryTracer), + scope, + Hint.withAttachment(fixture.attachment) + ) + + thenEnvelopeIsSentWith(eventCount = 0, sessionCount = 0, attachmentCount = 3, transactionCount = 1) + } + + @Test + fun `can replace attachments in eventProcessor for transactions`() { + val sut = fixture.getSut { options -> + options.addEventProcessor(object : EventProcessor { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { + return event + } + + override fun process( + transaction: SentryTransaction, + hint: Hint + ): SentryTransaction? { + hint.replaceAttachments(listOf(fixture.attachment3)) + return transaction + } + }) + } + + val scope = givenScopeWithStartedSession() + scope.addAttachment(fixture.attachment2) + + sut.captureTransaction( + SentryTransaction(fixture.sentryTracer), + scope, + Hint.withAttachment(fixture.attachment) + ) + + thenEnvelopeIsSentWith(eventCount = 0, sessionCount = 0, attachmentCount = 1, transactionCount = 1) + } + + @Test + fun `passing attachments via hint into breadcrumb ignores them`() { + val sut = fixture.getSut { options -> + options.setBeforeBreadcrumb { breadcrumb, hints -> + breadcrumb + } + } + + val scope = givenScopeWithStartedSession() + scope.addBreadcrumb(Breadcrumb.info("hello from breadcrumb"), Hint.withAttachment(fixture.attachment)) + + sut.captureException(IllegalStateException(), scope) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 0) + } + + @Test + fun `adding attachments in beforeBreadcrumb ignores them`() { + val sut = fixture.getSut { options -> + options.setBeforeBreadcrumb { breadcrumb, hints -> + hints.addAttachment(fixture.attachment) + breadcrumb + } + } + + val scope = givenScopeWithStartedSession() + scope.addBreadcrumb(Breadcrumb.info("hello from breadcrumb")) + + sut.captureException(IllegalStateException(), scope) + + thenEnvelopeIsSentWith(eventCount = 1, sessionCount = 1, attachmentCount = 0) + } + private fun givenScopeWithStartedSession(errored: Boolean = false, crashed: Boolean = false): Scope { val scope = createScope(fixture.sentryOptions) scope.startSession() @@ -1610,7 +1852,7 @@ class SentryClientTest { verify(fixture.transport, never()).send(anyOrNull(), anyOrNull()) } - private fun thenEnvelopeIsSentWith(eventCount: Int, sessionCount: Int) { + private fun thenEnvelopeIsSentWith(eventCount: Int, sessionCount: Int, attachmentCount: Int = 0, transactionCount: Int = 0) { val argumentCaptor = argumentCaptor() verify(fixture.transport, times(1)).send(argumentCaptor.capture(), anyOrNull()) @@ -1618,6 +1860,8 @@ class SentryClientTest { val envelopeItemTypes = envelope.items.map { it.header.type } assertEquals(eventCount, envelopeItemTypes.count { it == SentryItemType.Event }) assertEquals(sessionCount, envelopeItemTypes.count { it == SentryItemType.Session }) + assertEquals(attachmentCount, envelopeItemTypes.count { it == SentryItemType.Attachment }) + assertEquals(transactionCount, envelopeItemTypes.count { it == SentryItemType.Transaction }) } private fun thenSessionIsStillOK(scope: Scope) { @@ -1639,8 +1883,8 @@ class SentryClientTest { } class CustomBeforeSendCallback : SentryOptions.BeforeSendCallback { - override fun execute(event: SentryEvent, hint: MutableMap?): SentryEvent? { - hint?.remove(SENTRY_SCREENSHOT) + override fun execute(event: SentryEvent, hint: Hint): SentryEvent? { + hint.screenshot = null return event } @@ -1802,7 +2046,7 @@ class SentryClientTest { private fun eventProcessorThrows(): EventProcessor { return object : EventProcessor { - override fun process(event: SentryEvent, hint: Map?): SentryEvent? { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { throw Throwable() } } diff --git a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt index 76400ef545..9c8d95b785 100644 --- a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt +++ b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt @@ -13,13 +13,13 @@ import io.sentry.SentryEvent import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.Session -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.cache.EnvelopeCache.PREFIX_CURRENT_SESSION_FILE import io.sentry.cache.EnvelopeCache.SUFFIX_CURRENT_SESSION_FILE import io.sentry.hints.DiskFlushNotification import io.sentry.hints.SessionEndHint import io.sentry.hints.SessionStartHint import io.sentry.protocol.User +import io.sentry.util.HintUtils import java.io.File import java.nio.file.Files import java.nio.file.Path @@ -92,8 +92,8 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) @@ -109,14 +109,14 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) - hintsMap[SENTRY_TYPE_CHECK_HINT] = SessionEndHint() - cache.store(envelope, hintsMap) + HintUtils.setTypeCheckHint(hints, SessionEndHint()) + cache.store(envelope, hints) assertFalse(currentFile.exists()) file.deleteRecursively() @@ -130,8 +130,8 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val currentFile = File(fixture.options.cacheDirPath!!, "$PREFIX_CURRENT_SESSION_FILE$SUFFIX_CURRENT_SESSION_FILE") assertTrue(currentFile.exists()) @@ -150,12 +150,12 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val newEnvelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - cache.store(newEnvelope, hintsMap) + cache.store(newEnvelope, hints) verify(fixture.logger).log(eq(SentryLevel.WARNING), eq("Current session is not ended, we'd need to end it.")) } @@ -170,12 +170,12 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val newEnvelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - cache.store(newEnvelope, hintsMap) + cache.store(newEnvelope, hints) verify(fixture.logger).log(eq(SentryLevel.INFO), eq("Crash marker file exists, last Session is gonna be Crashed.")) assertFalse(markerFile.exists()) file.deleteRecursively() @@ -192,12 +192,12 @@ class EnvelopeCacheTest { markerFile.writeText(charset = Charsets.UTF_8, text = date) val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val newEnvelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - cache.store(newEnvelope, hintsMap) + cache.store(newEnvelope, hints) assertFalse(markerFile.exists()) file.deleteRecursively() File(fixture.options.cacheDirPath!!).deleteRecursively() @@ -214,15 +214,15 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) val newEnvelope = SentryEnvelope.from(fixture.serializer, createSession(), null) // since the first store call would set as readCrashedLastRun=true SentryCrashLastRunState.getInstance().reset() - cache.store(newEnvelope, hintsMap) + cache.store(newEnvelope, hints) verify(fixture.logger).log(eq(SentryLevel.INFO), eq("Crash marker file exists, last Session is gonna be Crashed.")) assertFalse(markerFile.exists()) file.deleteRecursively() @@ -241,8 +241,8 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, createSession(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to SessionStartHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(SessionStartHint()) + cache.store(envelope, hints) // passing empty string since readCrashedLastRun is already set assertTrue(SentryCrashLastRunState.getInstance().isCrashedLastRun("", false)!!) @@ -258,8 +258,8 @@ class EnvelopeCacheTest { val envelope = SentryEnvelope.from(fixture.serializer, SentryEvent(), null) - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to DiskFlushHint()) - cache.store(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(DiskFlushHint()) + cache.store(envelope, hints) assertTrue(markerFile.exists()) } diff --git a/sentry/src/test/java/io/sentry/clientreport/ClientReportTest.kt b/sentry/src/test/java/io/sentry/clientreport/ClientReportTest.kt index 96c7fdedd7..e5071a2c06 100644 --- a/sentry/src/test/java/io/sentry/clientreport/ClientReportTest.kt +++ b/sentry/src/test/java/io/sentry/clientreport/ClientReportTest.kt @@ -11,14 +11,15 @@ import io.sentry.SentryEnvelopeItem import io.sentry.SentryEvent import io.sentry.SentryOptions import io.sentry.Session -import io.sentry.TypeCheckHint import io.sentry.UserFeedback import io.sentry.dsnString import io.sentry.hints.DiskFlushNotification +import io.sentry.hints.Hint import io.sentry.hints.Retryable import io.sentry.protocol.SentryId import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User +import io.sentry.util.HintUtils import java.time.LocalDateTime import java.time.ZoneId import java.time.temporal.ChronoUnit @@ -149,13 +150,13 @@ class ClientReportTest { class DropEverythingEventProcessor : EventProcessor { - override fun process(event: SentryEvent, hint: MutableMap?): SentryEvent? { + override fun process(event: SentryEvent, hint: Hint): SentryEvent? { return null } override fun process( transaction: SentryTransaction, - hint: MutableMap? + hint: Hint ): SentryTransaction? { return null } @@ -193,9 +194,9 @@ class ClientReportTestHelper(val options: SentryOptions) { } companion object { - fun retryableHint() = mutableMapOf(TypeCheckHint.SENTRY_TYPE_CHECK_HINT to TestRetryable()) - fun diskFlushNotificationHint() = mutableMapOf(TypeCheckHint.SENTRY_TYPE_CHECK_HINT to TestDiskFlushNotification()) - fun retryableDiskFlushNotificationHint() = mutableMapOf(TypeCheckHint.SENTRY_TYPE_CHECK_HINT to TestRetryableDiskFlushNotification()) + fun retryableHint() = HintUtils.createWithTypeCheckHint(TestRetryable()) + fun diskFlushNotificationHint() = HintUtils.createWithTypeCheckHint(TestDiskFlushNotification()) + fun retryableDiskFlushNotificationHint() = HintUtils.createWithTypeCheckHint(TestRetryableDiskFlushNotification()) fun assertClientReport(clientReportRecorder: IClientReportRecorder, expectedEvents: List) { val recorder = clientReportRecorder as ClientReportRecorder diff --git a/sentry/src/test/java/io/sentry/hints/HintTest.kt b/sentry/src/test/java/io/sentry/hints/HintTest.kt new file mode 100644 index 0000000000..ffde4fd048 --- /dev/null +++ b/sentry/src/test/java/io/sentry/hints/HintTest.kt @@ -0,0 +1,202 @@ +package io.sentry.hints + +import io.sentry.Attachment +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class HintTest { + @Test + fun `getting as wrong class returns null`() { + val hint = Hint() + hint.set("hint1", "not a number") + + assertNull(hint.getAs("hint1", Int::class.java)) + } + + @Test + fun `getting as correct class returns it`() { + val hint = Hint() + hint.set("hint1", "some string") + + assertEquals("some string", hint.getAs("hint1", String::class.java)) + } + + @Test + fun `getting casted returns null if not contained`() { + val hint = Hint() + assertNull(hint.getAs("hint-does-not-exist", Int::class.java)) + } + + @Test + fun `getting returns null if not contained`() { + val hint = Hint() + assertNull(hint.get("hint-does-not-exist")) + } + + @Test + fun `kotlin java interop for primitives works for float`() { + val hint = Hint() + hint.set("hint1", 1.3f) + assertEquals(1.3f, hint.getAs("hint1", Float::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for double`() { + val hint = Hint() + hint.set("hint1", 1.4) + assertEquals(1.4, hint.getAs("hint1", Double::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for long`() { + val hint = Hint() + hint.set("hint1", 1718L) + assertEquals(1718L, hint.getAs("hint1", Long::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for int`() { + val hint = Hint() + hint.set("hint1", 123) + assertEquals(123, hint.getAs("hint1", Int::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for short`() { + val hint = Hint() + val s: Short = 123 + hint.set("hint1", s) + assertEquals(s, hint.getAs("hint1", Short::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for byte`() { + val hint = Hint() + val b: Byte = 1 + hint.set("hint1", b) + assertEquals(b, hint.getAs("hint1", Byte::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for char`() { + val hint = Hint() + hint.set("hint1", 'a') + assertEquals('a', hint.getAs("hint1", Char::class.java)) + } + + @Test + fun `kotlin java interop for primitives works for boolean`() { + val hint = Hint() + hint.set("hint1", true) + assertEquals(true, hint.getAs("hint1", Boolean::class.java)) + } + + @Test + fun `setting twice only keeps second value`() { + val hint = Hint() + + hint.set("hint1", "some string") + hint.set("hint1", "a different string") + + assertEquals("a different string", hint.getAs("hint1", String::class.java)) + } + + @Test + fun `after removing the value is gone`() { + val hint = Hint() + + hint.set("hint1", "some string") + assertEquals("some string", hint.getAs("hint1", String::class.java)) + + hint.remove("hint1") + assertNull(hint.get("hint1")) + } + + @Test + fun `removing leaves other values`() { + val hint = Hint() + + hint.set("hint1", "some string") + assertEquals("some string", hint.getAs("hint1", String::class.java)) + hint.set("hint2", "another string") + + hint.remove("hint1") + assertNull(hint.get("hint1")) + assertEquals("another string", hint.getAs("hint2", String::class.java)) + } + + @Test + fun `can retrieve Attachments`() { + val hint = Hint() + assertNotNull(hint.attachments) + } + + @Test + fun `can create hints with attachment`() { + val attachment = newAttachment("test1") + val hint = Hint.withAttachment(attachment) + assertEquals(listOf(attachment), hint.attachments) + } + + @Test + fun `can create hints with attachments`() { + val attachment1 = newAttachment("test1") + val attachment2 = newAttachment("test1") + val hint = Hint.withAttachments(listOf(attachment1, attachment2)) + assertEquals(listOf(attachment1, attachment2), hint.attachments) + } + + @Test + fun `can add an attachment`() { + val hint = Hint() + val attachment = newAttachment("test1") + hint.addAttachment(attachment) + + assertEquals(listOf(attachment), hint.attachments) + } + + @Test + fun `can add multiple attachments`() { + val hint = Hint() + val attachment1 = newAttachment("test1") + val attachment2 = newAttachment("test2") + hint.addAttachment(attachment1) + hint.addAttachment(attachment2) + + assertEquals(listOf(attachment1, attachment2), hint.attachments) + } + + @Test + fun `after reset list is empty`() { + val hint = Hint() + val attachment1 = newAttachment("test1") + val attachment2 = newAttachment("test2") + hint.addAttachment(attachment1) + hint.addAttachment(attachment2) + + hint.clearAttachments() + + assertEquals(emptyList(), hint.attachments) + } + + @Test + fun `after replace list contains only new item`() { + val hint = Hint() + val attachment1 = newAttachment("test1") + val attachment2 = newAttachment("test2") + val attachment3 = newAttachment("test2") + val attachment4 = newAttachment("test2") + hint.addAttachment(attachment1) + hint.addAttachment(attachment2) + + hint.replaceAttachments(listOf(attachment3, attachment4)) + + assertEquals(listOf(attachment3, attachment4), hint.attachments) + } + + companion object { + fun newAttachment(content: String) = Attachment(content.toByteArray(), "$content.txt") + } +} diff --git a/sentry/src/test/java/io/sentry/transport/AsyncHttpTransportTest.kt b/sentry/src/test/java/io/sentry/transport/AsyncHttpTransportTest.kt index 31ed3f6287..1af9cac6ed 100644 --- a/sentry/src/test/java/io/sentry/transport/AsyncHttpTransportTest.kt +++ b/sentry/src/test/java/io/sentry/transport/AsyncHttpTransportTest.kt @@ -17,10 +17,10 @@ import io.sentry.SentryEvent import io.sentry.SentryOptions import io.sentry.SentryOptionsManipulator import io.sentry.Session -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.clientreport.NoOpClientReportRecorder import io.sentry.dsnString import io.sentry.protocol.User +import io.sentry.util.HintUtils import java.io.IOException import kotlin.test.Test import kotlin.test.assertEquals @@ -184,8 +184,8 @@ class AsyncHttpTransportTest { whenever(fixture.rateLimiter.filter(any(), anyOrNull())).thenReturn(null) // when - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - fixture.getSUT().send(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + fixture.getSUT().send(envelope, hints) // then verify(fixture.sentryOptions.envelopeDiskCache).discard(any()) @@ -242,8 +242,8 @@ class AsyncHttpTransportTest { val envelope = SentryEnvelope.from(fixture.sentryOptions.serializer, ev, null) // when - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CachedEvent()) - fixture.getSUT().send(envelope, hintsMap) + val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) + fixture.getSUT().send(envelope, hints) // then verify(fixture.sentryOptions.envelopeDiskCache).discard(any()) diff --git a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt index c75cc08dd8..e7fd08e411 100644 --- a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt +++ b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt @@ -22,6 +22,7 @@ import io.sentry.TransactionContext import io.sentry.UserFeedback import io.sentry.clientreport.DiscardReason import io.sentry.clientreport.IClientReportRecorder +import io.sentry.hints.Hint import io.sentry.protocol.SentryId import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User @@ -63,7 +64,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("50:transaction:key, 1:default;error;security:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNotNull(result) assertEquals(1, result.items.count()) } @@ -79,7 +80,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("50:transaction:key, 2700:default;error;security:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -94,7 +95,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("1:transaction:key, 1:default;error;security:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNotNull(result) assertEquals(2, result.items.count()) } @@ -108,7 +109,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("50::key", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -121,7 +122,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("1::key, 60:default;error;security:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -134,7 +135,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("60:error:key, 1:error:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -147,7 +148,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits("1:error:key, 5:error:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -160,7 +161,7 @@ class RateLimiterTest { rateLimiter.updateRetryAfterLimits(null, null, 429) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) } @@ -185,7 +186,7 @@ class RateLimiterTest { val envelope = SentryEnvelope(SentryEnvelopeHeader(), arrayListOf(eventItem, userFeedbackItem, sessionItem, attachmentItem)) rateLimiter.updateRetryAfterLimits(null, null, 429) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNull(result) @@ -217,7 +218,7 @@ class RateLimiterTest { val envelope = SentryEnvelope(SentryEnvelopeHeader(), arrayListOf(eventItem, userFeedbackItem, sessionItem, attachmentItem)) rateLimiter.updateRetryAfterLimits("60:error:key, 1:error:organization", null, 1) - val result = rateLimiter.filter(envelope, null) + val result = rateLimiter.filter(envelope, Hint()) assertNotNull(result) assertEquals(3, result.items.toList().size) diff --git a/sentry/src/test/java/io/sentry/util/HintUtilsTest.kt b/sentry/src/test/java/io/sentry/util/HintUtilsTest.kt index 9e8db6c300..d6f24ab566 100644 --- a/sentry/src/test/java/io/sentry/util/HintUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/util/HintUtilsTest.kt @@ -2,9 +2,9 @@ package io.sentry.util import com.nhaarman.mockitokotlin2.mock import io.sentry.CustomCachedApplyScopeDataHint -import io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT import io.sentry.hints.ApplyScopeData import io.sentry.hints.Cached +import io.sentry.hints.Hint import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -13,24 +13,24 @@ class HintUtilsTest { @Test fun `if event is Cached, it should not apply scopes data`() { - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - assertFalse(HintUtils.shouldApplyScopeData(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint(mock()) + assertFalse(HintUtils.shouldApplyScopeData(hints)) } @Test fun `if event is not Cached, it should apply scopes data`() { - assertTrue(HintUtils.shouldApplyScopeData(null)) + assertTrue(HintUtils.shouldApplyScopeData(Hint())) } @Test fun `if event is ApplyScopeData, it should apply scopes data`() { - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to mock()) - assertTrue(HintUtils.shouldApplyScopeData(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint(mock()) + assertTrue(HintUtils.shouldApplyScopeData(hints)) } @Test fun `if event is Cached but also ApplyScopeData, it should apply scopes data`() { - val hintsMap = mutableMapOf(SENTRY_TYPE_CHECK_HINT to CustomCachedApplyScopeDataHint()) - assertTrue(HintUtils.shouldApplyScopeData(hintsMap)) + val hints = HintUtils.createWithTypeCheckHint(CustomCachedApplyScopeDataHint()) + assertTrue(HintUtils.shouldApplyScopeData(hints)) } }