diff --git a/CHANGELOG.md b/CHANGELOG.md index efc56ac3a..e55a99a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Features - Adopt generic variant type in public APIs ([#971](https://github.com/getsentry/sentry-unreal/pull/971)) +- Add runtime attachments support for Windows/Linux ([#982](https://github.com/getsentry/sentry-unreal/pull/982)) ### Dependencies diff --git a/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.cpp index 16534478a..d38d85641 100644 --- a/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.cpp @@ -2,6 +2,7 @@ #include "AndroidSentrySubsystem.h" +#include "AndroidSentryAttachment.h" #include "AndroidSentryBreadcrumb.h" #include "AndroidSentryEvent.h" #include "AndroidSentryId.h" @@ -127,6 +128,27 @@ void FAndroidSentrySubsystem::ClearBreadcrumbs() FSentryJavaObjectWrapper::CallStaticMethod(SentryJavaClasses::Sentry, "clearBreadcrumbs", "()V"); } +void FAndroidSentrySubsystem::AddAttachment(TSharedPtr attachment) +{ + TSharedPtr attachmentAndroid = StaticCastSharedPtr(attachment); + + FSentryJavaObjectWrapper::CallStaticMethod(SentryJavaClasses::SentryBridgeJava, "addAttachment", "(Lio/sentry/Attachment;)V", + attachmentAndroid->GetJObject()); +} + +void FAndroidSentrySubsystem::RemoveAttachment(TSharedPtr attachment) +{ + TSharedPtr attachmentAndroid = StaticCastSharedPtr(attachment); + + FSentryJavaObjectWrapper::CallStaticMethod(SentryJavaClasses::SentryBridgeJava, "removeAttachment", "(Lio/sentry/Attachment;)V", + attachmentAndroid->GetJObject()); +} + +void FAndroidSentrySubsystem::ClearAttachments() +{ + FSentryJavaObjectWrapper::CallStaticMethod(SentryJavaClasses::SentryBridgeJava, "clearAttachments", "()V"); +} + TSharedPtr FAndroidSentrySubsystem::CaptureMessage(const FString& message, ESentryLevel level) { auto id = FSentryJavaObjectWrapper::CallStaticObjectMethod(SentryJavaClasses::Sentry, "captureMessage", "(Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;", diff --git a/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.h b/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.h index 6981c0e5e..7286fc147 100644 --- a/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.h @@ -14,6 +14,9 @@ class FAndroidSentrySubsystem : public ISentrySubsystem virtual void AddBreadcrumb(TSharedPtr breadcrumb) override; virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap& Data, ESentryLevel Level) override; virtual void ClearBreadcrumbs() override; + virtual void AddAttachment(TSharedPtr attachment) override; + virtual void RemoveAttachment(TSharedPtr attachment) override; + virtual void ClearAttachments() override; virtual TSharedPtr CaptureMessage(const FString& message, ESentryLevel level) override; virtual TSharedPtr CaptureMessageWithScope(const FString& message, ESentryLevel level, const FSentryScopeDelegate& onConfigureScope) override; virtual TSharedPtr CaptureEvent(TSharedPtr event) override; diff --git a/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java b/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java index 3e1cf4eb9..3ef17eedb 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java +++ b/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java @@ -14,6 +14,7 @@ import java.util.HashMap; import java.util.Map; +import io.sentry.Attachment; import io.sentry.Breadcrumb; import io.sentry.Hint; import io.sentry.IScopes; @@ -225,4 +226,17 @@ public static Object getScopeContext(final IScope scope, final String key) { public static void setScopeExtra(final IScope scope, final String key, final Object values) { scope.setExtra(key, values.toString()); } + + public static void addAttachment(final Attachment attachment) { + Sentry.getGlobalScope().addAttachment(attachment); + } + + public static void removeAttachment(final Attachment attachment) { + // Currently, Android SDK doesn't have API allowing to remove individual attachments + } + + public static void clearAttachments() { + Sentry.getGlobalScope().clearAttachments(); + } + } \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.cpp index e2316e307..93658a014 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.cpp @@ -2,6 +2,7 @@ #include "AppleSentrySubsystem.h" +#include "AppleSentryAttachment.h" #include "AppleSentryBreadcrumb.h" #include "AppleSentryEvent.h" #include "AppleSentryId.h" @@ -202,6 +203,27 @@ void FAppleSentrySubsystem::ClearBreadcrumbs() }]; } +void FAppleSentrySubsystem::AddAttachment(TSharedPtr attachment) +{ + TSharedPtr attachmentApple = StaticCastSharedPtr(attachment); + + [SentrySDK configureScope:^(SentryScope* scope) { + [scope addAttachment:attachmentApple->GetNativeObject()]; + }]; +} + +void FAppleSentrySubsystem::RemoveAttachment(TSharedPtr attachment) +{ + // Currently, Cocoa SDK doesn't have API allowing to remove individual attachments +} + +void FAppleSentrySubsystem::ClearAttachments() +{ + [SentrySDK configureScope:^(SentryScope* scope) { + [scope clearAttachments]; + }]; +} + TSharedPtr FAppleSentrySubsystem::CaptureMessage(const FString& message, ESentryLevel level) { FSentryScopeDelegate onConfigureScope; diff --git a/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.h b/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.h index dd231b6c4..b4a9b6aff 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.h @@ -14,6 +14,9 @@ class FAppleSentrySubsystem : public ISentrySubsystem virtual void AddBreadcrumb(TSharedPtr breadcrumb) override; virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap& Data, ESentryLevel Level) override; virtual void ClearBreadcrumbs() override; + virtual void AddAttachment(TSharedPtr attachment) override; + virtual void RemoveAttachment(TSharedPtr attachment) override; + virtual void ClearAttachments() override; virtual TSharedPtr CaptureMessage(const FString& message, ESentryLevel level) override; virtual TSharedPtr CaptureMessageWithScope(const FString& message, ESentryLevel level, const FSentryScopeDelegate& onConfigureScope) override; virtual TSharedPtr CaptureEvent(TSharedPtr event) override; diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.cpp b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.cpp new file mode 100644 index 000000000..8a8244a22 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2025 Sentry. All Rights Reserved. + +#include "GenericPlatformSentryAttachment.h" + +#if USE_SENTRY_NATIVE + +FGenericPlatformSentryAttachment::FGenericPlatformSentryAttachment(const TArray& data, const FString& filename, const FString& contentType) + : Data(data), Filename(filename), ContentType(contentType), Attachment(nullptr) +{ +} + +FGenericPlatformSentryAttachment::FGenericPlatformSentryAttachment(const FString& path, const FString& filename, const FString& contentType) + : Path(path), Filename(filename), ContentType(contentType), Attachment(nullptr) +{ +} + +FGenericPlatformSentryAttachment::~FGenericPlatformSentryAttachment() +{ + // Put custom destructor logic here if needed +} + +void FGenericPlatformSentryAttachment::SetNativeObject(sentry_attachment_t* attachment) +{ + Attachment = attachment; +} + +sentry_attachment_t* FGenericPlatformSentryAttachment::GetNativeObject() +{ + return Attachment; +} + +TArray FGenericPlatformSentryAttachment::GetData() const +{ + return Data; +} + +FString FGenericPlatformSentryAttachment::GetPath() const +{ + return Path; +} + +FString FGenericPlatformSentryAttachment::GetFilename() const +{ + return Filename; +} + +FString FGenericPlatformSentryAttachment::GetContentType() const +{ + return ContentType; +} + +const TArray& FGenericPlatformSentryAttachment::GetDataByRef() const +{ + return Data; +} + +#endif diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.h b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.h new file mode 100644 index 000000000..24dd67d04 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.h @@ -0,0 +1,39 @@ +// Copyright (c) 2025 Sentry. All Rights Reserved. + +#pragma once + +#include "Convenience/GenericPlatformSentryInclude.h" + +#include "Interface/SentryAttachmentInterface.h" + +#if USE_SENTRY_NATIVE + +class FGenericPlatformSentryAttachment : public ISentryAttachment +{ +public: + FGenericPlatformSentryAttachment(const TArray& data, const FString& filename, const FString& contentType); + FGenericPlatformSentryAttachment(const FString& path, const FString& filename, const FString& contentType); + virtual ~FGenericPlatformSentryAttachment() override; + + void SetNativeObject(sentry_attachment_t* attachment); + sentry_attachment_t* GetNativeObject(); + + virtual TArray GetData() const override; + virtual FString GetPath() const override; + virtual FString GetFilename() const override; + virtual FString GetContentType() const override; + + const TArray& GetDataByRef() const; + +private: + TArray Data; + FString Path; + FString Filename; + FString ContentType; + + sentry_attachment_t* Attachment; +}; + +typedef FGenericPlatformSentryAttachment FPlatformSentryAttachment; + +#endif diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.cpp b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.cpp index 97f703290..62562f09a 100644 --- a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.cpp +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2025 Sentry. All Rights Reserved. #include "GenericPlatformSentryScope.h" +#include "GenericPlatformSentryAttachment.h" #include "GenericPlatformSentryBreadcrumb.h" #include "GenericPlatformSentryEvent.h" @@ -39,12 +40,12 @@ void FGenericPlatformSentryScope::ClearBreadcrumbs() void FGenericPlatformSentryScope::AddAttachment(TSharedPtr attachment) { - // Not available for generic platform + Attachments.Add(StaticCastSharedPtr(attachment)); } void FGenericPlatformSentryScope::ClearAttachments() { - // Not available for generic platform + Attachments.Empty(); } void FGenericPlatformSentryScope::SetTag(const FString& key, const FString& value) @@ -195,6 +196,18 @@ void FGenericPlatformSentryScope::Apply(sentry_scope_t* scope) sentry_scope_add_breadcrumb(scope, nativeBreadcrumb); } + for (auto& Attachment : Attachments) + { + if (!Attachment->GetPath().IsEmpty()) + { + AddFileAttachment(Attachment, scope); + } + else + { + AddByteAttachment(Attachment, scope); + } + } + if (Fingerprint.Num() > 0) { sentry_scope_set_fingerprints(scope, FGenericPlatformSentryConverters::StringArrayToNative(Fingerprint)); @@ -218,4 +231,31 @@ void FGenericPlatformSentryScope::Apply(sentry_scope_t* scope) sentry_scope_set_level(scope, FGenericPlatformSentryConverters::SentryLevelToNative(Level)); } +void FGenericPlatformSentryScope::AddFileAttachment(TSharedPtr attachment, sentry_scope_t* scope) +{ + sentry_attachment_t* nativeAttachment = + sentry_scope_attach_file(scope, TCHAR_TO_UTF8(*attachment->GetPath())); + + if (!attachment->GetFilename().IsEmpty()) + sentry_attachment_set_filename(nativeAttachment, TCHAR_TO_UTF8(*attachment->GetFilename())); + + if (!attachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*attachment->GetContentType())); + + attachment->SetNativeObject(nativeAttachment); +} + +void FGenericPlatformSentryScope::AddByteAttachment(TSharedPtr attachment, sentry_scope_t* scope) +{ + const TArray& byteBuf = attachment->GetDataByRef(); + + sentry_attachment_t* nativeAttachment = + sentry_scope_attach_bytes(scope, reinterpret_cast(byteBuf.GetData()), byteBuf.Num(), TCHAR_TO_UTF8(*attachment->GetFilename())); + + if (!attachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*attachment->GetContentType())); + + attachment->SetNativeObject(nativeAttachment); +} + #endif diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.h b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.h index b9413b81e..18d4bf529 100644 --- a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.h +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentryScope.h @@ -9,6 +9,7 @@ #if USE_SENTRY_NATIVE +class FGenericPlatformSentryAttachment; class FGenericPlatformSentryBreadcrumb; class FGenericPlatformSentryEvent; @@ -46,6 +47,10 @@ class FGenericPlatformSentryScope : public ISentryScope void Apply(sentry_scope_t* scope); +protected: + virtual void AddFileAttachment(TSharedPtr attachment, sentry_scope_t* scope); + virtual void AddByteAttachment(TSharedPtr attachment, sentry_scope_t* scope); + private: FString Dist; FString Environment; @@ -59,9 +64,13 @@ class FGenericPlatformSentryScope : public ISentryScope TRingBuffer> Breadcrumbs; + TArray> Attachments; + ESentryLevel Level; }; +#if !PLATFORM_MICROSOFT typedef FGenericPlatformSentryScope FPlatformSentryScope; +#endif #endif \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp index 7979e2085..269a4e469 100644 --- a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2025 Sentry. All Rights Reserved. #include "GenericPlatformSentrySubsystem.h" +#include "GenericPlatformSentryAttachment.h" #include "GenericPlatformSentryBreadcrumb.h" #include "GenericPlatformSentryEvent.h" #include "GenericPlatformSentryId.h" @@ -205,6 +206,41 @@ void FGenericPlatformSentrySubsystem::InitCrashReporter(const FString& release, crashReporter->SetEnvironment(environment); } +void FGenericPlatformSentrySubsystem::AddFileAttachment(TSharedPtr attachment) +{ + TSharedPtr platformAttachment = StaticCastSharedPtr(attachment); + + sentry_attachment_t* nativeAttachment = + sentry_attach_file(TCHAR_TO_UTF8(*platformAttachment->GetPath())); + + if (!platformAttachment->GetFilename().IsEmpty()) + sentry_attachment_set_filename(nativeAttachment, TCHAR_TO_UTF8(*platformAttachment->GetFilename())); + + if (!platformAttachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*platformAttachment->GetContentType())); + + platformAttachment->SetNativeObject(nativeAttachment); + + attachments.Add(platformAttachment); +} + +void FGenericPlatformSentrySubsystem::AddByteAttachment(TSharedPtr attachment) +{ + TSharedPtr platformAttachment = StaticCastSharedPtr(attachment); + + const TArray& byteBuf = platformAttachment->GetDataByRef(); + + sentry_attachment_t* nativeAttachment = + sentry_attach_bytes(reinterpret_cast(byteBuf.GetData()), byteBuf.Num(), TCHAR_TO_UTF8(*platformAttachment->GetFilename())); + + if (!platformAttachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*platformAttachment->GetContentType())); + + platformAttachment->SetNativeObject(nativeAttachment); + + attachments.Add(platformAttachment); +} + FGenericPlatformSentrySubsystem::FGenericPlatformSentrySubsystem() : beforeSend(nullptr) , beforeBreadcrumb(nullptr) @@ -381,6 +417,42 @@ void FGenericPlatformSentrySubsystem::ClearBreadcrumbs() // Not implemented in sentry-native } +void FGenericPlatformSentrySubsystem::AddAttachment(TSharedPtr attachment) +{ + if (!attachment->GetPath().IsEmpty()) + { + AddFileAttachment(attachment); + } + else + { + AddByteAttachment(attachment); + } +} + +void FGenericPlatformSentrySubsystem::RemoveAttachment(TSharedPtr attachment) +{ + TSharedPtr platformAttachment = StaticCastSharedPtr(attachment); + + sentry_attachment_t* nativeAttachment = platformAttachment->GetNativeObject(); + + if (!nativeAttachment) + return; + + sentry_remove_attachment(nativeAttachment); + + platformAttachment->SetNativeObject(nullptr); +} + +void FGenericPlatformSentrySubsystem::ClearAttachments() +{ + for (auto& attachment : attachments) + { + RemoveAttachment(attachment); + } + + attachments.Empty(); +} + TSharedPtr FGenericPlatformSentrySubsystem::CaptureMessage(const FString& message, ESentryLevel level) { sentry_value_t nativeEvent = sentry_value_new_message_event(FGenericPlatformSentryConverters::SentryLevelToNative(level), nullptr, TCHAR_TO_UTF8(*message)); diff --git a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.h b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.h index a20f78b43..a9efab927 100644 --- a/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.h @@ -8,6 +8,7 @@ #include "HAL/CriticalSection.h" +class FGenericPlatformSentryAttachment; class FGenericPlatformSentryScope; class FGenericPlatformSentryCrashReporter; @@ -25,6 +26,9 @@ class FGenericPlatformSentrySubsystem : public ISentrySubsystem virtual void AddBreadcrumb(TSharedPtr breadcrumb) override; virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap& Data, ESentryLevel Level) override; virtual void ClearBreadcrumbs() override; + virtual void AddAttachment(TSharedPtr attachment) override; + virtual void RemoveAttachment(TSharedPtr attachment) override; + virtual void ClearAttachments() override; virtual TSharedPtr CaptureMessage(const FString& message, ESentryLevel level) override; virtual TSharedPtr CaptureMessageWithScope(const FString& message, ESentryLevel level, const FSentryScopeDelegate& onConfigureScope) override; virtual TSharedPtr CaptureEvent(TSharedPtr event) override; @@ -71,6 +75,11 @@ class FGenericPlatformSentrySubsystem : public ISentrySubsystem void InitCrashReporter(const FString& release, const FString& environment); + virtual void AddFileAttachment(TSharedPtr attachment); + virtual void AddByteAttachment(TSharedPtr attachment); + + TArray> attachments; + private: /** * Static wrappers that are passed to the Sentry library. diff --git a/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryAttachment.h b/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryAttachment.h index f4a8e4520..38b2fc4db 100644 --- a/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryAttachment.h +++ b/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryAttachment.h @@ -6,6 +6,8 @@ #include "Android/AndroidSentryAttachment.h" #elif PLATFORM_APPLE #include "Apple/AppleSentryAttachment.h" +#elif USE_SENTRY_NATIVE +#include "GenericPlatform/GenericPlatformSentryAttachment.h" #else #include "Null/NullSentryAttachment.h" #endif diff --git a/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryScope.h b/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryScope.h index c1aedf176..0d096dad4 100644 --- a/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryScope.h +++ b/plugin-dev/Source/Sentry/Private/HAL/PlatformSentryScope.h @@ -6,6 +6,8 @@ #include "Android/AndroidSentryScope.h" #elif PLATFORM_APPLE #include "Apple/AppleSentryScope.h" +#elif PLATFORM_MICROSOFT +#include "Microsoft/MicrosoftSentryScope.h" #elif USE_SENTRY_NATIVE #include "GenericPlatform/GenericPlatformSentryScope.h" #else diff --git a/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h b/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h index b31d10e89..58f503fcb 100644 --- a/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h +++ b/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h @@ -7,6 +7,7 @@ #include "SentryDataTypes.h" #include "SentryVariant.h" +class ISentryAttachment; class ISentryBreadcrumb; class ISentryEvent; class ISentryUserFeedback; @@ -35,6 +36,9 @@ class ISentrySubsystem virtual void AddBreadcrumb(TSharedPtr breadcrumb) = 0; virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap& Data, ESentryLevel Level) = 0; virtual void ClearBreadcrumbs() = 0; + virtual void AddAttachment(TSharedPtr attachment) = 0; + virtual void RemoveAttachment(TSharedPtr attachment) = 0; + virtual void ClearAttachments() = 0; virtual TSharedPtr CaptureMessage(const FString& message, ESentryLevel level) = 0; virtual TSharedPtr CaptureMessageWithScope(const FString& message, ESentryLevel level, const FSentryScopeDelegate& onConfigureScope) = 0; virtual TSharedPtr CaptureEvent(TSharedPtr event) = 0; diff --git a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.cpp b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.cpp new file mode 100644 index 000000000..cf5e111c8 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2025 Sentry. All Rights Reserved. + +#include "MicrosoftSentryScope.h" + +#include "GenericPlatform/GenericPlatformSentryAttachment.h" + +void FMicrosoftSentryScope::AddFileAttachment(TSharedPtr attachment, sentry_scope_t* scope) +{ + sentry_attachment_t* nativeAttachment = + sentry_scope_attach_filew(scope, *attachment->GetPath()); + + if (!attachment->GetFilename().IsEmpty()) + sentry_attachment_set_filenamew(nativeAttachment, *attachment->GetFilename()); + + if (!attachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*attachment->GetContentType())); + + attachment->SetNativeObject(nativeAttachment); +} + +void FMicrosoftSentryScope::AddByteAttachment(TSharedPtr attachment, sentry_scope_t* scope) +{ + const TArray& byteBuf = attachment->GetDataByRef(); + + sentry_attachment_t* nativeAttachment = + sentry_scope_attach_bytesw(scope, reinterpret_cast(byteBuf.GetData()), byteBuf.Num(), *attachment->GetFilename()); + + if (!attachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*attachment->GetContentType())); + + attachment->SetNativeObject(nativeAttachment); +} \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.h b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.h new file mode 100644 index 000000000..4e39f1d81 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentryScope.h @@ -0,0 +1,21 @@ +// Copyright (c) 2025 Sentry. All Rights Reserved. + +#pragma once + +#if USE_SENTRY_NATIVE + +#include "GenericPlatform/GenericPlatformSentryScope.h" + +class FMicrosoftSentryScope : public FGenericPlatformSentryScope +{ +public: + virtual ~FMicrosoftSentryScope() override = default; + +protected: + virtual void AddFileAttachment(TSharedPtr attachment, sentry_scope_t* scope) override; + virtual void AddByteAttachment(TSharedPtr attachment, sentry_scope_t* scope) override; +}; + +typedef FMicrosoftSentryScope FPlatformSentryScope; + +#endif diff --git a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp index e940cafb0..8cad4879f 100644 --- a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp @@ -10,6 +10,8 @@ #include "SentryModule.h" #include "SentrySettings.h" +#include "GenericPlatform/GenericPlatformSentryAttachment.h" + #include "GenericPlatform/GenericPlatformOutputDevices.h" #include "Misc/EngineVersionComparison.h" @@ -67,4 +69,39 @@ void FMicrosoftSentrySubsystem::ConfigureScreenshotAttachment(sentry_options_t* sentry_options_add_attachmentw(Options, *GetScreenshotPath()); } +void FMicrosoftSentrySubsystem::AddFileAttachment(TSharedPtr attachment) +{ + TSharedPtr platformAttachment = StaticCastSharedPtr(attachment); + + sentry_attachment_t* nativeAttachment = + sentry_attach_filew(*platformAttachment->GetPath()); + + if (!platformAttachment->GetFilename().IsEmpty()) + sentry_attachment_set_filenamew(nativeAttachment, *platformAttachment->GetFilename()); + + if (!platformAttachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*platformAttachment->GetContentType())); + + platformAttachment->SetNativeObject(nativeAttachment); + + attachments.Add(platformAttachment); +} + +void FMicrosoftSentrySubsystem::AddByteAttachment(TSharedPtr attachment) +{ + TSharedPtr platformAttachment = StaticCastSharedPtr(attachment); + + const TArray& byteBuf = platformAttachment->GetDataByRef(); + + sentry_attachment_t* nativeAttachment = + sentry_attach_bytesw(reinterpret_cast(byteBuf.GetData()), byteBuf.Num(), *platformAttachment->GetFilename()); + + if (!platformAttachment->GetContentType().IsEmpty()) + sentry_attachment_set_content_type(nativeAttachment, TCHAR_TO_UTF8(*platformAttachment->GetContentType())); + + platformAttachment->SetNativeObject(nativeAttachment); + + attachments.Add(platformAttachment); +} + #endif // USE_SENTRY_NATIVE diff --git a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h index 071b52da0..45bce50bb 100644 --- a/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h @@ -18,6 +18,9 @@ class FMicrosoftSentrySubsystem : public FGenericPlatformSentrySubsystem virtual void ConfigureDatabasePath(sentry_options_t* Options) override; virtual void ConfigureLogFileAttachment(sentry_options_t* Options) override; virtual void ConfigureScreenshotAttachment(sentry_options_t* Options) override; + + virtual void AddFileAttachment(TSharedPtr attachment) override; + virtual void AddByteAttachment(TSharedPtr attachment) override; }; #endif // USE_SENTRY_NATIVE diff --git a/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp index 451564740..193df3014 100644 --- a/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp @@ -25,6 +25,7 @@ #include "Misc/AssertionMacros.h" #include "Misc/CoreDelegates.h" #include "Misc/EngineVersion.h" +#include "SentryAttachment.h" #include "Interface/SentrySubsystemInterface.h" @@ -246,6 +247,30 @@ void USentrySubsystem::ClearBreadcrumbs() SubsystemNativeImpl->ClearBreadcrumbs(); } +void USentrySubsystem::AddAttachment(USentryAttachment* Attachment) +{ + check(SubsystemNativeImpl); + + if (!SubsystemNativeImpl || !SubsystemNativeImpl->IsEnabled()) + { + return; + } + + SubsystemNativeImpl->AddAttachment(Attachment->GetNativeObject()); +} + +void USentrySubsystem::ClearAttachments() +{ + check(SubsystemNativeImpl); + + if (!SubsystemNativeImpl || !SubsystemNativeImpl->IsEnabled()) + { + return; + } + + SubsystemNativeImpl->ClearAttachments(); +} + FString USentrySubsystem::CaptureMessage(const FString& Message, ESentryLevel Level) { check(SubsystemNativeImpl); diff --git a/plugin-dev/Source/Sentry/Public/SentrySubsystem.h b/plugin-dev/Source/Sentry/Public/SentrySubsystem.h index 8e8a23c7f..7ae42df24 100644 --- a/plugin-dev/Source/Sentry/Public/SentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Public/SentrySubsystem.h @@ -104,6 +104,18 @@ class SENTRY_API USentrySubsystem : public UEngineSubsystem UFUNCTION(BlueprintCallable, Category = "Sentry") void ClearBreadcrumbs(); + /** + * Adds an attachment to the current Scope. + * + * @param Attachment The attachment that will be added to every event. + */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void AddAttachment(USentryAttachment* Attachment); + + /** Clears all previously added attachments from the current scope. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void ClearAttachments(); + /** * Captures the message. * diff --git a/scripts/packaging/package-github.snapshot b/scripts/packaging/package-github.snapshot index 51ce8678c..698e2638a 100644 --- a/scripts/packaging/package-github.snapshot +++ b/scripts/packaging/package-github.snapshot @@ -80,6 +80,8 @@ Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashCo Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashContext.h Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashReporter.cpp Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashReporter.h +Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.cpp +Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.h Source/Sentry/Private/GenericPlatform/GenericPlatformSentryBreadcrumb.cpp Source/Sentry/Private/GenericPlatform/GenericPlatformSentryBreadcrumb.h Source/Sentry/Private/GenericPlatform/GenericPlatformSentryEvent.cpp @@ -138,6 +140,8 @@ Source/Sentry/Private/Linux/LinuxSentryUser.h Source/Sentry/Private/Mac/MacSentrySubsystem.cpp Source/Sentry/Private/Mac/MacSentrySubsystem.h Source/Sentry/Private/Mac/MacSentryUser.h +Source/Sentry/Private/Microsoft/MicrosoftSentryScope.cpp +Source/Sentry/Private/Microsoft/MicrosoftSentryScope.h Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h Source/Sentry/Private/Null/NullSentryAttachment.h diff --git a/scripts/packaging/package-marketplace.snapshot b/scripts/packaging/package-marketplace.snapshot index 1f6f70199..ca7664995 100644 --- a/scripts/packaging/package-marketplace.snapshot +++ b/scripts/packaging/package-marketplace.snapshot @@ -79,6 +79,8 @@ Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashCo Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashContext.h Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashReporter.cpp Source/Sentry/Private/GenericPlatform/CrashReporter/GenericPlatformSentryCrashReporter.h +Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.cpp +Source/Sentry/Private/GenericPlatform/GenericPlatformSentryAttachment.h Source/Sentry/Private/GenericPlatform/GenericPlatformSentryBreadcrumb.cpp Source/Sentry/Private/GenericPlatform/GenericPlatformSentryBreadcrumb.h Source/Sentry/Private/GenericPlatform/GenericPlatformSentryEvent.cpp @@ -137,6 +139,8 @@ Source/Sentry/Private/Linux/LinuxSentryUser.h Source/Sentry/Private/Mac/MacSentrySubsystem.cpp Source/Sentry/Private/Mac/MacSentrySubsystem.h Source/Sentry/Private/Mac/MacSentryUser.h +Source/Sentry/Private/Microsoft/MicrosoftSentryScope.cpp +Source/Sentry/Private/Microsoft/MicrosoftSentryScope.h Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.cpp Source/Sentry/Private/Microsoft/MicrosoftSentrySubsystem.h Source/Sentry/Private/Null/NullSentryAttachment.h