diff --git a/CHANGELOG.md b/CHANGELOG.md index 3733d9728..95ff44c6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- When running on Android, the SDK now links errors and events originating on different layers (managed, native errors) via `trace ID` ([#1997](https://github.com/getsentry/sentry-unity/pull/1997)) - The SDK now reports the game's name as part of the app context ([2083](https://github.com/getsentry/sentry-unity/pull/2083)) - The SDK now reports the active scene's name as part of the `Unity Context` ([2084](https://github.com/getsentry/sentry-unity/pull/2084)) diff --git a/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs b/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs index ef54bb937..0f80acfd8 100644 --- a/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs +++ b/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs @@ -1,3 +1,4 @@ +using System; using UnityEngine; namespace Sentry.Unity.Android; @@ -15,7 +16,8 @@ public AndroidJavaScopeObserver(SentryOptions options, IJniExecutor jniExecutor) _jniExecutor = jniExecutor; } - private AndroidJavaObject GetSentryJava() => new AndroidJavaClass("io.sentry.Sentry"); + private static AndroidJavaObject GetSentryJava() => new AndroidJavaClass("io.sentry.Sentry"); + private static AndroidJavaObject GetInternalSentryJava() => new AndroidJavaClass("io.sentry.android.core.InternalSentrySdk"); public override void AddBreadcrumbImpl(Breadcrumb breadcrumb) { @@ -88,4 +90,14 @@ public override void UnsetUserImpl() sentry.CallStatic("setUser", null); }); } + + public override void SetTraceImpl(SentryId traceId, SpanId spanId) + { + _jniExecutor.Run(() => + { + using var sentry = GetInternalSentryJava(); + // We have to explicitly cast to `(Double?)` + sentry.CallStatic("setTrace", traceId.ToString(), spanId.ToString(), (Double?)null, (Double?)null); + }); + } } diff --git a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs index c61de02b9..fc63611d7 100644 --- a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs +++ b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs @@ -206,6 +206,7 @@ internal void ModifyManifest(string basePath) // Disabling the native in favor of the C# layer for now androidManifest.SetNdkEnabled(_options.NdkIntegrationEnabled); androidManifest.SetNdkScopeSync(_options.NdkScopeSyncEnabled); + androidManifest.SetAutoTraceIdGeneration(false); androidManifest.SetAutoSessionTracking(false); androidManifest.SetAutoAppLifecycleBreadcrumbs(false); androidManifest.SetAnr(false); @@ -483,6 +484,9 @@ internal void SetNdkEnabled(bool enableNdk) internal void SetNdkScopeSync(bool enableNdkScopeSync) => SetMetaData($"{SentryPrefix}.ndk.scope-sync.enable", enableNdkScopeSync.ToString()); + internal void SetAutoTraceIdGeneration(bool enableAutoTraceIdGeneration) + => SetMetaData($"{SentryPrefix}.traces.enable-auto-id-generation", enableAutoTraceIdGeneration.ToString()); + internal void SetDebug(bool debug) => SetMetaData($"{SentryPrefix}.debug", debug ? "true" : "false"); // https://github.com/getsentry/sentry-java/blob/db4dfc92f202b1cefc48d019fdabe24d487db923/sentry/src/main/java/io/sentry/SentryLevel.java#L4-L9 diff --git a/src/Sentry.Unity.Native/NativeScopeObserver.cs b/src/Sentry.Unity.Native/NativeScopeObserver.cs index 5075febca..3499e38d8 100644 --- a/src/Sentry.Unity.Native/NativeScopeObserver.cs +++ b/src/Sentry.Unity.Native/NativeScopeObserver.cs @@ -40,6 +40,10 @@ public override void SetUserImpl(SentryUser user) } public override void UnsetUserImpl() => C.sentry_remove_user(); + public override void SetTraceImpl(SentryId traceId, SpanId spanId) + { + // TODO: Needs to be implemented + } private static string GetTimestamp(DateTimeOffset timestamp) => // "o": Using ISO 8601 to make sure the timestamp makes it to the bridge correctly. diff --git a/src/Sentry.Unity.iOS/NativeScopeObserver.cs b/src/Sentry.Unity.iOS/NativeScopeObserver.cs index f46d69bdf..836a8532e 100644 --- a/src/Sentry.Unity.iOS/NativeScopeObserver.cs +++ b/src/Sentry.Unity.iOS/NativeScopeObserver.cs @@ -25,6 +25,10 @@ public override void SetUserImpl(SentryUser user) => SentryCocoaBridgeProxy.SetUser(user.Email, user.Id, user.IpAddress, user.Username); public override void UnsetUserImpl() => SentryCocoaBridgeProxy.UnsetUser(); + public override void SetTraceImpl(SentryId traceId, SpanId spanId) + { + // TODO: Needs to be implemented + } internal static string GetTimestamp(DateTimeOffset timestamp) => // "o": Using ISO 8601 to make sure the timestamp makes it to the bridge correctly. diff --git a/src/Sentry.Unity/ScopeObserver.cs b/src/Sentry.Unity/ScopeObserver.cs index 86dc3e872..9055ff55e 100644 --- a/src/Sentry.Unity/ScopeObserver.cs +++ b/src/Sentry.Unity/ScopeObserver.cs @@ -3,7 +3,7 @@ namespace Sentry.Unity; /// <summary> -/// Sentry Unity Scope Observer wrapper for the common behaviour accross platforms. +/// Sentry Unity Scope Observer wrapper for the common behaviour across platforms. /// </summary> public abstract class ScopeObserver : IScopeObserver { @@ -81,10 +81,17 @@ public void SetUser(SentryUser? user) } } - public void SetTrace(SentryId traceId, SpanId parentSpanId) - { } - public abstract void SetUserImpl(SentryUser user); public abstract void UnsetUserImpl(); + + public void SetTrace(SentryId traceId, SpanId spanId) + { + _options.DiagnosticLogger?.Log( + SentryLevel.Debug, "{0} Scope Sync - Setting Trace traceId:{1} spanId:{2}", null, + _name, traceId, spanId); + SetTraceImpl(traceId, spanId); + } + + public abstract void SetTraceImpl(SentryId traceId, SpanId spanId); } diff --git a/src/Sentry.Unity/SentryUnitySDK.cs b/src/Sentry.Unity/SentryUnitySDK.cs index 029e34194..c32ae428d 100644 --- a/src/Sentry.Unity/SentryUnitySDK.cs +++ b/src/Sentry.Unity/SentryUnitySDK.cs @@ -51,6 +51,11 @@ private SentryUnitySdk(SentryUnityOptions options) unitySdk._dotnetSdk = SentrySdk.Init(options); + // For now, we're creating a new trace after initializing to be able to tie errors and crashes together on all + // layers. To be able to regenerate new traces based on some mechanism, this will move into some sort of + // integration i.e. scene manager. + SentrySdk.SetTrace(SentryId.Create(), SpanId.Create()); + if (options.NativeContextWriter is { } contextWriter) { SentrySdk.ConfigureScope((scope) => diff --git a/test/Sentry.Unity.Android.Tests/TestSentryJava.cs b/test/Sentry.Unity.Android.Tests/TestSentryJava.cs index 16cb0fd97..be1139782 100644 --- a/test/Sentry.Unity.Android.Tests/TestSentryJava.cs +++ b/test/Sentry.Unity.Android.Tests/TestSentryJava.cs @@ -19,6 +19,7 @@ public void Init(IJniExecutor jniExecutor, SentryUnityOptions options, TimeSpan public bool? CrashedLastRun(IJniExecutor jniExecutor) => IsCrashedLastRun; public void Close(IJniExecutor jniExecutor) { } + public void SetTrace(IJniExecutor jniExecutor, string traceId, string spanId) { } public void WriteScope( IJniExecutor jniExecutor,