diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d569dd18..4e8049f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ ### Features -- The _Metrics_ APIs are now stable: removed `Experimental` from `SentrySdk` and `SentryOptions`. ([#2615](https://github.com/getsentry/sentry-unity/pull/2615)) +- The _Metrics_ APIs are now stable: removed `Experimental` from `SentrySdk` and `SentryOptions` ([#2615](https://github.com/getsentry/sentry-unity/pull/2615)) +- Attachments added to the scope are now included in native crash reports on Android, Windows, and Linux ([#2609](https://github.com/getsentry/sentry-unity/pull/2609)) ### Dependencies diff --git a/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs b/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs index fb037b172..65936ac79 100644 --- a/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs +++ b/src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs @@ -37,7 +37,12 @@ public override void UnsetUserImpl() => public override void SetTraceImpl(SentryId traceId, SpanId spanId) => _sentryJava.SetTrace(traceId, spanId); - public override void AddAttachmentImpl(SentryAttachment attachment) { } + public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) => + _sentryJava.AddAttachment(filePath, fileName, contentType); - public override void ClearAttachmentsImpl() { } + public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) => + _sentryJava.AddAttachmentBytes(data, fileName, contentType); + + public override void ClearAttachmentsImpl() => + _sentryJava.ClearAttachments(); } diff --git a/src/Sentry.Unity.Android/SentryJava.cs b/src/Sentry.Unity.Android/SentryJava.cs index 9a68442aa..918acc746 100644 --- a/src/Sentry.Unity.Android/SentryJava.cs +++ b/src/Sentry.Unity.Android/SentryJava.cs @@ -42,6 +42,9 @@ public void WriteScope( public void SetUser(SentryUser user); public void UnsetUser(); public void SetTrace(SentryId traceId, SpanId spanId); + void AddAttachment(string path, string fileName, string? contentType); + void AddAttachmentBytes(byte[] data, string fileName, string? contentType); + void ClearAttachments(); } /// @@ -361,6 +364,44 @@ public void SetTrace(SentryId traceId, SpanId spanId) }); } + public void AddAttachment(string path, string fileName, string? contentType) + { + RunJniSafe(() => + { + using var attachment = contentType is not null + ? new AndroidJavaObject("io.sentry.Attachment", path, fileName, contentType) + : new AndroidJavaObject("io.sentry.Attachment", path, fileName); + + using var sentry = GetSentryJava(); + sentry.CallStatic("configureScope", new ScopeCallback(scope => + scope.Call("addAttachment", attachment))); + }); + } + + public void AddAttachmentBytes(byte[] data, string fileName, string? contentType) + { + RunJniSafe(() => + { + using var attachment = contentType is not null + ? new AndroidJavaObject("io.sentry.Attachment", data, fileName, contentType) + : new AndroidJavaObject("io.sentry.Attachment", data, fileName); + + using var sentry = GetSentryJava(); + sentry.CallStatic("configureScope", new ScopeCallback(scope => + scope.Call("addAttachment", attachment))); + }); + } + + public void ClearAttachments() + { + RunJniSafe(() => + { + using var sentry = GetSentryJava(); + sentry.CallStatic("configureScope", new ScopeCallback(scope => + scope.Call("clearAttachments"))); + }); + } + // https://github.com/getsentry/sentry-java/blob/db4dfc92f202b1cefc48d019fdabe24d487db923/sentry/src/main/java/io/sentry/SentryLevel.java#L4-L9 internal static string GetLevelString(SentryLevel level) => level switch { diff --git a/src/Sentry.Unity.Native/CFunctions.cs b/src/Sentry.Unity.Native/CFunctions.cs index 4a644e70c..212fc0ed7 100644 --- a/src/Sentry.Unity.Native/CFunctions.cs +++ b/src/Sentry.Unity.Native/CFunctions.cs @@ -165,6 +165,15 @@ internal static void SetValueIfNotNull(sentry_value_t obj, string key, long? val [DllImport(SentryLib)] internal static extern void sentry_set_trace(string traceId, string parentSpanId); + [DllImport(SentryLib)] + internal static extern IntPtr sentry_attach_file(string path); + + [DllImport(SentryLib)] + internal static extern IntPtr sentry_attach_bytes(byte[] buf, UIntPtr buf_len, string filename); + + [DllImport(SentryLib)] + internal static extern void sentry_clear_attachments(); + internal static readonly Lazy> DebugImages = new(LoadDebugImages); private static IEnumerable LoadDebugImages() diff --git a/src/Sentry.Unity.Native/NativeScopeObserver.cs b/src/Sentry.Unity.Native/NativeScopeObserver.cs index 8b1a443de..c99e11641 100644 --- a/src/Sentry.Unity.Native/NativeScopeObserver.cs +++ b/src/Sentry.Unity.Native/NativeScopeObserver.cs @@ -43,9 +43,14 @@ public override void SetUserImpl(SentryUser user) public override void SetTraceImpl(SentryId traceId, SpanId spanId) => C.sentry_set_trace(traceId.ToString(), spanId.ToString()); - public override void AddAttachmentImpl(SentryAttachment attachment) { } + public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) => + C.sentry_attach_file(filePath); - public override void ClearAttachmentsImpl() { } + public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) => + C.sentry_attach_bytes(data, (UIntPtr)data.Length, fileName); + + public override void ClearAttachmentsImpl() => + C.sentry_clear_attachments(); 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 00014bc1e..0358d6086 100644 --- a/src/Sentry.Unity.iOS/NativeScopeObserver.cs +++ b/src/Sentry.Unity.iOS/NativeScopeObserver.cs @@ -29,15 +29,26 @@ public override void SetUserImpl(SentryUser user) => public override void SetTraceImpl(SentryId traceId, SpanId spanId) => SentryCocoaBridgeProxy.SetTrace(traceId.ToString(), spanId.ToString()); + public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) + { + // iOS/macOS attachment sync to sentry-cocoa is not yet supported. + } + + public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) + { + // iOS/macOS attachment sync to sentry-cocoa is not yet supported. + } + + public override void ClearAttachmentsImpl() + { + // iOS/macOS attachment sync to sentry-cocoa is not yet supported. + } + internal static string GetTimestamp(DateTimeOffset timestamp) => // "o": Using ISO 8601 to make sure the timestamp makes it to the bridge correctly. // https://docs.microsoft.com/en-gb/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip timestamp.ToString("o"); - public override void AddAttachmentImpl(SentryAttachment attachment) { } - - public override void ClearAttachmentsImpl() { } - internal static int GetBreadcrumbLevel(BreadcrumbLevel breadcrumbLevel) => // https://github.com/getsentry/sentry-cocoa/blob/50f955aeb214601dd62b5dae7abdaddc8a1f24d9/Sources/Sentry/Public/SentryDefines.h#L99-L105 breadcrumbLevel switch diff --git a/src/Sentry.Unity/ScopeObserver.cs b/src/Sentry.Unity/ScopeObserver.cs index d4f66c6cc..3ae361163 100644 --- a/src/Sentry.Unity/ScopeObserver.cs +++ b/src/Sentry.Unity/ScopeObserver.cs @@ -89,11 +89,25 @@ public void SetTrace(SentryId traceId, SpanId spanId) public void AddAttachment(SentryAttachment attachment) { - _options.LogDebug("{0} Scope Sync - Adding attachment", _name); - AddAttachmentImpl(attachment); + if (attachment.Content is FileAttachmentContent fileContent) + { + _options.LogDebug("{0} Scope Sync - Adding file attachment \"{1}\"", _name, fileContent.FilePath); + AddFileAttachmentImpl(fileContent.FilePath, attachment.FileName, attachment.ContentType); + } + else if (attachment.Content is ByteAttachmentContent byteContent) + { + _options.LogDebug("{0} Scope Sync - Adding byte attachment \"{1}\" ({2} bytes)", _name, attachment.FileName, byteContent.Bytes.Length); + AddByteAttachmentImpl(byteContent.Bytes, attachment.FileName, attachment.ContentType); + } + else + { + _options.LogDebug("{0} Scope Sync - Skipping attachment \"{1}\" (unsupported content type for native sync)", _name, attachment.FileName); + } } - public abstract void AddAttachmentImpl(SentryAttachment attachment); + public abstract void AddFileAttachmentImpl(string filePath, string fileName, string? contentType); + + public abstract void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType); public void ClearAttachments() { diff --git a/test/Sentry.Unity.Android.Tests/TestSentryJava.cs b/test/Sentry.Unity.Android.Tests/TestSentryJava.cs index 08dbe299c..195d94221 100644 --- a/test/Sentry.Unity.Android.Tests/TestSentryJava.cs +++ b/test/Sentry.Unity.Android.Tests/TestSentryJava.cs @@ -54,4 +54,10 @@ public void SetUser(SentryUser user) { } public void UnsetUser() { } public void SetTrace(SentryId traceId, SpanId spanId) { } + + public void AddAttachment(string path, string fileName, string? contentType) { } + + public void AddAttachmentBytes(byte[] data, string fileName, string? contentType) { } + + public void ClearAttachments() { } }