Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b59f942
Add metrics api stubs
tustanivsky Jan 30, 2026
44eed67
Fix build errors and update naming
tustanivsky Feb 2, 2026
f04925b
Add temp Apple implementation
tustanivsky Feb 2, 2026
0e63c93
Fix cocoa binaries path in build deps script
tustanivsky Feb 2, 2026
4dc3dae
Merge branch 'main' into feat/metrics
tustanivsky Feb 4, 2026
cf4de17
Fix compilation errors
tustanivsky Feb 4, 2026
d139a69
Update changelog
tustanivsky Feb 4, 2026
ec3276b
Add default blueprint value for metric attributes
tustanivsky Feb 4, 2026
ac2558a
Add demo UI
tustanivsky Feb 4, 2026
56b9af3
Add metrics api implementation for native
tustanivsky Feb 4, 2026
334dab1
Merge branch 'main' into feat/metrics
tustanivsky Feb 5, 2026
967864e
Merge branch 'main' into feat/metrics
tustanivsky Feb 5, 2026
1301253
Remove unit for counters
tustanivsky Feb 6, 2026
918954a
FIx Android build error
tustanivsky Feb 6, 2026
6b68e96
Comment Apple metrics impl
tustanivsky Feb 6, 2026
50d026f
Refactor unit
tustanivsky Feb 6, 2026
a77a770
Format code
getsentry-bot Feb 6, 2026
7da386d
Update snapshot
tustanivsky Feb 6, 2026
747b057
Refactor
tustanivsky Feb 6, 2026
0a0be38
Add attribute map convertor
tustanivsky Feb 6, 2026
1e3cf1c
Formatting
tustanivsky Feb 6, 2026
60a926a
Fix demo blueprint
tustanivsky Feb 6, 2026
b3f29a7
Add cons ref
tustanivsky Feb 6, 2026
bbb987f
Format code
getsentry-bot Feb 6, 2026
1e6a68f
Propagate metrics setting on Android and Apple
tustanivsky Feb 6, 2026
6650729
Merge branch 'feat/metrics' of github.com:getsentry/sentry-unreal int…
tustanivsky Feb 6, 2026
26a077d
Add before send metric handler
tustanivsky Feb 6, 2026
ba18be1
Add metric type enum and handle double/float
tustanivsky Feb 6, 2026
2e36c9a
Expose metric unit to blueprints
tustanivsky Feb 6, 2026
2941e5a
Add test metric handler blueprint
tustanivsky Feb 6, 2026
83d3caf
Fix android build errors
tustanivsky Feb 6, 2026
893ed4a
Fix sample gui layout on mobile
tustanivsky Feb 6, 2026
f96d2e9
Update package snapshot
tustanivsky Feb 6, 2026
d72eeff
Fix missing initializer
tustanivsky Feb 6, 2026
4411dd2
Fix packaging script
tustanivsky Feb 6, 2026
90cf838
Fix pr suggestions
tustanivsky Feb 6, 2026
d0951da
Remove unit enum getter
tustanivsky Feb 6, 2026
d1e9820
Format code
getsentry-bot Feb 6, 2026
ba4fb62
Add unit tests
tustanivsky Feb 6, 2026
7d56c99
Update package snapshot
tustanivsky Feb 6, 2026
6397ad2
Refactor attribute get/set/remove utils in Java bridge
tustanivsky Feb 6, 2026
4f6a68d
Fix tests
tustanivsky Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- Add Metrics API support ([#1214](https://github.com/getsentry/sentry-unreal/pull/1214))

### Dependencies

- Bump Cocoa SDK from v9.3.0 to v9.4.0 ([#1218](https://github.com/getsentry/sentry-unreal/pull/1218))
Expand Down
134 changes: 134 additions & 0 deletions plugin-dev/Source/Sentry/Private/Android/AndroidSentryMetric.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright (c) 2025 Sentry. All Rights Reserved.

#include "AndroidSentryMetric.h"

#include "Infrastructure/AndroidSentryConverters.h"
#include "Infrastructure/AndroidSentryJavaClasses.h"

FAndroidSentryMetric::FAndroidSentryMetric()
: FSentryJavaObjectWrapper(SentryJavaClasses::SentryMetricsEvent, "()V")
{
SetupClassMethods();
}

FAndroidSentryMetric::FAndroidSentryMetric(jobject metricEvent)
: FSentryJavaObjectWrapper(SentryJavaClasses::SentryMetricsEvent, metricEvent)
{
SetupClassMethods();
}

void FAndroidSentryMetric::SetupClassMethods()
{
SetNameMethod = GetMethod("setName", "(Ljava/lang/String;)V");
GetNameMethod = GetMethod("getName", "()Ljava/lang/String;");
SetTypeMethod = GetMethod("setType", "(Ljava/lang/String;)V");
GetTypeMethod = GetMethod("getType", "()Ljava/lang/String;");
SetValueMethod = GetMethod("setValue", "(Ljava/lang/Double;)V");
GetValueMethod = GetMethod("getValue", "()Ljava/lang/Double;");
SetUnitMethod = GetMethod("setUnit", "(Ljava/lang/String;)V");
GetUnitMethod = GetMethod("getUnit", "()Ljava/lang/String;");
}

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

FString FAndroidSentryMetric::GetName() const
{
return CallMethod<FString>(GetNameMethod);
}

void FAndroidSentryMetric::SetType(const FString& type)
{
CallMethod<void>(SetTypeMethod, *GetJString(type));
}

FString FAndroidSentryMetric::GetType() const
{
return CallMethod<FString>(GetTypeMethod);
}

void FAndroidSentryMetric::SetValue(float value)
{
TSharedPtr<FSentryJavaObjectWrapper> javaDouble = MakeShareable(new FSentryJavaObjectWrapper(SentryJavaClasses::Double, "(D)V", static_cast<double>(value)));
CallMethod<void>(SetValueMethod, javaDouble->GetJObject());
}

float FAndroidSentryMetric::GetValue() const
{
auto valueObject = CallObjectMethod<jobject>(GetValueMethod);
if (!valueObject)
{
return 0.0f;
}

FSentryJavaObjectWrapper valueWrapper(SentryJavaClasses::Double, *valueObject);
FSentryJavaMethod floatValueMethod = valueWrapper.GetMethod("floatValue", "()F");
return valueWrapper.CallMethod<float>(floatValueMethod);
}

void FAndroidSentryMetric::SetUnit(const FString& unit)
{
CallMethod<void>(SetUnitMethod, *GetJString(unit));
}

FString FAndroidSentryMetric::GetUnit() const
{
return CallMethod<FString>(GetUnitMethod);
}

void FAndroidSentryMetric::SetAttribute(const FString& key, const FSentryVariant& value)
{
TSharedPtr<FSentryJavaObjectWrapper> attribute = FAndroidSentryConverters::VariantToNative(value);

if (!attribute)
{
return;
}

CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "setMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;Ljava/lang/Object;)V",
GetJObject(), *GetJString(key), attribute->GetJObject());
}

FSentryVariant FAndroidSentryMetric::GetAttribute(const FString& key) const
{
auto attribute = CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "getMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)Ljava/lang/Object;",
GetJObject(), *GetJString(key));

if (!attribute)
{
return FSentryVariant();
}

return FAndroidSentryConverters::VariantToUnreal(*attribute);
}

bool FAndroidSentryMetric::TryGetAttribute(const FString& key, FSentryVariant& value) const
{
auto attribute = CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "getMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)Ljava/lang/Object;",
GetJObject(), *GetJString(key));

if (!attribute)
{
return false;
}

value = FAndroidSentryConverters::VariantToUnreal(*attribute);

return true;
}

void FAndroidSentryMetric::RemoveAttribute(const FString& key)
{
CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "removeMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)V",
GetJObject(), *GetJString(key));
}

void FAndroidSentryMetric::AddAttributes(const TMap<FString, FSentryVariant>& attributes)
{
for (const auto& pair : attributes)
{
SetAttribute(pair.Key, pair.Value);
}
}
43 changes: 43 additions & 0 deletions plugin-dev/Source/Sentry/Private/Android/AndroidSentryMetric.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2025 Sentry. All Rights Reserved.

#pragma once

#include "Interface/SentryMetricInterface.h"

#include "Infrastructure/AndroidSentryJavaObjectWrapper.h"

class FAndroidSentryMetric : public ISentryMetric, public FSentryJavaObjectWrapper
{
public:
FAndroidSentryMetric();
FAndroidSentryMetric(jobject metricEvent);

void SetupClassMethods();

virtual void SetName(const FString& name) override;
virtual FString GetName() const override;
virtual void SetType(const FString& type) override;
virtual FString GetType() const override;
virtual void SetValue(float value) override;
virtual float GetValue() const override;
virtual void SetUnit(const FString& unit) override;
virtual FString GetUnit() const override;

virtual void SetAttribute(const FString& key, const FSentryVariant& value) override;
virtual FSentryVariant GetAttribute(const FString& key) const override;
virtual bool TryGetAttribute(const FString& key, FSentryVariant& value) const override;
virtual void RemoveAttribute(const FString& key) override;
virtual void AddAttributes(const TMap<FString, FSentryVariant>& attributes) override;

private:
FSentryJavaMethod SetNameMethod;
FSentryJavaMethod GetNameMethod;
FSentryJavaMethod SetTypeMethod;
FSentryJavaMethod GetTypeMethod;
FSentryJavaMethod SetValueMethod;
FSentryJavaMethod GetValueMethod;
FSentryJavaMethod SetUnitMethod;
FSentryJavaMethod GetUnitMethod;
};

typedef FAndroidSentryMetric FPlatformSentryMetric;
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ FAndroidSentrySubsystem::~FAndroidSentrySubsystem()
SentryJavaClasses::ClearJavaClassRefsCache();
}

void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryTraceSampler* traceSampler)
void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryBeforeMetricHandler* beforeMetricHandler, USentryTraceSampler* traceSampler)
{
isScreenshotAttachmentEnabled = settings->AttachScreenshot;

Expand All @@ -67,6 +67,7 @@ void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings,
SettingsJson->SetBoolField(TEXT("enableAnrTracking"), settings->EnableAppNotRespondingTracking);
SettingsJson->SetBoolField(TEXT("enableAutoLogAttachment"), settings->EnableAutoLogAttachment);
SettingsJson->SetBoolField(TEXT("enableStructuredLogging"), settings->EnableStructuredLogging);
SettingsJson->SetBoolField(TEXT("enableMetrics"), settings->EnableMetrics);
if (settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate)
{
SettingsJson->SetNumberField(TEXT("tracesSampleRate"), settings->TracesSampleRate);
Expand All @@ -87,6 +88,10 @@ void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings,
{
SettingsJson->SetNumberField(TEXT("beforeLogHandler"), (jlong)beforeLogHandler);
}
if (beforeMetricHandler != nullptr)
{
SettingsJson->SetNumberField(TEXT("beforeMetricHandler"), (jlong)beforeMetricHandler);
}

FString SettingsJsonStr;
TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&SettingsJsonStr);
Expand Down Expand Up @@ -194,6 +199,27 @@ void FAndroidSentrySubsystem::AddLog(const FString& Message, ESentryLevel Level,
}
}

void FAndroidSentrySubsystem::AddCount(const FString& Key, int32 Value, const TMap<FString, FSentryVariant>& Attributes)
{
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricCount", "(Ljava/lang/String;DLjava/util/HashMap;)V",
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), attributesMap->GetJObject());
}

void FAndroidSentrySubsystem::AddDistribution(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes)
{
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricDistribution", "(Ljava/lang/String;DLjava/lang/String;Ljava/util/HashMap;)V",
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), *FSentryJavaObjectWrapper::GetJString(Unit), attributesMap->GetJObject());
}

void FAndroidSentrySubsystem::AddGauge(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes)
{
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricGauge", "(Ljava/lang/String;DLjava/lang/String;Ljava/util/HashMap;)V",
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), *FSentryJavaObjectWrapper::GetJString(Unit), attributesMap->GetJObject());
}

void FAndroidSentrySubsystem::ClearBreadcrumbs()
{
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "clearBreadcrumbs", "()V");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ class FAndroidSentrySubsystem : public ISentrySubsystem
FAndroidSentrySubsystem();
~FAndroidSentrySubsystem();

virtual void InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryTraceSampler* traceSampler) override;
virtual void InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryBeforeMetricHandler* beforeMetricHandler, USentryTraceSampler* traceSampler) override;
virtual void Close() override;
virtual bool IsEnabled() override;
virtual ESentryCrashedLastRun IsCrashedLastRun() override;
virtual void AddBreadcrumb(TSharedPtr<ISentryBreadcrumb> breadcrumb) override;
virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap<FString, FSentryVariant>& Data, ESentryLevel Level) override;
virtual void AddLog(const FString& Message, ESentryLevel Level, const TMap<FString, FSentryVariant>& Attributes) override;
virtual void AddCount(const FString& Key, int32 Value, const TMap<FString, FSentryVariant>& Attributes) override;
virtual void AddDistribution(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes) override;
virtual void AddGauge(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes) override;
virtual void ClearBreadcrumbs() override;
virtual void AddAttachment(TSharedPtr<ISentryAttachment> attachment) override;
virtual void RemoveAttachment(TSharedPtr<ISentryAttachment> attachment) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const FSentryJavaClass SentryJavaClasses::TransactionOptions = FSentryJavaClass
const FSentryJavaClass SentryJavaClasses::SentryTraceHeader = FSentryJavaClass { "io/sentry/SentryTraceHeader", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::SentryLogEvent = FSentryJavaClass { "io/sentry/SentryLogEvent", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::SentryLogLevel = FSentryJavaClass { "io/sentry/SentryLogLevel", ESentryJavaClassType::External };
const FSentryJavaClass SentryJavaClasses::SentryMetricsEvent = FSentryJavaClass { "io/sentry/SentryMetricsEvent", ESentryJavaClassType::External };

// System Java classes definitions
const FSentryJavaClass SentryJavaClasses::ArrayList = FSentryJavaClass { "java/util/ArrayList", ESentryJavaClassType::System };
Expand Down Expand Up @@ -73,6 +74,7 @@ void SentryJavaClasses::InitJavaClassRefsCache()
JavaClassRefsCache.Add(SentryTraceHeader.Name, FindJavaClassRef(SentryTraceHeader));
JavaClassRefsCache.Add(SentryLogEvent.Name, FindJavaClassRef(SentryLogEvent));
JavaClassRefsCache.Add(SentryLogLevel.Name, FindJavaClassRef(SentryLogLevel));
JavaClassRefsCache.Add(SentryMetricsEvent.Name, FindJavaClassRef(SentryMetricsEvent));

// System Java classes definitions
JavaClassRefsCache.Add(ArrayList.Name, FindJavaClassRef(ArrayList));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct SentryJavaClasses
const static FSentryJavaClass SentryTraceHeader;
const static FSentryJavaClass SentryLogEvent;
const static FSentryJavaClass SentryLogLevel;
const static FSentryJavaClass SentryMetricsEvent;

// System Java classes
const static FSentryJavaClass ArrayList;
Expand Down
Loading
Loading