Skip to content

Commit

Permalink
Add performance monitoring API (#470)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* 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 <[email protected]>
  • Loading branch information
tustanivsky and bitsandfoxes authored Jan 19, 2024
1 parent fd5ed68 commit ae49e20
Show file tree
Hide file tree
Showing 44 changed files with 1,151 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -149,6 +153,22 @@ USentryId* SentryConvertorsAndroid::SentryIdToUnreal(jobject id)
return unrealId;
}

USentryTransaction* SentryConvertorsAndroid::SentryTransactionToUnreal(jobject transaction)
{
TSharedPtr<SentryTransactionAndroid> transactionNativeImpl = MakeShareable(new SentryTransactionAndroid(transaction));
USentryTransaction* unrealTransaction = NewObject<USentryTransaction>();
unrealTransaction->InitWithNativeImpl(transactionNativeImpl);
return unrealTransaction;
}

USentrySpan* SentryConvertorsAndroid::SentrySpanToUnreal(jobject span)
{
TSharedPtr<SentrySpanAndroid> spanNativeImpl = MakeShareable(new SentrySpanAndroid(span));
USentrySpan* unrealSpan = NewObject<USentrySpan>();
unrealSpan->InitWithNativeImpl(spanNativeImpl);
return unrealSpan;
}

TMap<FString, FString> SentryConvertorsAndroid::StringMapToUnreal(jobject map)
{
TMap<FString, FString> result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

class USentryScope;
class USentryId;
class USentryTransaction;
class USentrySpan;
class FSentryJavaObjectWrapper;
class FJsonValue;

Expand All @@ -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<FString, FString> StringMapToUnreal(jobject stringMap);
static TArray<FString> StringListToUnreal(jobject stringList);
static TArray<uint8> ByteArrayToUnreal(jbyteArray byteArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<SentryAndroidOptions>() {
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
50 changes: 50 additions & 0 deletions plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp
Original file line number Diff line number Diff line change
@@ -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<void>(FinishMethod);
}

bool SentrySpanAndroid::IsFinished() const
{
return CallMethod<bool>(IsFinishedMethod);;
}

void SentrySpanAndroid::SetTag(const FString& key, const FString& value)
{
CallMethod<void>(SetTagMethod, *GetJString(key), *GetJString(value));
}

void SentrySpanAndroid::RemoveTag(const FString& key)
{
SetTag(key, TEXT(""));
}

void SentrySpanAndroid::SetData(const FString& key, const TMap<FString, FString>& values)
{
CallMethod<void>(SetDataMethod, *GetJString(key), SentryConvertorsAndroid::StringMapToNative(values)->GetJObject());
}

void SentrySpanAndroid::RemoveData(const FString& key)
{
SetData(key, TMap<FString, FString>());
}
29 changes: 29 additions & 0 deletions plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h
Original file line number Diff line number Diff line change
@@ -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<FString, FString>& values) override;
virtual void RemoveData(const FString& key) override;


private:
FSentryJavaMethod FinishMethod;
FSentryJavaMethod IsFinishedMethod;
FSentryJavaMethod SetTagMethod;
FSentryJavaMethod SetDataMethod;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&SettingsJsonStr);
Expand Down Expand Up @@ -206,3 +216,11 @@ void SentrySubsystemAndroid::EndSession()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "endSession", "()V", nullptr);
}

USentryTransaction* SentrySubsystemAndroid::StartTransaction(const FString& name, const FString& operation)
{
auto transaction = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "startTransaction", "(Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ITransaction;",
*FSentryJavaObjectWrapper::GetJString(name), *FSentryJavaObjectWrapper::GetJString(operation));

return SentryConvertorsAndroid::SentryTransactionToUnreal(*transaction);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Original file line number Diff line number Diff line change
@@ -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<jobject>(StartChildMethod, *GetJString(operation), *GetJString(desctiption));
return SentryConvertorsAndroid::SentrySpanToUnreal(*span);
}

void SentryTransactionAndroid::Finish()
{
CallMethod<void>(FinishMethod);
}

bool SentryTransactionAndroid::IsFinished() const
{
return CallMethod<bool>(IsFinishedMethod);;
}

void SentryTransactionAndroid::SetName(const FString& name)
{
CallMethod<void>(SetNameMethod, *GetJString(name));
}

void SentryTransactionAndroid::SetTag(const FString& key, const FString& value)
{
CallMethod<void>(SetTagMethod, *GetJString(key), *GetJString(value));
}

void SentryTransactionAndroid::RemoveTag(const FString& key)
{
SetTag(key, TEXT(""));
}

void SentryTransactionAndroid::SetData(const FString& key, const TMap<FString, FString>& values)
{
CallMethod<void>(SetDataMethod, *GetJString(key), SentryConvertorsAndroid::StringMapToNative(values)->GetJObject());
}

void SentryTransactionAndroid::RemoveData(const FString& key)
{
SetData(key, TMap<FString, FString>());
}
Original file line number Diff line number Diff line change
@@ -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<FString, FString>& values) override;
virtual void RemoveData(const FString& key) override;

private:
FSentryJavaMethod StartChildMethod;
FSentryJavaMethod FinishMethod;
FSentryJavaMethod IsFinishedMethod;
FSentryJavaMethod SetNameMethod;
FSentryJavaMethod SetTagMethod;
FSentryJavaMethod SetDataMethod;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -147,6 +151,22 @@ USentryId* SentryConvertorsApple::SentryIdToUnreal(SentryId* id)
return unrealId;
}

USentryTransaction* SentryConvertorsApple::SentryTransactionToUnreal(id<SentrySpan> transaction)
{
TSharedPtr<SentryTransactionApple> transactionNativeImpl = MakeShareable(new SentryTransactionApple(transaction));
USentryTransaction* unrealTransaction = NewObject<USentryTransaction>();
unrealTransaction->InitWithNativeImpl(transactionNativeImpl);
return unrealTransaction;
}

USentrySpan* SentryConvertorsApple::SentrySpanToUnreal(id<SentrySpan> span)
{
TSharedPtr<SentrySpanApple> spanNativeImpl = MakeShareable(new SentrySpanApple(span));
USentrySpan* unrealSpan = NewObject<USentrySpan>();
unrealSpan->InitWithNativeImpl(spanNativeImpl);
return unrealSpan;
}

SentryLevel SentryConvertorsApple::StringToSentryLevel(NSString* string)
{
SentryLevel nativeLevel = kSentryLevelDebug;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

class USentryScope;
class USentryId;
class USentryTransaction;

class SentryConvertorsApple
{
Expand All @@ -25,6 +26,8 @@ class SentryConvertorsApple
static TArray<uint8> ByteDataToUnreal(NSData* data);
static USentryScope* SentryScopeToUnreal(SentryScope* scope);
static USentryId* SentryIdToUnreal(SentryId* id);
static USentryTransaction* SentryTransactionToUnreal(id<SentrySpan> transaction);
static USentrySpan* SentrySpanToUnreal(id<SentrySpan> span);

/** Other conversions */
static SentryLevel StringToSentryLevel(NSString* string);
Expand Down
Loading

0 comments on commit ae49e20

Please sign in to comment.