Skip to content

Commit

Permalink
Add trace propagation (#631)
Browse files Browse the repository at this point in the history
  • Loading branch information
tustanivsky authored Oct 9, 2024
1 parent 1790c73 commit be32823
Show file tree
Hide file tree
Showing 32 changed files with 221 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Add setting that allows switching between the project and user directories for the internal Sentry database location on Windows/Linux ([#616](https://github.com/getsentry/sentry-unreal/pull/616))
- Add non-ASCII characters support for user messages ([#624](https://github.com/getsentry/sentry-unreal/pull/624))
- Add API to allow users to trace their distributed system and connect in-game with backend errors ([#631](https://github.com/getsentry/sentry-unreal/pull/631))
- Allow overriding `UploadSymbolsAutomatically` via environment variable `SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY` ([#636](https://github.com/getsentry/sentry-unreal/pull/636))

### Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const FSentryJavaClass SentryJavaClasses::SamplingContext = FSentryJavaClass {
const FSentryJavaClass SentryJavaClasses::CustomSamplingContext = FSentryJavaClass { "io/sentry/CustomSamplingContext", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::TransactionContext = FSentryJavaClass { "io/sentry/TransactionContext", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::TransactionOptions = FSentryJavaClass { "io/sentry/TransactionOptions", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::SentryTraceHeader = FSentryJavaClass { "io/sentry/SentryTraceHeader", 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 @@ -25,6 +25,7 @@ struct SentryJavaClasses
const static FSentryJavaClass CustomSamplingContext;
const static FSentryJavaClass TransactionContext;
const static FSentryJavaClass TransactionOptions;
const static FSentryJavaClass SentryTraceHeader;

// System Java classes
const static FSentryJavaClass ArrayList;
Expand Down
10 changes: 10 additions & 0 deletions plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void SentrySpanAndroid::SetupClassMethods()
IsFinishedMethod = GetMethod("isFinished", "()Z");
SetTagMethod = GetMethod("setTag", "(Ljava/lang/String;Ljava/lang/String;)V");
SetDataMethod = GetMethod("setData", "(Ljava/lang/String;Ljava/lang/Object;)V");
ToSentryTraceMethod = GetMethod("toSentryTrace", "()Lio/sentry/SentryTraceHeader;");
}

void SentrySpanAndroid::Finish()
Expand Down Expand Up @@ -48,3 +49,12 @@ void SentrySpanAndroid::RemoveData(const FString& key)
{
SetData(key, TMap<FString, FString>());
}

void SentrySpanAndroid::GetTrace(FString& name, FString& value)
{
FSentryJavaObjectWrapper NativeTraceHeader(SentryJavaClasses::SentryTraceHeader, *CallObjectMethod<jobject>(ToSentryTraceMethod));
FSentryJavaMethod GetValueMethod = NativeTraceHeader.GetMethod("getValue", "()Ljava/lang/String;");

name = TEXT("sentry-trace");
value = NativeTraceHeader.CallMethod<FString>(GetValueMethod);
}
3 changes: 2 additions & 1 deletion plugin-dev/Source/Sentry/Private/Android/SentrySpanAndroid.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class SentrySpanAndroid : public ISentrySpan, public FSentryJavaObjectWrapper
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;

virtual void GetTrace(FString& name, FString& value) override;

private:
FSentryJavaMethod FinishMethod;
FSentryJavaMethod IsFinishedMethod;
FSentryJavaMethod SetTagMethod;
FSentryJavaMethod SetDataMethod;
FSentryJavaMethod ToSentryTraceMethod;
};
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,11 @@ USentryTransaction* SentrySubsystemAndroid::StartTransactionWithContextAndOption

return SentryConvertorsAndroid::SentryTransactionToUnreal(*transaction);
}

USentryTransactionContext* SentrySubsystemAndroid::ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders)
{
auto transactionContext = FSentryJavaObjectWrapper::CallStaticObjectMethod<jobject>(SentryJavaClasses::Sentry, "continueTrace", "(Ljava/lang/String;Ljava/util/List;)Lio/sentry/TransactionContext;",
*FSentryJavaObjectWrapper::GetJString(sentryTrace), SentryConvertorsAndroid::StringArrayToNative(baggageHeaders)->GetJObject());

return SentryConvertorsAndroid::SentryTransactionContextToUnreal(*transactionContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ class SentrySubsystemAndroid : public ISentrySubsystem
virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override;
virtual USentryTransaction* StartTransactionWithContext(USentryTransactionContext* context) override;
virtual USentryTransaction* StartTransactionWithContextAndOptions(USentryTransactionContext* context, const TMap<FString, FString>& options) override;
virtual USentryTransactionContext* ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders) override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void SentryTransactionAndroid::SetupClassMethods()
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");
ToSentryTraceMethod = GetMethod("toSentryTrace", "()Lio/sentry/SentryTraceHeader;");
}

USentrySpan* SentryTransactionAndroid::StartChild(const FString& operation, const FString& desctiption)
Expand Down Expand Up @@ -61,3 +62,12 @@ void SentryTransactionAndroid::RemoveData(const FString& key)
{
SetData(key, TMap<FString, FString>());
}

void SentryTransactionAndroid::GetTrace(FString& name, FString& value)
{
FSentryJavaObjectWrapper NativeTraceHeader(SentryJavaClasses::SentryTraceHeader, *CallObjectMethod<jobject>(ToSentryTraceMethod));
FSentryJavaMethod GetValueMethod = NativeTraceHeader.GetMethod("getValue", "()Ljava/lang/String;");

name = TEXT("sentry-trace");
value = NativeTraceHeader.CallMethod<FString>(GetValueMethod);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class SentryTransactionAndroid : public ISentryTransaction, public FSentryJavaOb
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;
virtual void GetTrace(FString& name, FString& value) override;

private:
FSentryJavaMethod StartChildMethod;
Expand All @@ -29,4 +30,5 @@ class SentryTransactionAndroid : public ISentryTransaction, public FSentryJavaOb
FSentryJavaMethod SetNameMethod;
FSentryJavaMethod SetTagMethod;
FSentryJavaMethod SetDataMethod;
FSentryJavaMethod ToSentryTraceMethod;
};
5 changes: 5 additions & 0 deletions plugin-dev/Source/Sentry/Private/Apple/SentryIdApple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

SentryIdApple::SentryIdApple()
{
// `SentryId` definition was moved to Swift so its name that can be recognized by UE should be taken from "Sentry-Swift.h" to successfully load class on Mac
#if PLATFORM_MAC
IdApple = [[SENTRY_APPLE_CLASS(_TtC6Sentry8SentryId) alloc] init];
#elif PLATFORM_IOS
IdApple = [[SENTRY_APPLE_CLASS(SentryId) alloc] init];
#endif
}

SentryIdApple::SentryIdApple(SentryId* id)
Expand Down
10 changes: 10 additions & 0 deletions plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "SentrySpanApple.h"

#include "SentryDefines.h"

#include "Infrastructure/SentryConvertorsApple.h"

#include "Convenience/SentryInclude.h"
Expand Down Expand Up @@ -51,3 +53,11 @@ void SentrySpanApple::RemoveData(const FString& key)
{
[SpanApple removeDataForKey:key.GetNSString()];
}

void SentrySpanApple::GetTrace(FString& name, FString& value)
{
SentryTraceHeader* traceHeader = [SpanApple toTraceHeader];

name = TEXT("sentry-trace");
value = FString([traceHeader value]);
}
2 changes: 1 addition & 1 deletion plugin-dev/Source/Sentry/Private/Apple/SentrySpanApple.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SentrySpanApple : public ISentrySpan
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;

virtual void GetTrace(FString& name, FString& value) override;

private:
id<SentrySpan> SpanApple;
Expand Down
36 changes: 35 additions & 1 deletion plugin-dev/Source/Sentry/Private/Apple/SentrySubsystemApple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ void SentrySubsystemApple::InitWithSettings(const USentrySettings* settings, USe
[options addInAppExclude:it->GetNSString()];
}
options.enableAppHangTracking = settings->EnableAppNotRespondingTracking;
options.enableTracing = settings->EnableTracing;
if(settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate)
{
options.tracesSampleRate = [NSNumber numberWithFloat:settings->TracesSampleRate];
Expand Down Expand Up @@ -303,3 +302,38 @@ USentryTransaction* SentrySubsystemApple::StartTransactionWithContextAndOptions(

return SentryConvertorsApple::SentryTransactionToUnreal(transaction);
}

USentryTransactionContext* SentrySubsystemApple::ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders)
{
TArray<FString> traceParts;
sentryTrace.ParseIntoArray(traceParts, TEXT("-"));

if (traceParts.Num() < 2)
{
return nullptr;
}

SentrySampleDecision sampleDecision = kSentrySampleDecisionUndecided;
if (traceParts.Num() == 3)
{
sampleDecision = traceParts[2].Equals(TEXT("1")) ? kSentrySampleDecisionYes : kSentrySampleDecisionNo;
}

// `SentryId` definition was moved to Swift so its name that can be recognized by UE should be taken from "Sentry-Swift.h" to successfully load class on Mac

#if PLATFORM_MAC
SentryId* traceId = [[SENTRY_APPLE_CLASS(_TtC6Sentry8SentryId) alloc] initWithUUIDString:traceParts[0].GetNSString()];
#elif PLATFORM_IOS
SentryId* traceId = [[SENTRY_APPLE_CLASS(SentryId) alloc] initWithUUIDString:traceParts[0].GetNSString()];
#endif

SentryTransactionContext* transactionContext = [[SENTRY_APPLE_CLASS(SentryTransactionContext) alloc] initWithName:@"<unlabeled transaction>" operation:@"default"
traceId:traceId
spanId:[[SENTRY_APPLE_CLASS(SentrySpanId) alloc] init]
parentSpanId:[[SENTRY_APPLE_CLASS(SentrySpanId) alloc] initWithValue:traceParts[1].GetNSString()]
parentSampled:sampleDecision];

// currently `sentry-cocoa` doesn't have API for `SentryTransactionContext` to set `baggageHeaders`

return SentryConvertorsApple::SentryTransactionContextToUnreal(transactionContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ class SentrySubsystemApple : public ISentrySubsystem
virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override;
virtual USentryTransaction* StartTransactionWithContext(USentryTransactionContext* context) override;
virtual USentryTransaction* StartTransactionWithContextAndOptions(USentryTransactionContext* context, const TMap<FString, FString>& options) override;
virtual USentryTransactionContext* ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders) override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ void SentryTransactionApple::RemoveData(const FString& key)
{
[TransactionApple removeDataForKey:key.GetNSString()];
}

void SentryTransactionApple::GetTrace(FString& name, FString& value)
{
SentryTraceHeader* traceHeader = [TransactionApple toTraceHeader];

name = TEXT("sentry-trace");
value = FString([traceHeader value]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SentryTransactionApple : public ISentryTransaction
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;
virtual void GetTrace(FString& name, FString& value) override;

private:
id<SentrySpan> TransactionApple;
Expand Down
18 changes: 18 additions & 0 deletions plugin-dev/Source/Sentry/Private/Desktop/SentrySpanDesktop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

#if USE_SENTRY_NATIVE

void CopySpanTracingHeader(const char *key, const char *value, void *userdata)
{
sentry_value_t *header = static_cast<sentry_value_t*>(userdata);
sentry_value_set_by_key(*header, key, sentry_value_new_string(value));
}

SentrySpanDesktop::SentrySpanDesktop(sentry_span_t* span)
: SpanDesktop(span)
, isFinished(false)
Expand Down Expand Up @@ -62,4 +68,16 @@ void SentrySpanDesktop::RemoveData(const FString& key)
sentry_span_remove_data(SpanDesktop, TCHAR_TO_ANSI(*key));
}

void SentrySpanDesktop::GetTrace(FString& name, FString& value)
{
sentry_value_t tracingHeader = sentry_value_new_object();

sentry_span_iter_headers(SpanDesktop, CopySpanTracingHeader, &tracingHeader);

name = TEXT("sentry-trace");
value = FString(sentry_value_as_string(sentry_value_get_by_key(tracingHeader, "sentry-trace")));

sentry_value_decref(tracingHeader);
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class SentrySpanDesktop : public ISentrySpan
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;
virtual void GetTrace(FString& name, FString& value) override;

private:
sentry_span_t* SpanDesktop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,21 @@ USentryTransaction* SentrySubsystemDesktop::StartTransactionWithContextAndOption
return StartTransactionWithContext(context);
}

USentryTransactionContext* SentrySubsystemDesktop::ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders)
{
sentry_transaction_context_t* nativeTransactionContext = sentry_transaction_context_new("<unlabeled transaction>", "default");
sentry_transaction_context_update_from_header(nativeTransactionContext, "sentry-trace", TCHAR_TO_ANSI(*sentryTrace));

// currently `sentry-native` doesn't have API for `sentry_transaction_context_t` to set `baggageHeaders`

TSharedPtr<SentryTransactionContextDesktop> transactionContextDesktop = MakeShareable(new SentryTransactionContextDesktop(nativeTransactionContext));

USentryTransactionContext* TransactionContext = NewObject<USentryTransactionContext>();
TransactionContext->InitWithNativeImpl(transactionContextDesktop);

return TransactionContext;
}

USentryBeforeSendHandler* SentrySubsystemDesktop::GetBeforeSendHandler()
{
return beforeSend;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class SentrySubsystemDesktop : public ISentrySubsystem
virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) override;
virtual USentryTransaction* StartTransactionWithContext(USentryTransactionContext* context) override;
virtual USentryTransaction* StartTransactionWithContextAndOptions(USentryTransactionContext* context, const TMap<FString, FString>& options) override;
virtual USentryTransactionContext* ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders) override;

USentryBeforeSendHandler* GetBeforeSendHandler();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

#if USE_SENTRY_NATIVE

void CopyTransactionTracingHeader(const char *key, const char *value, void *userdata)
{
sentry_value_t *header = static_cast<sentry_value_t*>(userdata);
sentry_value_set_by_key(*header, key, sentry_value_new_string(value));
}

SentryTransactionDesktop::SentryTransactionDesktop(sentry_transaction_t* transaction)
: TransactionDesktop(transaction)
, isFinished(false)
Expand Down Expand Up @@ -77,4 +83,16 @@ void SentryTransactionDesktop::RemoveData(const FString& key)
sentry_transaction_remove_data(TransactionDesktop, TCHAR_TO_ANSI(*key));
}

void SentryTransactionDesktop::GetTrace(FString& name, FString& value)
{
sentry_value_t tracingHeader = sentry_value_new_object();

sentry_transaction_iter_headers(TransactionDesktop, CopyTransactionTracingHeader, &tracingHeader);

name = TEXT("sentry-trace");
value = FString(sentry_value_as_string(sentry_value_get_by_key(tracingHeader, "sentry-trace")));

sentry_value_decref(tracingHeader);
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class SentryTransactionDesktop : public ISentryTransaction
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;
virtual void GetTrace(FString& name, FString& value) override;

private:
sentry_transaction_t* TransactionDesktop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ class ISentrySpan
virtual void RemoveTag(const FString& key) = 0;
virtual void SetData(const FString& key, const TMap<FString, FString>& values) = 0;
virtual void RemoveData(const FString& key) = 0;
virtual void GetTrace(FString& name, FString& value) = 0;
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@ class ISentrySubsystem
virtual USentryTransaction* StartTransaction(const FString& name, const FString& operation) = 0;
virtual USentryTransaction* StartTransactionWithContext(USentryTransactionContext* context) = 0;
virtual USentryTransaction* StartTransactionWithContextAndOptions(USentryTransactionContext* context, const TMap<FString, FString>& options) = 0;
virtual USentryTransactionContext* ContinueTrace(const FString& sentryTrace, const TArray<FString>& baggageHeaders) = 0;
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ class ISentryTransaction
virtual void RemoveTag(const FString& key) = 0;
virtual void SetData(const FString& key, const TMap<FString, FString>& values) = 0;
virtual void RemoveData(const FString& key) = 0;
virtual void GetTrace(FString& name, FString& value) = 0;
};
8 changes: 8 additions & 0 deletions plugin-dev/Source/Sentry/Private/SentrySpan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ void USentrySpan::RemoveData(const FString& key)
SentrySpanNativeImpl->RemoveData(key);
}

void USentrySpan::GetTrace(FString& name, FString& value)
{
if (!SentrySpanNativeImpl || SentrySpanNativeImpl->IsFinished())
return;

SentrySpanNativeImpl->GetTrace(name, value);
}

void USentrySpan::InitWithNativeImpl(TSharedPtr<ISentrySpan> spanImpl)
{
SentrySpanNativeImpl = spanImpl;
Expand Down
8 changes: 8 additions & 0 deletions plugin-dev/Source/Sentry/Private/SentrySubsystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,14 @@ USentryTransaction* USentrySubsystem::StartTransactionWithContextAndOptions(USen
return SubsystemNativeImpl->StartTransactionWithContextAndOptions(Context, Options);
}

USentryTransactionContext* USentrySubsystem::ContinueTrace(const FString& SentryTrace, const TArray<FString>& BaggageHeaders)
{
if (!SubsystemNativeImpl || !SubsystemNativeImpl->IsEnabled())
return nullptr;

return SubsystemNativeImpl->ContinueTrace(SentryTrace, BaggageHeaders);
}

bool USentrySubsystem::IsSupportedForCurrentSettings()
{
if(!IsCurrentBuildConfigurationEnabled() || !IsCurrentBuildTargetEnabled() || !IsCurrentPlatformEnabled())
Expand Down
8 changes: 8 additions & 0 deletions plugin-dev/Source/Sentry/Private/SentryTransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ void USentryTransaction::RemoveData(const FString& key)
SentryTransactionNativeImpl->RemoveData(key);
}

void USentryTransaction::GetTrace(FString& name, FString& value)
{
if (!SentryTransactionNativeImpl || SentryTransactionNativeImpl->IsFinished())
return;

SentryTransactionNativeImpl->GetTrace(name, value);
}

void USentryTransaction::InitWithNativeImpl(TSharedPtr<ISentryTransaction> transactionImpl)
{
SentryTransactionNativeImpl = transactionImpl;
Expand Down
Loading

0 comments on commit be32823

Please sign in to comment.