Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
#4018 - Safety calls to json serialization between native & dotnet an…
…droid - could not repro issue, but this was necessary
  • Loading branch information
aritchie committed Mar 3, 2025
commit 22ef5842d173f59689b5bbb18d995fc9b1bc88d6
5 changes: 5 additions & 0 deletions samples/Sentry.Samples.Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ protected override void OnCreate(Bundle? savedInstanceState)
// https://docs.sentry.io/platforms/android/configuration/
// Enable Native Android SDK ANR detection
options.Native.AnrEnabled = true;

options.SetBeforeSend(evt =>
{
return evt;
});
});

// Here's an example of adding custom scope information.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android34.0</TargetFramework>
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
Expand Down
9 changes: 8 additions & 1 deletion src/Sentry/Internal/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,14 @@ public static void Deconstruct(this JsonProperty jsonProperty, out string name,

foreach (var (name, value) in json.EnumerateObject())
{
result[name] = value.GetString();
if (value.ValueKind == JsonValueKind.String)
{
result[name] = value.GetString();
}
else
{
result[name] = value.ToString();
}
}

return result;
Expand Down
20 changes: 15 additions & 5 deletions src/Sentry/Platforms/Android/Callbacks/BeforeSendCallback.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Sentry.Android.Extensions;
using Sentry.Extensibility;

namespace Sentry.Android.Callbacks;

Expand All @@ -22,10 +23,19 @@ public BeforeSendCallback(
{
// Note: Hint is unused due to:
// https://github.com/getsentry/sentry-dotnet/issues/1469

var evnt = e.ToSentryEvent(_javaOptions);
var hint = h.ToHint();
var result = _beforeSend?.Invoke(evnt, hint);
return result?.ToJavaSentryEvent(_options, _javaOptions);
try
{
// because this can go out to user code, we want to prevent external crashing
// also, native types tend to move before dotnet does, so serialization can fail
var evnt = e.ToSentryEvent(_javaOptions);
var hint = h.ToHint();
var result = _beforeSend?.Invoke(evnt, hint);
return result?.ToJavaSentryEvent(_options, _javaOptions);
}
catch (Exception exception)
{
_options.LogError(exception, "Before Send Error");
return e;
}
}
}
128 changes: 128 additions & 0 deletions test/Sentry.Tests/Platforms/Android/JsonExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using Sentry.Android.Extensions;

namespace Sentry.Tests.Platforms.Android;

public class JsonExtensionsTests

{
[Fact]
public void ToJavaSentryEvent_Success()

{
var evt = new SentryEvent(new Exception("Test Exception"));

evt.Level = SentryLevel.Debug;
evt.ServerName = "test server name";
evt.Distribution = "test distribution";
evt.Logger = "test logger";
evt.Release = "test release";
evt.Environment = "test environment";
evt.TransactionName = "test transaction name";
evt.Message = new SentryMessage
{
Params = ["Test"]
};

evt.SetTag("TestTagKey", "TestTagValue");
evt.AddBreadcrumb(new Breadcrumb("test breadcrumb", "test type"));
evt.SetExtra("TestExtraKey", "TestExtraValue");
evt.User = new SentryUser
{
Id = "user id",
Username = "test",
Email = "[email protected]",
IpAddress = "127.0.0.1"
};

var native = evt.ToJavaSentryEvent(new SentryOptions(), new JavaSdk.SentryOptions());

AssertEqual(evt, native);
}


[Fact]
public void ToSentryEvent_ConvertToManaged()
{
var native = new JavaSdk.SentryEvent();

native.Throwable = new Exception("Test Exception").ToThrowable();
native.Timestamp = DateTimeOffset.UtcNow.ToJavaDate();
native.Level = JavaSdk.SentryLevel.Debug;
native.ServerName = "native server name";
native.Dist = "native dist";
native.Logger = "native logger";
native.Release = "native release";
native.Environment = "native env";
native.Transaction = "native transaction";
native.Message = new JavaSdk.Protocol.Message
{
Params = ["Test"]
};
native.Tags = new Dictionary<string, string>
{
{ "TestTagKey", "TestTagValue" }
};
native.Extras = new Dictionary<string, Java.Lang.Object>
{
{ "TestExtraKey", "TestExtraValue" }
};
native.Breadcrumbs =
[
new JavaSdk.Breadcrumb
{
Category = "category",
Level = JavaSdk.SentryLevel.Debug
}
];

native.User = new JavaSdk.Protocol.User
{
Id = "user id",
Username = "test",
Email = "[email protected]",
IpAddress = "127.0.0.1"
};

var managed = native.ToSentryEvent(new JavaSdk.SentryOptions());

AssertEqual(managed, native);
}


private static void AssertEqual(SentryEvent managed, JavaSdk.SentryEvent native)
{
native.ServerName.Should().Be(managed.ServerName, "Server Name");
native.Dist.Should().Be(managed.Distribution, "Distribution");
native.Logger.Should().Be(managed.Logger, "Logger");
native.Release.Should().Be(managed.Release, "Release");
native.Environment.Should().Be(managed.Environment, "Environment");
native.Transaction.Should().Be(managed.TransactionName!, "Transaction");
native.Level!.ToString().Should().Be(managed.Level.ToString(), "Level");
native.Throwable.Message.Should().Be(managed.Exception!.Message, "Message should match");

// extras
native.Extras.Should().NotBeNull("No extras found");
native.Extras.Count.Should().Be(1, "Extras should have 1 item");
native.Extras!.Keys!.First().Should().Be(managed.Extra.Keys.First(), "Extras key should match");
native.Extras!.Values!.First().Should().Be(managed.Extra.Values.First(), "Extra value should match");

// tags
native.Tags.Should().NotBeNull("No tags found");
native.Tags.Count.Should().Be(1, "Tags should have 1 item");
native.Tags!.Keys!.First().Should().Be(managed.Tags.Keys.First());
native.Tags!.Values!.First().Should().Be(managed.Tags.Values.First());

// breadcrumbs
native.Breadcrumbs.Should().NotBeNull("No breadcrumbs found");
var nb = native.Breadcrumbs!.First();
var mb = managed.Breadcrumbs!.First();
nb.Message.Should().Be(mb.Message, "Breadcrumb message");
nb.Type.Should().Be(mb.Type, "Breadcrumb type");

// user
native.User!.Id.Should().Be(managed.User.Id, "UserId should match");
native.User.Email.Should().Be(managed.User.Email, "Email should match");
native.User.Username.Should().Be(managed.User.Username, "Username should match");
native.User.IpAddress.Should().Be(managed.User.IpAddress, "IpAddress should match");
}
}
Loading