diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d7f42dc6..4ba64f0f5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * Check internal JNI calls for pending exceptions and no-op [#1088](/~https://github.com/bugsnag/bugsnag-android/pull/1088) [#1091](/~https://github.com/bugsnag/bugsnag-android/pull/1091) +* Add global metadata to ANR error reports + [#1095](/~https://github.com/bugsnag/bugsnag-android/pull/1095) ## 5.5.2 (2021-01-27) diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Client.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/Client.java index 2fbf84a3c0..e3e20d9923 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/Client.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Client.java @@ -934,4 +934,8 @@ T getPlugin(@NonNull Class clz) { Notifier getNotifier() { return notifier; } + + MetadataState getMetadataState() { + return metadataState; + } } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java index d7479511b0..58cef131c9 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java @@ -389,7 +389,8 @@ public boolean onError(@NonNull Event event) { public static Event createEvent(@Nullable Throwable exc, @NonNull Client client, @NonNull SeverityReason severityReason) { - return new Event(exc, client.getConfig(), severityReason, client.logger); + Metadata metadata = client.getMetadataState().getMetadata(); + return new Event(exc, client.getConfig(), severityReason, metadata, client.logger); } @NonNull diff --git a/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/AnrDetailsCollectorTest.kt b/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/AnrDetailsCollectorTest.kt index 5e4e58b388..196ab679bf 100644 --- a/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/AnrDetailsCollectorTest.kt +++ b/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/AnrDetailsCollectorTest.kt @@ -64,6 +64,7 @@ class AnrDetailsCollectorTest { @Test fun anrDetailsAltered() { Mockito.`when`(client.config).thenReturn(BugsnagTestUtils.generateImmutableConfig()) + Mockito.`when`(client.getMetadataState()).thenReturn(BugsnagTestUtils.generateMetadataState()) val event = NativeInterface.createEvent( RuntimeException("whoops"), client, diff --git a/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/BugsnagTestUtils.java b/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/BugsnagTestUtils.java index f0ce1d330d..7f1eebcad9 100644 --- a/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/BugsnagTestUtils.java +++ b/bugsnag-plugin-android-anr/src/test/java/com/bugsnag/android/BugsnagTestUtils.java @@ -28,6 +28,9 @@ static ImmutableConfig generateImmutableConfig() { return convert(generateConfiguration()); } + static MetadataState generateMetadataState() { + return new MetadataState(); + } static ImmutableConfig convert(Configuration config) { return ImmutableConfigKt.convertToImmutableConfig(config, null); diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt index 893bad732e..33280a9c11 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt @@ -41,6 +41,7 @@ class EventDeserializerTest { `when`(client.config).thenReturn(TestData.generateConfig()) `when`(client.getLogger()).thenReturn(object : Logger {}) + `when`(client.getMetadataState()).thenReturn(TestHooks.generateMetadataState()) } private fun breadcrumbMap() = hashMapOf( diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java index 6f24ac8e0a..0da27b1877 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java @@ -4,4 +4,8 @@ class TestHooks { static boolean getUnhandledOverridden(Event event) { return event.impl.getUnhandledOverridden(); } + + static MetadataState generateMetadataState() { + return new MetadataState(); + } } diff --git a/features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/AppNotRespondingScenario.kt b/features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/AppNotRespondingScenario.kt index 5bced3661e..0716db8ee6 100644 --- a/features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/AppNotRespondingScenario.kt +++ b/features/fixtures/mazerunner/jvm-scenarios/src/main/java/com/bugsnag/android/mazerunner/scenarios/AppNotRespondingScenario.kt @@ -3,6 +3,7 @@ package com.bugsnag.android.mazerunner.scenarios import android.content.Context import android.os.Handler import android.os.Looper +import com.bugsnag.android.Bugsnag import com.bugsnag.android.Configuration /** @@ -21,6 +22,11 @@ internal class AppNotRespondingScenario( override fun startScenario() { super.startScenario() + Bugsnag.addMetadata("custom", "global", "present in global metadata") + Bugsnag.addOnError { event -> + event.addMetadata("custom", "local", "present in local metadata") + true + } val main = Handler(Looper.getMainLooper()) main.postDelayed( Runnable { diff --git a/features/smoke_tests/unhandled.feature b/features/smoke_tests/unhandled.feature index 0f966b0465..7a58f7f2ce 100644 --- a/features/smoke_tests/unhandled.feature +++ b/features/smoke_tests/unhandled.feature @@ -230,3 +230,7 @@ Scenario: ANR detection And the event "threads.0.stacktrace.0.method" is not null And the event "threads.0.stacktrace.0.file" is not null And the event "threads.0.stacktrace.0.lineNumber" is not null + + # Metadata validation + And the event "metaData.custom.global" equals "present in global metadata" + And the event "metaData.custom.local" equals "present in local metadata"