From ae49e204e7d51cc862465580377f0fe78aeb4492 Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Fri, 19 Jan 2024 11:18:59 +0200 Subject: [PATCH] Add performance monitoring API (#470) * Add tracing settings * Update tracing init for Apple * Add tracing init for Android * Replace switch in Apple tracing init * Add tracing init for desktop * Add placeholder classes for performance monitoring API * Update plugin snapshot * Add get/set methods for Span and Trancaction native impl * Add minimap API for starting/finishing transactions * Add basic spans implementation * Add missing implementation parts * Add performance test workflow to demo * Fix Android crash * Add transaction and span convertors for desktop * Add more performance monitoring API methods * Fix comment * Fix method signature * Add missing Android implmentations * Update sample * Remove transaction SetName implementation * Update settings order * Update changelog * Fix members init order * Add const specifier to IsFinished method * Add automation test for transaction and span * Update plugin-dev/Source/Sentry/Private/SentrySettings.cpp Co-authored-by: Stefan Jandl * Add missing implementation for Android span * Add log messages about sampling functions not being implemented * Add log message about missing transaction SetName implementation for Apple --------- Co-authored-by: Stefan Jandl --- CHANGELOG.md | 1 + .../SentryConvertorsAndroid.cpp | 20 ++++ .../Infrastructure/SentryConvertorsAndroid.h | 4 + .../Infrastructure/SentryJavaClasses.cpp | 2 + .../Infrastructure/SentryJavaClasses.h | 2 + .../Android/Java/SentryBridgeJava.java | 15 +++ .../Private/Android/Jni/SentryJniAndroid.cpp | 5 + .../Private/Android/SentrySpanAndroid.cpp | 50 ++++++++++ .../Private/Android/SentrySpanAndroid.h | 29 ++++++ .../Android/SentrySubsystemAndroid.cpp | 18 ++++ .../Private/Android/SentrySubsystemAndroid.h | 1 + .../Android/SentryTransactionAndroid.cpp | 63 ++++++++++++ .../Android/SentryTransactionAndroid.h | 32 ++++++ .../Infrastructure/SentryConvertorsApple.cpp | 20 ++++ .../Infrastructure/SentryConvertorsApple.h | 3 + .../Sentry/Private/Apple/SentrySpanApple.cpp | 48 +++++++++ .../Sentry/Private/Apple/SentrySpanApple.h | 27 +++++ .../Private/Apple/SentrySubsystemApple.cpp | 20 ++++ .../Private/Apple/SentrySubsystemApple.h | 1 + .../Private/Apple/SentryTransactionApple.cpp | 67 +++++++++++++ .../Private/Apple/SentryTransactionApple.h | 28 ++++++ .../SentryConvertorsDesktop.cpp | 20 ++++ .../Infrastructure/SentryConvertorsDesktop.h | 4 + .../Private/Desktop/SentrySpanDesktop.cpp | 65 +++++++++++++ .../Private/Desktop/SentrySpanDesktop.h | 36 +++++++ .../Desktop/SentrySubsystemDesktop.cpp | 24 ++++- .../Private/Desktop/SentrySubsystemDesktop.h | 1 + .../Desktop/SentryTransactionDesktop.cpp | 80 +++++++++++++++ .../Desktop/SentryTransactionDesktop.h | 38 ++++++++ .../Private/Interface/SentrySpanInterface.h | 18 ++++ .../Interface/SentrySubsystemInterface.h | 2 + .../Interface/SentryTransactionInterface.h | 22 +++++ .../Source/Sentry/Private/SentrySettings.cpp | 3 + .../Source/Sentry/Private/SentrySpan.cpp | 75 ++++++++++++++ .../Source/Sentry/Private/SentrySubsystem.cpp | 8 ++ .../Sentry/Private/SentryTransaction.cpp | 92 ++++++++++++++++++ .../Private/Tests/SentrySubsystem.spec.cpp | 22 +++++ .../Source/Sentry/Public/SentrySettings.h | 27 +++++ plugin-dev/Source/Sentry/Public/SentrySpan.h | 51 ++++++++++ .../Source/Sentry/Public/SentrySubsystem.h | 13 ++- .../Source/Sentry/Public/SentryTransaction.h | 60 ++++++++++++ sample/Content/UI/W_SentryDemo.uasset | Bin 179245 -> 290207 bytes scripts/packaging/package-github.snapshot | 18 ++++ .../packaging/package-marketplace.snapshot | 18 ++++ 44 files changed, 1151 insertions(+), 2 deletions(-) create mode 100644 plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h create mode 100644 plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.h create mode 100644 plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.h create mode 100644 plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.h create mode 100644 plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.h create mode 100644 plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.cpp create mode 100644 plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.h create mode 100644 plugin-dev/Source/Sentry/Private/Interface/SentrySpanInterface.h create mode 100644 plugin-dev/Source/Sentry/Private/Interface/SentryTransactionInterface.h create mode 100644 plugin-dev/Source/Sentry/Private/SentrySpan.cpp create mode 100644 plugin-dev/Source/Sentry/Private/SentryTransaction.cpp create mode 100644 plugin-dev/Source/Sentry/Public/SentrySpan.h create mode 100644 plugin-dev/Source/Sentry/Public/SentryTransaction.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c6ac7bb..2b93f8c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- Add performance monitoring API ([#470](https://github.com/getsentry/sentry-unreal/pull/470)) - Add `IsCrashedLastRun` allowing to check whether the app crashed during its last run ([#483](https://github.com/getsentry/sentry-unreal/pull/483)) ### Fixes diff --git a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.cpp b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.cpp index 9c5caaa8..27e80a5a 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.cpp +++ b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.cpp @@ -6,10 +6,14 @@ #include "SentryScope.h" #include "SentryId.h" +#include "SentryTransaction.h" +#include "SentrySpan.h" #include "SentryDefines.h" #include "Android/SentryScopeAndroid.h" #include "Android/SentryIdAndroid.h" +#include "Android/SentryTransactionAndroid.h" +#include "Android/SentrySpanAndroid.h" #include "Android/AndroidApplication.h" #include "Android/AndroidJavaEnv.h" @@ -149,6 +153,22 @@ USentryId* SentryConvertorsAndroid::SentryIdToUnreal(jobject id) return unrealId; } +USentryTransaction* SentryConvertorsAndroid::SentryTransactionToUnreal(jobject transaction) +{ + TSharedPtr transactionNativeImpl = MakeShareable(new SentryTransactionAndroid(transaction)); + USentryTransaction* unrealTransaction = NewObject(); + unrealTransaction->InitWithNativeImpl(transactionNativeImpl); + return unrealTransaction; +} + +USentrySpan* SentryConvertorsAndroid::SentrySpanToUnreal(jobject span) +{ + TSharedPtr spanNativeImpl = MakeShareable(new SentrySpanAndroid(span)); + USentrySpan* unrealSpan = NewObject(); + unrealSpan->InitWithNativeImpl(spanNativeImpl); + return unrealSpan; +} + TMap SentryConvertorsAndroid::StringMapToUnreal(jobject map) { TMap result; diff --git a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.h b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.h index 0c91f567..c93f40dd 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.h +++ b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryConvertorsAndroid.h @@ -8,6 +8,8 @@ class USentryScope; class USentryId; +class USentryTransaction; +class USentrySpan; class FSentryJavaObjectWrapper; class FJsonValue; @@ -24,6 +26,8 @@ class SentryConvertorsAndroid static ESentryLevel SentryLevelToUnreal(jobject level); static USentryScope* SentryScopeToUnreal(jobject scope); static USentryId* SentryIdToUnreal(jobject id); + static USentryTransaction* SentryTransactionToUnreal(jobject transaction); + static USentrySpan* SentrySpanToUnreal(jobject span); static TMap StringMapToUnreal(jobject stringMap); static TArray StringListToUnreal(jobject stringList); static TArray ByteArrayToUnreal(jbyteArray byteArray); diff --git a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.cpp b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.cpp index 2ca85e2c..bb2b332e 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.cpp +++ b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.cpp @@ -15,6 +15,8 @@ const FSentryJavaClass SentryJavaClasses::UserFeedback = FSentryJavaClass { "io const FSentryJavaClass SentryJavaClasses::Message = FSentryJavaClass { "io/sentry/protocol/Message", ESentryJavaClassType::External }; const FSentryJavaClass SentryJavaClasses::SentryLevel = FSentryJavaClass { "io/sentry/SentryLevel", ESentryJavaClassType::External }; const FSentryJavaClass SentryJavaClasses::SentryHint = FSentryJavaClass { "io/sentry/Hint", ESentryJavaClassType::External }; +const FSentryJavaClass SentryJavaClasses::Transaction = FSentryJavaClass { "io/sentry/ITransaction", ESentryJavaClassType::External }; +const FSentryJavaClass SentryJavaClasses::Span = FSentryJavaClass { "io/sentry/ISpan", ESentryJavaClassType::External }; // System Java classes definitions const FSentryJavaClass SentryJavaClasses::ArrayList = FSentryJavaClass { "java/util/ArrayList", ESentryJavaClassType::System }; diff --git a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.h b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.h index 04703260..c37e773a 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.h +++ b/plugin-dev/Source/Sentry/Private/Android/Infrastructure/SentryJavaClasses.h @@ -19,6 +19,8 @@ struct SentryJavaClasses const static FSentryJavaClass Message; const static FSentryJavaClass SentryLevel; const static FSentryJavaClass SentryHint; + const static FSentryJavaClass Transaction; + const static FSentryJavaClass Span; // System Java classes const static FSentryJavaClass ArrayList; diff --git a/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java b/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java index eee8da5a..118ffb20 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java +++ b/plugin-dev/Source/Sentry/Private/Android/Java/SentryBridgeJava.java @@ -17,6 +17,7 @@ import io.sentry.Breadcrumb; import io.sentry.Hint; import io.sentry.IHub; +import io.sentry.SamplingContext; import io.sentry.IScope; import io.sentry.ScopeCallback; import io.sentry.Sentry; @@ -30,6 +31,7 @@ public class SentryBridgeJava { public static native void onConfigureScope(long callbackAddr, IScope scope); public static native SentryEvent onBeforeSend(long handlerAddr, SentryEvent event, Hint hint); + public static native Double onTracesSampler(long samplerAddr, SamplingContext samplingContext); public static void init(Activity activity, final String settingsJsonStr, final long beforeSendHandler) { SentryAndroid.init(activity, new Sentry.OptionsConfiguration() { @@ -62,6 +64,19 @@ public SentryEvent execute(SentryEvent event, Hint hint) { for (int i = 0; i < Excludes.length(); i++) { options.addInAppExclude(Excludes.getString(i)); } + options.setEnableTracing(settingJson.getBoolean("enableTracing")); + if(settingJson.has("tracesSampleRate")) { + options.setTracesSampleRate(settingJson.getDouble("tracesSampleRate")); + } + if(settingJson.has("tracesSampler")) { + final long samplerAddr = settingJson.getLong("tracesSampler"); + options.setTracesSampler(new SentryOptions.TracesSamplerCallback() { + @Override + public Double sample(SamplingContext samplingContext) { + return onTracesSampler(samplerAddr, samplingContext); + } + }); + } } catch (JSONException e) { throw new RuntimeException(e); } diff --git a/plugin-dev/Source/Sentry/Private/Android/Jni/SentryJniAndroid.cpp b/plugin-dev/Source/Sentry/Private/Android/Jni/SentryJniAndroid.cpp index cb7369ae..cd93899d 100644 --- a/plugin-dev/Source/Sentry/Private/Android/Jni/SentryJniAndroid.cpp +++ b/plugin-dev/Source/Sentry/Private/Android/Jni/SentryJniAndroid.cpp @@ -31,4 +31,9 @@ JNI_METHOD jobject Java_io_sentry_unreal_SentryBridgeJava_onBeforeSend(JNIEnv* e HintToProcess->InitWithNativeImpl(MakeShareable(new SentryHintAndroid(hint))); return handler->HandleBeforeSend(EventToProcess, HintToProcess) ? event : nullptr; +} + +JNI_METHOD jobject Java_io_sentry_unreal_SentryBridgeJava_onTracesSampler(JNIEnv* env, jclass clazz, jlong objAddr, jobject samplingContext) +{ + return nullptr; } \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp b/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp new file mode 100644 index 00000000..5c401a7e --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentrySpanAndroid.h" + +#include "Infrastructure/SentryConvertorsAndroid.h" +#include "Infrastructure/SentryJavaClasses.h" + +SentrySpanAndroid::SentrySpanAndroid(jobject span) + : FSentryJavaObjectWrapper(SentryJavaClasses::Span, span) +{ + SetupClassMethods(); +} + +void SentrySpanAndroid::SetupClassMethods() +{ + FinishMethod = GetMethod("finish", "()V"); + IsFinishedMethod = GetMethod("isFinished", "()Z"); + SetTagMethod = GetMethod("setTag", "(Ljava/lang/String;Ljava/lang/String;)V"); + SetDataMethod = GetMethod("setData", "(Ljava/lang/String;Ljava/lang/Object;)V"); +} + +void SentrySpanAndroid::Finish() +{ + CallMethod(FinishMethod); +} + +bool SentrySpanAndroid::IsFinished() const +{ + return CallMethod(IsFinishedMethod);; +} + +void SentrySpanAndroid::SetTag(const FString& key, const FString& value) +{ + CallMethod(SetTagMethod, *GetJString(key), *GetJString(value)); +} + +void SentrySpanAndroid::RemoveTag(const FString& key) +{ + SetTag(key, TEXT("")); +} + +void SentrySpanAndroid::SetData(const FString& key, const TMap& values) +{ + CallMethod(SetDataMethod, *GetJString(key), SentryConvertorsAndroid::StringMapToNative(values)->GetJObject()); +} + +void SentrySpanAndroid::RemoveData(const FString& key) +{ + SetData(key, TMap()); +} diff --git a/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h b/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h new file mode 100644 index 00000000..2ee130e2 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h @@ -0,0 +1,29 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Interface/SentrySpanInterface.h" + +#include "Infrastructure/SentryJavaObjectWrapper.h" + +class SentrySpanAndroid : public ISentrySpan, public FSentryJavaObjectWrapper +{ +public: + SentrySpanAndroid(jobject span); + + void SetupClassMethods(); + + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + + +private: + FSentryJavaMethod FinishMethod; + FSentryJavaMethod IsFinishedMethod; + FSentryJavaMethod SetTagMethod; + FSentryJavaMethod SetDataMethod; +}; diff --git a/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.cpp b/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.cpp index 24c52d90..08141e75 100644 --- a/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.cpp +++ b/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.cpp @@ -44,6 +44,16 @@ void SentrySubsystemAndroid::InitWithSettings(const USentrySettings* settings, U SettingsJson->SetArrayField(TEXT("inAppInclude"), SentryConvertorsAndroid::StrinArrayToJsonArray(settings->InAppInclude)); SettingsJson->SetArrayField(TEXT("inAppExclude"), SentryConvertorsAndroid::StrinArrayToJsonArray(settings->InAppExclude)); SettingsJson->SetBoolField(TEXT("sendDefaultPii"), settings->SendDefaultPii); + SettingsJson->SetBoolField(TEXT("enableTracing"), settings->EnableTracing); + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate) + { + SettingsJson->SetNumberField(TEXT("tracesSampleRate"), settings->TracesSampleRate); + } + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::TracesSampler) + { + UE_LOG(LogSentrySdk, Warning, TEXT("Currently sampling functions are not supported")); + SettingsJson->SetNumberField(TEXT("tracesSampler"), (jlong)0); + } FString SettingsJsonStr; TSharedRef> JsonWriter = TJsonWriterFactory<>::Create(&SettingsJsonStr); @@ -206,3 +216,11 @@ void SentrySubsystemAndroid::EndSession() { FSentryJavaObjectWrapper::CallStaticMethod(SentryJavaClasses::SentryBridgeJava, "endSession", "()V", nullptr); } + +USentryTransaction* SentrySubsystemAndroid::StartTransaction(const FString& name, const FString& operation) +{ + auto transaction = FSentryJavaObjectWrapper::CallStaticObjectMethod(SentryJavaClasses::Sentry, "startTransaction", "(Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ITransaction;", + *FSentryJavaObjectWrapper::GetJString(name), *FSentryJavaObjectWrapper::GetJString(operation)); + + return SentryConvertorsAndroid::SentryTransactionToUnreal(*transaction); +} diff --git a/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.h b/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.h index 107e3bc8..d8cda9ec 100644 --- a/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.h +++ b/plugin-dev/Source/Sentry/Private/Android/SentrySubsystemAndroid.h @@ -27,4 +27,5 @@ class SentrySubsystemAndroid : public ISentrySubsystem virtual void SetLevel(ESentryLevel level) override; virtual void StartSession() override; virtual void EndSession() override; + virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override; }; diff --git a/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.cpp b/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.cpp new file mode 100644 index 00000000..f67bffba --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentryTransactionAndroid.h" + +#include "Infrastructure/SentryConvertorsAndroid.h" +#include "Infrastructure/SentryJavaClasses.h" + +SentryTransactionAndroid::SentryTransactionAndroid(jobject transaction) + : FSentryJavaObjectWrapper(SentryJavaClasses::Transaction, transaction) +{ + SetupClassMethods(); +} + +void SentryTransactionAndroid::SetupClassMethods() +{ + StartChildMethod = GetMethod("startChild", "(Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan;"); + FinishMethod = GetMethod("finish", "()V"); + IsFinishedMethod = GetMethod("isFinished", "()Z"); + SetNameMethod = GetMethod("setName", "(Ljava/lang/String;)V"); + SetTagMethod = GetMethod("setTag", "(Ljava/lang/String;Ljava/lang/String;)V"); + SetDataMethod = GetMethod("setData", "(Ljava/lang/String;Ljava/lang/Object;)V"); +} + +USentrySpan* SentryTransactionAndroid::StartChild(const FString& operation, const FString& desctiption) +{ + auto span = CallObjectMethod(StartChildMethod, *GetJString(operation), *GetJString(desctiption)); + return SentryConvertorsAndroid::SentrySpanToUnreal(*span); +} + +void SentryTransactionAndroid::Finish() +{ + CallMethod(FinishMethod); +} + +bool SentryTransactionAndroid::IsFinished() const +{ + return CallMethod(IsFinishedMethod);; +} + +void SentryTransactionAndroid::SetName(const FString& name) +{ + CallMethod(SetNameMethod, *GetJString(name)); +} + +void SentryTransactionAndroid::SetTag(const FString& key, const FString& value) +{ + CallMethod(SetTagMethod, *GetJString(key), *GetJString(value)); +} + +void SentryTransactionAndroid::RemoveTag(const FString& key) +{ + SetTag(key, TEXT("")); +} + +void SentryTransactionAndroid::SetData(const FString& key, const TMap& values) +{ + CallMethod(SetDataMethod, *GetJString(key), SentryConvertorsAndroid::StringMapToNative(values)->GetJObject()); +} + +void SentryTransactionAndroid::RemoveData(const FString& key) +{ + SetData(key, TMap()); +} diff --git a/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.h b/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.h new file mode 100644 index 00000000..aa51c851 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Android/SentryTransactionAndroid.h @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Interface/SentryTransactionInterface.h" + +#include "Infrastructure/SentryJavaObjectWrapper.h" + +class SentryTransactionAndroid : public ISentryTransaction, public FSentryJavaObjectWrapper +{ +public: + SentryTransactionAndroid(jobject transaction); + + void SetupClassMethods(); + + virtual USentrySpan* StartChild(const FString& operation, const FString& desctiption) override; + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetName(const FString& name) override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + +private: + FSentryJavaMethod StartChildMethod; + FSentryJavaMethod FinishMethod; + FSentryJavaMethod IsFinishedMethod; + FSentryJavaMethod SetNameMethod; + FSentryJavaMethod SetTagMethod; + FSentryJavaMethod SetDataMethod; +}; diff --git a/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.cpp b/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.cpp index 80814997..fb28ce4a 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.cpp +++ b/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.cpp @@ -3,10 +3,14 @@ #include "SentryConvertorsApple.h" #include "SentryScope.h" #include "SentryId.h" +#include "SentryTransaction.h" +#include "SentrySpan.h" #include "SentryDefines.h" #include "Apple/SentryScopeApple.h" #include "Apple/SentryIdApple.h" +#include "Apple/SentryTransactionApple.h" +#include "Apple/SentrySpanApple.h" SentryLevel SentryConvertorsApple::SentryLevelToNative(ESentryLevel level) { @@ -147,6 +151,22 @@ USentryId* SentryConvertorsApple::SentryIdToUnreal(SentryId* id) return unrealId; } +USentryTransaction* SentryConvertorsApple::SentryTransactionToUnreal(id transaction) +{ + TSharedPtr transactionNativeImpl = MakeShareable(new SentryTransactionApple(transaction)); + USentryTransaction* unrealTransaction = NewObject(); + unrealTransaction->InitWithNativeImpl(transactionNativeImpl); + return unrealTransaction; +} + +USentrySpan* SentryConvertorsApple::SentrySpanToUnreal(id span) +{ + TSharedPtr spanNativeImpl = MakeShareable(new SentrySpanApple(span)); + USentrySpan* unrealSpan = NewObject(); + unrealSpan->InitWithNativeImpl(spanNativeImpl); + return unrealSpan; +} + SentryLevel SentryConvertorsApple::StringToSentryLevel(NSString* string) { SentryLevel nativeLevel = kSentryLevelDebug; diff --git a/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.h b/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.h index 1cbce542..2b7d649b 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.h +++ b/plugin-dev/Source/Sentry/Private/Apple/Infrastructure/SentryConvertorsApple.h @@ -8,6 +8,7 @@ class USentryScope; class USentryId; +class USentryTransaction; class SentryConvertorsApple { @@ -25,6 +26,8 @@ class SentryConvertorsApple static TArray ByteDataToUnreal(NSData* data); static USentryScope* SentryScopeToUnreal(SentryScope* scope); static USentryId* SentryIdToUnreal(SentryId* id); + static USentryTransaction* SentryTransactionToUnreal(id transaction); + static USentrySpan* SentrySpanToUnreal(id span); /** Other conversions */ static SentryLevel StringToSentryLevel(NSString* string); diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.cpp b/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.cpp new file mode 100644 index 00000000..e6830ade --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentrySpanApple.h" + +SentrySpanApple::SentrySpanApple(id span) +{ + SpanApple = span; +} + +SentrySpanApple::~SentrySpanApple() +{ + // Put custom destructor logic here if needed +} + +id SentrySpanApple::GetNativeObject() +{ + return SpanApple; +} + +void SentrySpanApple::Finish() +{ + [SpanApple finish]; +} + +bool SentrySpanApple::IsFinished() const +{ + return SpanApple.isFinished; +} + +void SentrySpanApple::SetTag(const FString& key, const FString& value) +{ + [SpanApple setTagValue:value.GetNSString() forKey:key.GetNSString()]; +} + +void SentrySpanApple::RemoveTag(const FString& key) +{ + [SpanApple removeTagForKey:key.GetNSString()]; +} + +void SentrySpanApple::SetData(const FString& key, const TMap& values) +{ + [SpanApple setDataValue:SentryConvertorsApple::StringMapToNative(values) forKey:key.GetNSString()]; +} + +void SentrySpanApple::RemoveData(const FString& key) +{ + [SpanApple removeDataForKey:key.GetNSString()]; +} diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.h b/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.h new file mode 100644 index 00000000..d508e651 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.h @@ -0,0 +1,27 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Interface/SentrySpanInterface.h" + +@protocol SentrySpan; + +class SentrySpanApple : public ISentrySpan +{ +public: + SentrySpanApple(id span); + virtual ~SentrySpanApple() override; + + id GetNativeObject(); + + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + + +private: + id SpanApple; +}; diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.cpp b/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.cpp index d874e41e..8c990a89 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.cpp +++ b/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.cpp @@ -7,6 +7,7 @@ #include "SentryScopeApple.h" #include "SentryUserApple.h" #include "SentryUserFeedbackApple.h" +#include "SentryTransactionApple.h" #include "SentryEvent.h" #include "SentryBreadcrumb.h" @@ -14,7 +15,9 @@ #include "SentrySettings.h" #include "SentryUserFeedback.h" #include "SentryUser.h" +#include "SentryTransaction.h" #include "SentryBeforeSendHandler.h" +#include "SentryDefines.h" #include "Infrastructure/SentryConvertorsApple.h" @@ -65,6 +68,16 @@ void SentrySubsystemApple::InitWithSettings(const USentrySettings* settings, USe { [options addInAppExclude:it->GetNSString()]; } + options.enableTracing = settings->EnableTracing; + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate) + { + options.tracesSampleRate = [NSNumber numberWithFloat:settings->TracesSampleRate]; + } + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::TracesSampler) + { + UE_LOG(LogSentrySdk, Warning, TEXT("Currently sampling functions are not supported")); + options.tracesSampler = nil; + } }]; } @@ -198,3 +211,10 @@ void SentrySubsystemApple::EndSession() { [SENTRY_APPLE_CLASS(SentrySDK) endSession]; } + +USentryTransaction* SentrySubsystemApple::StartTransaction(const FString& name, const FString& operation) +{ + id transaction = [SENTRY_APPLE_CLASS(SentrySDK) startTransactionWithName:name.GetNSString() operation:operation.GetNSString()]; + + return SentryConvertorsApple::SentryTransactionToUnreal(transaction); +} diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.h b/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.h index 14aa3990..f8158d7f 100644 --- a/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.h +++ b/plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.h @@ -27,4 +27,5 @@ class SentrySubsystemApple : public ISentrySubsystem virtual void SetLevel(ESentryLevel level) override; virtual void StartSession() override; virtual void EndSession() override; + virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override; }; diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.cpp b/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.cpp new file mode 100644 index 00000000..78891754 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentryTransactionApple.h" + +#include "Infrastructure/SentryConvertorsApple.h" + +#include "Convenience/SentryInclude.h" +#include "Convenience/SentryMacro.h" + +#include "SentryDefines.h" + +SentryTransactionApple::SentryTransactionApple(id transaction) +{ + TransactionApple = transaction; +} + +SentryTransactionApple::~SentryTransactionApple() +{ + // Put custom destructor logic here if needed +} + +id SentryTransactionApple::GetNativeObject() +{ + return TransactionApple; +} + +USentrySpan* SentryTransactionApple::StartChild(const FString& operation, const FString& desctiption) +{ + id span = [TransactionApple startChildWithOperation:operation.GetNSString() description:desctiption.GetNSString()]; + return SentryConvertorsApple::SentrySpanToUnreal(span); +} + +void SentryTransactionApple::Finish() +{ + [TransactionApple finish]; +} + +bool SentryTransactionApple::IsFinished() const +{ + return TransactionApple.isFinished; +} + +void SentryTransactionApple::SetName(const FString& name) +{ + // no corresponding implementation in sentry-cocoa + UE_LOG(LogSentrySdk, Warning, TEXT("The Cocoa SDK doesn't currently support SetName function")); +} + +void SentryTransactionApple::SetTag(const FString& key, const FString& value) +{ + [TransactionApple setTagValue:value.GetNSString() forKey:key.GetNSString()]; +} + +void SentryTransactionApple::RemoveTag(const FString& key) +{ + [TransactionApple removeTagForKey:key.GetNSString()]; +} + +void SentryTransactionApple::SetData(const FString& key, const TMap& values) +{ + [TransactionApple setDataValue:SentryConvertorsApple::StringMapToNative(values) forKey:key.GetNSString()]; +} + +void SentryTransactionApple::RemoveData(const FString& key) +{ + [TransactionApple removeDataForKey:key.GetNSString()]; +} diff --git a/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.h b/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.h new file mode 100644 index 00000000..f6b08db7 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Apple/SentryTransactionApple.h @@ -0,0 +1,28 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Interface/SentryTransactionInterface.h" + +@protocol SentrySpan; + +class SentryTransactionApple : public ISentryTransaction +{ +public: + SentryTransactionApple(id transaction); + virtual ~SentryTransactionApple() override; + + id GetNativeObject(); + + virtual USentrySpan* StartChild(const FString& operation, const FString& desctiption) override; + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetName(const FString& name) override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + +private: + id TransactionApple; +}; diff --git a/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.cpp b/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.cpp index d083f4a1..e9ec2139 100644 --- a/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.cpp +++ b/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.cpp @@ -2,9 +2,13 @@ #include "SentryConvertorsDesktop.h" #include "SentryId.h" +#include "SentryTransaction.h" +#include "SentrySpan.h" #include "SentryDefines.h" #include "Desktop/SentryIdDesktop.h" +#include "Desktop/SentryTransactionDesktop.h" +#include "Desktop/SentrySpanDesktop.h" #include "UObject/Package.h" #include "UObject/UObjectGlobals.h" @@ -116,6 +120,22 @@ USentryId* SentryConvertorsDesktop::SentryIdToUnreal(sentry_uuid_t id) return unrealId; } +USentryTransaction* SentryConvertorsDesktop::SentryTransactionToUnreal(sentry_transaction_t* transaction) +{ + TSharedPtr transactionNativeImpl = MakeShareable(new SentryTransactionDesktop(transaction)); + USentryTransaction* unrealTransaction = NewObject(); + unrealTransaction->InitWithNativeImpl(transactionNativeImpl); + return unrealTransaction; +} + +USentrySpan* SentryConvertorsDesktop::SentrySpanToUnreal(sentry_span_t* span) +{ + TSharedPtr spanNativeImpl = MakeShareable(new SentrySpanDesktop(span)); + USentrySpan* unrealSpan = NewObject(); + unrealSpan->InitWithNativeImpl(spanNativeImpl); + return unrealSpan; +} + TMap SentryConvertorsDesktop::StringMapToUnreal(sentry_value_t map) { TMap unrealMap; diff --git a/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.h b/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.h index 1e6ffe37..b10c2060 100644 --- a/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.h +++ b/plugin-dev/Source/Sentry/Private/Desktop/Infrastructure/SentryConvertorsDesktop.h @@ -9,6 +9,8 @@ #if USE_SENTRY_NATIVE class USentryId; +class USentryTransaction; +class USentrySpan; class SentryConvertorsDesktop { @@ -22,6 +24,8 @@ class SentryConvertorsDesktop static ESentryLevel SentryLevelToUnreal(sentry_value_t level); static ESentryLevel SentryLevelToUnreal(sentry_level_t level); static USentryId* SentryIdToUnreal(sentry_uuid_t id); + static USentryTransaction* SentryTransactionToUnreal(sentry_transaction_t* transaction); + static USentrySpan* SentrySpanToUnreal(sentry_span_t* span); static TMap StringMapToUnreal(sentry_value_t map); static TArray StringArrayToUnreal(sentry_value_t array); diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.cpp b/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.cpp new file mode 100644 index 00000000..d3f65cbe --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentrySpanDesktop.h" + +#include "Infrastructure/SentryConvertorsDesktop.h" + +#if USE_SENTRY_NATIVE + +SentrySpanDesktop::SentrySpanDesktop(sentry_span_t* span) + : SpanDesktop(span) + , isFinished(false) +{ +} + +SentrySpanDesktop::~SentrySpanDesktop() +{ + // Put custom destructor logic here if needed +} + +sentry_span_t* SentrySpanDesktop::GetNativeObject() +{ + return SpanDesktop; +} + +void SentrySpanDesktop::Finish() +{ + sentry_span_finish(SpanDesktop); + + isFinished = true; +} + +bool SentrySpanDesktop::IsFinished() const +{ + return isFinished; +} + +void SentrySpanDesktop::SetTag(const FString& key, const FString& value) +{ + FScopeLock Lock(&CriticalSection); + + sentry_span_set_tag(SpanDesktop, TCHAR_TO_ANSI(*key), TCHAR_TO_ANSI(*value)); +} + +void SentrySpanDesktop::RemoveTag(const FString& key) +{ + FScopeLock Lock(&CriticalSection); + + sentry_span_remove_tag(SpanDesktop, TCHAR_TO_ANSI(*key)); +} + +void SentrySpanDesktop::SetData(const FString& key, const TMap& values) +{ + FScopeLock Lock(&CriticalSection); + + sentry_span_set_data(SpanDesktop, TCHAR_TO_ANSI(*key), SentryConvertorsDesktop::StringMapToNative(values)); +} + +void SentrySpanDesktop::RemoveData(const FString& key) +{ + FScopeLock Lock(&CriticalSection); + + sentry_span_remove_data(SpanDesktop, TCHAR_TO_ANSI(*key)); +} + +#endif diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.h b/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.h new file mode 100644 index 00000000..f8c00552 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.h @@ -0,0 +1,36 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Convenience/SentryInclude.h" + +#include "HAL/CriticalSection.h" + +#include "Interface/SentrySpanInterface.h" + +#if USE_SENTRY_NATIVE + +class SentrySpanDesktop : public ISentrySpan +{ +public: + SentrySpanDesktop(sentry_span_t* span); + virtual ~SentrySpanDesktop() override; + + sentry_span_t* GetNativeObject(); + + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + +private: + sentry_span_t* SpanDesktop; + + FCriticalSection CriticalSection; + + bool isFinished; +}; + +#endif diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.cpp b/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.cpp index c4dc5462..323e3375 100644 --- a/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.cpp +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.cpp @@ -5,6 +5,7 @@ #include "SentryBreadcrumbDesktop.h" #include "SentryUserDesktop.h" #include "SentryScopeDesktop.h" +#include "SentryTransactionDesktop.h" #include "SentryDefines.h" #include "SentrySettings.h" @@ -12,12 +13,15 @@ #include "SentryBreadcrumb.h" #include "SentryUserFeedback.h" #include "SentryUser.h" +#include "SentryTransaction.h" #include "SentryModule.h" #include "SentryBeforeSendHandler.h" -#include "CrashReporter/SentryCrashContext.h" #include "Infrastructure/SentryConvertorsDesktop.h" + #include "CrashReporter/SentryCrashReporter.h" +#include "CrashReporter/SentryCrashContext.h" + #include "Transport/SentryTransport.h" #include "Misc/Paths.h" @@ -103,6 +107,15 @@ void SentrySubsystemDesktop::InitWithSettings(const USentrySettings* settings, U sentry_options_set_http_proxy(options, TCHAR_TO_ANSI(*settings->ProxyUrl)); } + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate) + { + sentry_options_set_traces_sample_rate(options, settings->TracesSampleRate); + } + if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::TracesSampler) + { + UE_LOG(LogSentrySdk, Warning, TEXT("The Native SDK doesn't currently support sampling functions")); + } + #if PLATFORM_WINDOWS sentry_options_set_handler_pathw(options, *FPaths::ConvertRelativePathToFull(HandlerPath)); sentry_options_set_database_pathw(options, *FPaths::ConvertRelativePathToFull(DatabasePath)); @@ -324,6 +337,15 @@ void SentrySubsystemDesktop::EndSession() sentry_end_session(); } +USentryTransaction* SentrySubsystemDesktop::StartTransaction(const FString& name, const FString& operation) +{ + sentry_transaction_context_t* transactionContext = sentry_transaction_context_new(TCHAR_TO_ANSI(*name), TCHAR_TO_ANSI(*operation)); + + sentry_transaction_t* nativeTransaction = sentry_transaction_start(transactionContext, sentry_value_new_null()); + + return SentryConvertorsDesktop::SentryTransactionToUnreal(nativeTransaction); +} + USentryBeforeSendHandler* SentrySubsystemDesktop::GetBeforeSendHandler() { return beforeSend; diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.h b/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.h index 31f0ff8a..e0899679 100644 --- a/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.h +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentrySubsystemDesktop.h @@ -36,6 +36,7 @@ class SentrySubsystemDesktop : public ISentrySubsystem virtual void SetLevel(ESentryLevel level) override; virtual void StartSession() override; virtual void EndSession() override; + virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override; USentryBeforeSendHandler* GetBeforeSendHandler(); diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.cpp b/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.cpp new file mode 100644 index 00000000..aceef7ab --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentryTransactionDesktop.h" +#include "SentrySpanDesktop.h" + +#include "SentrySpan.h" + +#include "Infrastructure/SentryConvertorsDesktop.h" + +#if USE_SENTRY_NATIVE + +SentryTransactionDesktop::SentryTransactionDesktop(sentry_transaction_t* transaction) + : TransactionDesktop(transaction) + , isFinished(false) +{ +} + +SentryTransactionDesktop::~SentryTransactionDesktop() +{ +} + +sentry_transaction_t* SentryTransactionDesktop::GetNativeObject() +{ + return TransactionDesktop; +} + +USentrySpan* SentryTransactionDesktop::StartChild(const FString& operation, const FString& desctiption) +{ + sentry_span_t* nativeSpan = sentry_transaction_start_child(TransactionDesktop, TCHAR_TO_ANSI(*operation), TCHAR_TO_ANSI(*desctiption)); + return SentryConvertorsDesktop::SentrySpanToUnreal(nativeSpan); +} + +void SentryTransactionDesktop::Finish() +{ + sentry_transaction_finish(TransactionDesktop); + + isFinished = true; +} + +bool SentryTransactionDesktop::IsFinished() const +{ + return isFinished; +} + +void SentryTransactionDesktop::SetName(const FString& name) +{ + FScopeLock Lock(&CriticalSection); + + sentry_transaction_set_name(TransactionDesktop, TCHAR_TO_ANSI(*name)); +} + +void SentryTransactionDesktop::SetTag(const FString& key, const FString& value) +{ + FScopeLock Lock(&CriticalSection); + + sentry_transaction_set_tag(TransactionDesktop, TCHAR_TO_ANSI(*key), TCHAR_TO_ANSI(*value)); +} + +void SentryTransactionDesktop::RemoveTag(const FString& key) +{ + FScopeLock Lock(&CriticalSection); + + sentry_transaction_remove_tag(TransactionDesktop, TCHAR_TO_ANSI(*key)); +} + +void SentryTransactionDesktop::SetData(const FString& key, const TMap& values) +{ + FScopeLock Lock(&CriticalSection); + + sentry_transaction_set_data(TransactionDesktop, TCHAR_TO_ANSI(*key), SentryConvertorsDesktop::StringMapToNative(values)); +} + +void SentryTransactionDesktop::RemoveData(const FString& key) +{ + FScopeLock Lock(&CriticalSection); + + sentry_transaction_remove_data(TransactionDesktop, TCHAR_TO_ANSI(*key)); +} + +#endif diff --git a/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.h b/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.h new file mode 100644 index 00000000..5a6f59ea --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Desktop/SentryTransactionDesktop.h @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "Convenience/SentryInclude.h" + +#include "HAL/CriticalSection.h" + +#include "Interface/SentryTransactionInterface.h" + +#if USE_SENTRY_NATIVE + +class SentryTransactionDesktop : public ISentryTransaction +{ +public: + SentryTransactionDesktop(sentry_transaction_t* transaction); + virtual ~SentryTransactionDesktop() override; + + sentry_transaction_t* GetNativeObject(); + + virtual USentrySpan* StartChild(const FString& operation, const FString& desctiption) override; + virtual void Finish() override; + virtual bool IsFinished() const override; + virtual void SetName(const FString& name) override; + virtual void SetTag(const FString& key, const FString& value) override; + virtual void RemoveTag(const FString& key) override; + virtual void SetData(const FString& key, const TMap& values) override; + virtual void RemoveData(const FString& key) override; + +private: + sentry_transaction_t* TransactionDesktop; + + FCriticalSection CriticalSection; + + bool isFinished; +}; + +#endif diff --git a/plugin-dev/Source/Sentry/Private/Interface/SentrySpanInterface.h b/plugin-dev/Source/Sentry/Private/Interface/SentrySpanInterface.h new file mode 100644 index 00000000..08ec7a1c --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Interface/SentrySpanInterface.h @@ -0,0 +1,18 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +class ISentrySpan +{ +public: + virtual ~ISentrySpan() = default; + + virtual void Finish() = 0; + virtual bool IsFinished() const = 0; + virtual void SetTag(const FString& key, const FString& value) = 0; + virtual void RemoveTag(const FString& key) = 0; + virtual void SetData(const FString& key, const TMap& values) = 0; + virtual void RemoveData(const FString& key) = 0; +}; \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h b/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h index b4dfd1ff..69e5759c 100644 --- a/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h +++ b/plugin-dev/Source/Sentry/Private/Interface/SentrySubsystemInterface.h @@ -14,6 +14,7 @@ class USentryId; class USentryUserFeedback; class USentryUser; class USentryBeforeSendHandler; +class USentryTransaction; class ISentrySubsystem { @@ -40,4 +41,5 @@ class ISentrySubsystem virtual void SetLevel(ESentryLevel level) = 0; virtual void StartSession() = 0; virtual void EndSession() = 0; + virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) = 0; }; \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/Interface/SentryTransactionInterface.h b/plugin-dev/Source/Sentry/Private/Interface/SentryTransactionInterface.h new file mode 100644 index 00000000..1cdbff55 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/Interface/SentryTransactionInterface.h @@ -0,0 +1,22 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +class USentrySpan; + +class ISentryTransaction +{ +public: + virtual ~ISentryTransaction() = default; + + virtual USentrySpan* StartChild(const FString& operation, const FString& desctiption) = 0; + virtual void Finish() = 0; + virtual bool IsFinished() const = 0; + virtual void SetName(const FString& name) = 0; + virtual void SetTag(const FString& key, const FString& value) = 0; + virtual void RemoveTag(const FString& key) = 0; + virtual void SetData(const FString& key, const TMap& values) = 0; + virtual void RemoveData(const FString& key) = 0; +}; \ No newline at end of file diff --git a/plugin-dev/Source/Sentry/Private/SentrySettings.cpp b/plugin-dev/Source/Sentry/Private/SentrySettings.cpp index 1b9b7c30..56ee7ae2 100644 --- a/plugin-dev/Source/Sentry/Private/SentrySettings.cpp +++ b/plugin-dev/Source/Sentry/Private/SentrySettings.cpp @@ -27,6 +27,9 @@ USentrySettings::USentrySettings(const FObjectInitializer& ObjectInitializer) , UseProxy(false) , ProxyUrl() , BeforeSendHandler(USentryBeforeSendHandler::StaticClass()) + , EnableTracing(false) + , SamplingType(ESentryTracesSamplingType::UniformSampleRate) + , TracesSampleRate(0.0f) , EnableForPromotedBuildsOnly(false) , UploadSymbolsAutomatically(false) , IncludeSources(false) diff --git a/plugin-dev/Source/Sentry/Private/SentrySpan.cpp b/plugin-dev/Source/Sentry/Private/SentrySpan.cpp new file mode 100644 index 00000000..7b8c6000 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/SentrySpan.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentrySpan.h" + +#include "Interface/SentrySpanInterface.h" + +#if PLATFORM_ANDROID +#include "Android/SentrySpanAndroid.h" +#elif PLATFORM_IOS || PLATFORM_MAC +#include "Apple/SentrySpanApple.h" +#elif PLATFORM_WINDOWS || PLATFORM_LINUX +#include "Desktop/SentrySpanDesktop.h" +#endif + +USentrySpan::USentrySpan() +{ +} + +void USentrySpan::Finish() +{ + if (!SentrySpanNativeImpl) + return; + + SentrySpanNativeImpl->Finish(); +} + +bool USentrySpan::IsFinished() const +{ + if (!SentrySpanNativeImpl) + return false; + + return SentrySpanNativeImpl->IsFinished(); +} + +void USentrySpan::SetTag(const FString& key, const FString& value) +{ + if (!SentrySpanNativeImpl || SentrySpanNativeImpl->IsFinished()) + return; + + SentrySpanNativeImpl->SetTag(key, value); +} + +void USentrySpan::RemoveTag(const FString& key) +{ + if (!SentrySpanNativeImpl || SentrySpanNativeImpl->IsFinished()) + return; + + SentrySpanNativeImpl->RemoveTag(key); +} + +void USentrySpan::SetData(const FString& key, const TMap& values) +{ + if (!SentrySpanNativeImpl || SentrySpanNativeImpl->IsFinished()) + return; + + SentrySpanNativeImpl->SetData(key, values); +} + +void USentrySpan::RemoveData(const FString& key) +{ + if (!SentrySpanNativeImpl || SentrySpanNativeImpl->IsFinished()) + return; + + SentrySpanNativeImpl->RemoveData(key); +} + +void USentrySpan::InitWithNativeImpl(TSharedPtr spanImpl) +{ + SentrySpanNativeImpl = spanImpl; +} + +TSharedPtr USentrySpan::GetNativeImpl() +{ + return SentrySpanNativeImpl; +} diff --git a/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp b/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp index f69dce7c..3a6df879 100644 --- a/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp +++ b/plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp @@ -293,6 +293,14 @@ void USentrySubsystem::EndSession() SubsystemNativeImpl->EndSession(); } +USentryTransaction* USentrySubsystem::StartTransaction(const FString& Name, const FString& Operation) +{ + if (!SubsystemNativeImpl || !SubsystemNativeImpl->IsEnabled()) + return nullptr; + + return SubsystemNativeImpl->StartTransaction(Name, Operation); +} + void USentrySubsystem::AddDefaultContext() { if (!SubsystemNativeImpl || !SubsystemNativeImpl->IsEnabled()) diff --git a/plugin-dev/Source/Sentry/Private/SentryTransaction.cpp b/plugin-dev/Source/Sentry/Private/SentryTransaction.cpp new file mode 100644 index 00000000..42159ac1 --- /dev/null +++ b/plugin-dev/Source/Sentry/Private/SentryTransaction.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#include "SentryTransaction.h" +#include "SentrySpan.h" + +#include "Interface/SentryTransactionInterface.h" + +#if PLATFORM_ANDROID +#include "Android/SentryTransactionAndroid.h" +#elif PLATFORM_IOS || PLATFORM_MAC +#include "Apple/SentryTransactionApple.h" +#elif PLATFORM_WINDOWS || PLATFORM_LINUX +#include "Desktop/SentryTransactionDesktop.h" +#endif + +USentryTransaction::USentryTransaction() +{ +} + +USentrySpan* USentryTransaction::StartChild(const FString& Operation, const FString& Description) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return nullptr; + + return SentryTransactionNativeImpl->StartChild(Operation, Description); +} + +void USentryTransaction::Finish() +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->Finish(); +} + +bool USentryTransaction::IsFinished() const +{ + if (!SentryTransactionNativeImpl) + return false; + + return SentryTransactionNativeImpl->IsFinished(); +} + +void USentryTransaction::SetName(const FString& name) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->SetName(name); +} + +void USentryTransaction::SetTag(const FString& key, const FString& value) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->SetTag(key, value); +} + +void USentryTransaction::RemoveTag(const FString& key) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->RemoveTag(key); +} + +void USentryTransaction::SetData(const FString& key, const TMap& values) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->SetData(key, values); +} + +void USentryTransaction::RemoveData(const FString& key) +{ + if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished()) + return; + + SentryTransactionNativeImpl->RemoveData(key); +} + +void USentryTransaction::InitWithNativeImpl(TSharedPtr transactionImpl) +{ + SentryTransactionNativeImpl = transactionImpl; +} + +TSharedPtr USentryTransaction::GetNativeImpl() +{ + return SentryTransactionNativeImpl; +} diff --git a/plugin-dev/Source/Sentry/Private/Tests/SentrySubsystem.spec.cpp b/plugin-dev/Source/Sentry/Private/Tests/SentrySubsystem.spec.cpp index ba542367..1fac3287 100644 --- a/plugin-dev/Source/Sentry/Private/Tests/SentrySubsystem.spec.cpp +++ b/plugin-dev/Source/Sentry/Private/Tests/SentrySubsystem.spec.cpp @@ -2,6 +2,8 @@ #include "SentrySubsystem.h" #include "SentryEvent.h" +#include "SentryTransaction.h" +#include "SentrySpan.h" #include "UObject/UObjectGlobals.h" #include "Misc/AutomationTest.h" @@ -64,6 +66,26 @@ void SentrySubsystemSpec::Define() }); }); + Describe("Transaction", [this]() + { + It("should be started and finished", [this]() + { + USentryTransaction* transaction = SentrySubsystem->StartTransaction(TEXT("Automation transaction"), TEXT("Automation operation")); + TestNotNull("Transaction is non-null", transaction); + TestFalse("Transaction is not finished", transaction->IsFinished()); + + USentrySpan* span = transaction->StartChild(TEXT("Automation span"), TEXT("Description text")); + TestNotNull("Span is non-null", span); + TestFalse("Span is not finished", span->IsFinished()); + + span->Finish(); + TestTrue("Span is finished", span->IsFinished()); + + transaction->Finish(); + TestTrue("Transaction is finished", transaction->IsFinished()); + }); + }); + AfterEach([this] { SentrySubsystem->Close(); diff --git a/plugin-dev/Source/Sentry/Public/SentrySettings.h b/plugin-dev/Source/Sentry/Public/SentrySettings.h index b9ed2ca4..5b6840c6 100644 --- a/plugin-dev/Source/Sentry/Public/SentrySettings.h +++ b/plugin-dev/Source/Sentry/Public/SentrySettings.h @@ -9,6 +9,15 @@ class USentryBeforeSendHandler; +UENUM(BlueprintType) +enum class ESentryTracesSamplingType : uint8 +{ + // Use uniform sample rate for all transactions + UniformSampleRate, + // Control the sample rate based on the transaction itself and the context in which it's captured (not implemented) + TracesSampler +}; + USTRUCT(BlueprintType) struct FAutomaticBreadcrumbs { @@ -235,6 +244,24 @@ class SENTRY_API USentrySettings : public UObject Meta = (DisplayName = "In-app exludes (for Android/Apple only)", Tooltip = "A list of string prefixes of module names that don't belong to the app.")) TArray InAppExclude; + UPROPERTY(Config, EditAnywhere, Category = "General|Performance Monitoring", + Meta = (DisplayName = "Enable tracing", ToolTip = "Flag indicating whether to enable tracing for performance monitoring.")) + bool EnableTracing; + + UPROPERTY(Config, EditAnywhere, Category = "General|Performance Monitoring", + Meta = (DisplayName = "Sampling type", ToolTip = "Method of controlling the sample rate for transactions.", EditCondition = "EnableTracing")) + ESentryTracesSamplingType SamplingType; + + UPROPERTY(Config, EditAnywhere, Category = "General|Performance Monitoring", + Meta = (DisplayName = "Traces sample rate", ToolTip = "Setting a uniform sample rate for all transactions to a number between 0.0 and 1.0. (For example, to send 20% of transactions, set TracesSampleRate to 0.2).", + EditCondition = "EnableTracing && SamplingType == ESentryTracesSamplingType::UniformSampleRate", EditConditionHides)) + float TracesSampleRate; + + UPROPERTY(Config, EditAnywhere, Category = "General|Performance Monitoring", + Meta = (DisplayName = "Traces sampler", ToolTip = "Custom hanler for determining traces sample rate based on the sampling context.", + EditCondition = "EnableTracing && SamplingType == ESentryTracesSamplingType::TracesSampler", EditConditionHides)) + TSubclassOf TracesSampler; + UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = "General|Misc", Meta = (DisplayName = "Promote values to tags")) FTagsPromotion TagsPromotion; diff --git a/plugin-dev/Source/Sentry/Public/SentrySpan.h b/plugin-dev/Source/Sentry/Public/SentrySpan.h new file mode 100644 index 00000000..5347a109 --- /dev/null +++ b/plugin-dev/Source/Sentry/Public/SentrySpan.h @@ -0,0 +1,51 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "SentrySpan.generated.h" + +class ISentrySpan; + +/** + * Unit of work within a transaction. + */ +UCLASS(BlueprintType) +class SENTRY_API USentrySpan : public UObject +{ + GENERATED_BODY() + +public: + USentrySpan(); + + /** Finishes and sends a span to Sentry. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void Finish(); + + /** Checks whether the span finished. */ + UFUNCTION(BlueprintPure, Category = "Sentry") + bool IsFinished() const; + + /** Sets tag associated with the span. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void SetTag(const FString& key, const FString& value); + + /** Removes tag associated with the span. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void RemoveTag(const FString& key); + + /** Sets data associated with the span. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void SetData(const FString& key, const TMap& values); + + /** Removes data associated with the span. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void RemoveData(const FString& key); + + void InitWithNativeImpl(TSharedPtr spanImpl); + TSharedPtr GetNativeImpl(); + +private: + TSharedPtr SentrySpanNativeImpl; +}; diff --git a/plugin-dev/Source/Sentry/Public/SentrySubsystem.h b/plugin-dev/Source/Sentry/Public/SentrySubsystem.h index f1a4a045..677e66e7 100644 --- a/plugin-dev/Source/Sentry/Public/SentrySubsystem.h +++ b/plugin-dev/Source/Sentry/Public/SentrySubsystem.h @@ -16,8 +16,10 @@ class USentryEvent; class USentryId; class USentryUserFeedback; class USentryUser; -class ISentrySubsystem; class USentryBeforeSendHandler; +class USentryTransaction; + +class ISentrySubsystem; DECLARE_DYNAMIC_DELEGATE_OneParam(FConfigureSettingsDelegate, USentrySettings*, Settings); @@ -234,6 +236,15 @@ class SENTRY_API USentrySubsystem : public UEngineSubsystem UFUNCTION(BlueprintCallable, Category = "Sentry") void EndSession(); + /** + * Starts a new transaction. + * + * @param Name Transaction name. + * @param Operation Short code identifying the type of operation the span is measuring. + */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + USentryTransaction* StartTransaction(const FString& Name, const FString& Operation); + private: /** Adds default context data for all events captured by Sentry SDK. */ void AddDefaultContext(); diff --git a/plugin-dev/Source/Sentry/Public/SentryTransaction.h b/plugin-dev/Source/Sentry/Public/SentryTransaction.h new file mode 100644 index 00000000..f17aab57 --- /dev/null +++ b/plugin-dev/Source/Sentry/Public/SentryTransaction.h @@ -0,0 +1,60 @@ +// Copyright (c) 2023 Sentry. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "SentryTransaction.generated.h" + +class ISentryTransaction; +class USentrySpan; + +/** + * Representation of an activity to measure or track. + */ +UCLASS(BlueprintType) +class SENTRY_API USentryTransaction : public UObject +{ + GENERATED_BODY() + +public: + USentryTransaction(); + + /** . */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + USentrySpan* StartChild(const FString& Operation, const FString& Description); + + /** Finishes and sends a transaction to Sentry. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void Finish(); + + /** Checks whether the transaction finished. */ + UFUNCTION(BlueprintPure, Category = "Sentry") + bool IsFinished() const; + + /** Sets transactions name. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void SetName(const FString& name); + + /** Sets tag associated with the transaction. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void SetTag(const FString& key, const FString& value); + + /** Removes tag associated with the transaction. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void RemoveTag(const FString& key); + + /** Sets data associated with the transaction. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void SetData(const FString& key, const TMap& values); + + /** Removes data associated with the transaction. */ + UFUNCTION(BlueprintCallable, Category = "Sentry") + void RemoveData(const FString& key); + + void InitWithNativeImpl(TSharedPtr transactionImpl); + TSharedPtr GetNativeImpl(); + +private: + TSharedPtr SentryTransactionNativeImpl; +}; diff --git a/sample/Content/UI/W_SentryDemo.uasset b/sample/Content/UI/W_SentryDemo.uasset index f63e72b36c8c30c1a7ae459c8689c99eabed6bc4..b61fc4f0e054dc5d42889c84f455f25fcc9faca1 100644 GIT binary patch literal 290207 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 L=Zo!xgz5haqvH0k literal 179245 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