diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidSerializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidSerializer.java index f3cdc8796..0dc254c77 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidSerializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidSerializer.java @@ -7,6 +7,7 @@ import io.sentry.core.ILogger; import io.sentry.core.ISerializer; import io.sentry.core.SentryEvent; +import io.sentry.core.SentryLevel; import io.sentry.core.protocol.Device; import io.sentry.core.protocol.SentryId; import java.io.IOException; @@ -38,6 +39,8 @@ private Gson provideGson() { Device.DeviceOrientation.class, new OrientationSerializerAdapter(logger)) .registerTypeAdapter( Device.DeviceOrientation.class, new OrientationDeserializerAdapter(logger)) + .registerTypeAdapter(SentryLevel.class, new SentryLevelSerializerAdapter(logger)) + .registerTypeAdapter(SentryLevel.class, new SentryLevelDeserializerAdapter(logger)) .registerTypeAdapterFactory(UnknownPropertiesTypeAdapterFactory.get()) .create(); } 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 b7a4b992c..8539d2439 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 @@ -157,6 +157,8 @@ private Long getMemorySize(ActivityManager.MemoryInfo memInfo) { // we can get some inspiration here // https://github.com/flutter/plugins/blob/master/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java private Device getDevice() { + // TODO: missing name and usable memory + Device device = new Device(); device.setManufacturer(Build.MANUFACTURER); device.setBrand(Build.BRAND); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelDeserializerAdapter.java b/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelDeserializerAdapter.java new file mode 100644 index 000000000..f6b88a6ff --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelDeserializerAdapter.java @@ -0,0 +1,32 @@ +package io.sentry.android.core.adapters; + +import static io.sentry.core.ILogger.log; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import io.sentry.core.ILogger; +import io.sentry.core.SentryLevel; +import java.lang.reflect.Type; +import java.util.Locale; + +public class SentryLevelDeserializerAdapter implements JsonDeserializer { + + private final ILogger logger; + + public SentryLevelDeserializerAdapter(ILogger logger) { + this.logger = logger; + } + + @Override + public SentryLevel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + try { + return json == null ? null : SentryLevel.valueOf(json.getAsString().toUpperCase(Locale.ROOT)); + } catch (Exception e) { + log(logger, SentryLevel.ERROR, "Error when deserializing SentryLevel", e); + } + return null; + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelSerializerAdapter.java b/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelSerializerAdapter.java new file mode 100644 index 000000000..62f67d335 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/adapters/SentryLevelSerializerAdapter.java @@ -0,0 +1,31 @@ +package io.sentry.android.core.adapters; + +import static io.sentry.core.ILogger.log; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import io.sentry.core.ILogger; +import io.sentry.core.SentryLevel; +import java.lang.reflect.Type; +import java.util.Locale; + +public class SentryLevelSerializerAdapter implements JsonSerializer { + + private final ILogger logger; + + public SentryLevelSerializerAdapter(ILogger logger) { + this.logger = logger; + } + + @Override + public JsonElement serialize(SentryLevel src, Type typeOfSrc, JsonSerializationContext context) { + try { + return src == null ? null : new JsonPrimitive(src.name().toLowerCase(Locale.ROOT)); + } catch (Exception e) { + log(logger, SentryLevel.ERROR, "Error when serializing SentryLevel", e); + } + return null; + } +} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidSerializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidSerializerTest.kt index d13098ee0..ad71d20ea 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidSerializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidSerializerTest.kt @@ -6,6 +6,7 @@ import com.google.gson.internal.LinkedTreeMap import com.nhaarman.mockitokotlin2.mock import io.sentry.core.DateUtils import io.sentry.core.SentryEvent +import io.sentry.core.SentryLevel import io.sentry.core.protocol.Contexts import io.sentry.core.protocol.Device import java.io.StringWriter @@ -200,6 +201,33 @@ class AndroidSerializerTest { assertEquals(Device.DeviceOrientation.LANDSCAPE, Device.DeviceOrientation.valueOf(orientation.toUpperCase())) // here too } + @Test + fun `when serializing a SentryLevel, it should become a sentry level string`() { + val sentryEvent = generateEmptySentryEvent() + sentryEvent.eventId = null + sentryEvent.timestamp = null + sentryEvent.level = SentryLevel.DEBUG + + val expected = "{\"level\":\"debug\"}" + + val actual = serializeToString(sentryEvent) + + assertEquals(expected, actual) + } + + @Test + fun `when deserializing a sentry level string, it should become a SentryLevel`() { + val sentryEvent = generateEmptySentryEvent() + sentryEvent.eventId = null + sentryEvent.timestamp = null + + val jsonEvent = "{\"level\":\"debug\"}" + + val actual = serializer.deserializeEvent(jsonEvent) + + assertEquals(SentryLevel.DEBUG, actual.level) + } + private fun generateEmptySentryEvent(): SentryEvent { return SentryEvent().apply { contexts = null diff --git a/sentry-core/src/main/java/io/sentry/core/Sentry.java b/sentry-core/src/main/java/io/sentry/core/Sentry.java index 66e65e2e0..47f48a103 100644 --- a/sentry-core/src/main/java/io/sentry/core/Sentry.java +++ b/sentry-core/src/main/java/io/sentry/core/Sentry.java @@ -74,35 +74,35 @@ public static SentryId captureException(Throwable throwable) { return getCurrentHub().captureException(throwable); } - public void addBreadcrumb(Breadcrumb breadcrumb) { + public static void addBreadcrumb(Breadcrumb breadcrumb) { getCurrentHub().addBreadcrumb(breadcrumb); } - public SentryId getLastEventId() { + public static SentryId getLastEventId() { return getCurrentHub().getLastEventId(); } - public void pushScope() { + public static void pushScope() { getCurrentHub().pushScope(); } - public void popScope() { + public static void popScope() { getCurrentHub().popScope(); } - public void withScope(ScopeCallback callback) { + public static void withScope(ScopeCallback callback) { getCurrentHub().withScope(callback); } - public void configureScope(ScopeCallback callback) { + public static void configureScope(ScopeCallback callback) { getCurrentHub().configureScope(callback); } - public void bindClient(SentryClient client) { + public static void bindClient(SentryClient client) { getCurrentHub().bindClient(client); } - public void flush(int timeoutMills) { + public static void flush(int timeoutMills) { getCurrentHub().flush(timeoutMills); } diff --git a/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java b/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java index 59d09e4ae..f0bfd604e 100644 --- a/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java +++ b/sentry-core/src/main/java/io/sentry/core/protocol/Contexts.java @@ -39,7 +39,7 @@ public OperatingSystem getOperatingSystem() { } public void setOperatingSystem(OperatingSystem operatingSystem) { - this.put(Device.TYPE, operatingSystem); + this.put(OperatingSystem.TYPE, operatingSystem); } public Runtime getRuntime() { diff --git a/sentry-sample/src/main/java/io/sentry/sample/MainActivity.java b/sentry-sample/src/main/java/io/sentry/sample/MainActivity.java index d84481591..33c266578 100644 --- a/sentry-sample/src/main/java/io/sentry/sample/MainActivity.java +++ b/sentry-sample/src/main/java/io/sentry/sample/MainActivity.java @@ -3,7 +3,11 @@ import android.os.Bundle; import android.os.StrictMode; import androidx.appcompat.app.AppCompatActivity; +import io.sentry.core.Breadcrumb; import io.sentry.core.Sentry; +import io.sentry.core.SentryLevel; +import io.sentry.core.protocol.User; +import java.util.Collections; import timber.log.Timber; public class MainActivity extends AppCompatActivity { @@ -37,6 +41,25 @@ protected void onCreate(Bundle savedInstanceState) { view -> { Sentry.captureException(new Exception("Some exception.")); }); + + findViewById(R.id.breadcrumb) + .setOnClickListener( + view -> { + Sentry.configureScope( + scope -> { + Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setMessage("Breadcrumb"); + scope.addBreadcrumb(breadcrumb); + scope.setExtra("extra", "extra"); + scope.setFingerprint(Collections.singletonList("fingerprint")); + scope.setLevel(SentryLevel.INFO); + scope.setTransaction("transaction"); + User user = new User(); + user.setUsername("username"); + scope.setUser(user); + scope.setTag("tag", "tag"); + }); + }); } private void districtMode() { diff --git a/sentry-sample/src/main/res/layout/activity_main.xml b/sentry-sample/src/main/res/layout/activity_main.xml index 79d345a2d..7d49e81b2 100644 --- a/sentry-sample/src/main/res/layout/activity_main.xml +++ b/sentry-sample/src/main/res/layout/activity_main.xml @@ -20,4 +20,9 @@ android:layout_height="wrap_content" android:id="@+id/capture_exception" android:text="@string/capture_exception"/> + +