Skip to content

Commit ac9cf4b

Browse files
Add Metrics API support (#1214)
* Add metrics api stubs * Fix build errors and update naming * Add temp Apple implementation * Fix cocoa binaries path in build deps script * Fix compilation errors * Update changelog * Add default blueprint value for metric attributes * Add demo UI * Add metrics api implementation for native * Remove unit for counters * FIx Android build error * Comment Apple metrics impl * Refactor unit * Format code * Update snapshot * Refactor * Add attribute map convertor * Formatting * Fix demo blueprint * Add cons ref * Format code * Propagate metrics setting on Android and Apple * Add before send metric handler * Add metric type enum and handle double/float * Expose metric unit to blueprints * Add test metric handler blueprint * Fix android build errors * Fix sample gui layout on mobile * Update package snapshot * Fix missing initializer * Fix packaging script * Fix pr suggestions * Remove unit enum getter * Format code * Add unit tests * Update package snapshot * Refactor attribute get/set/remove utils in Java bridge * Fix tests --------- Co-authored-by: Sentry Github Bot <bot+github-bot@sentry.io>
1 parent fb86b72 commit ac9cf4b

50 files changed

Lines changed: 1518 additions & 61 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Add Metrics API support ([#1214](https://github.com/getsentry/sentry-unreal/pull/1214))
8+
59
### Dependencies
610

711
- Bump Cocoa SDK from v9.3.0 to v9.4.0 ([#1218](https://github.com/getsentry/sentry-unreal/pull/1218))
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2025 Sentry. All Rights Reserved.
2+
3+
#include "AndroidSentryMetric.h"
4+
5+
#include "Infrastructure/AndroidSentryConverters.h"
6+
#include "Infrastructure/AndroidSentryJavaClasses.h"
7+
8+
FAndroidSentryMetric::FAndroidSentryMetric()
9+
: FSentryJavaObjectWrapper(SentryJavaClasses::SentryMetricsEvent, "()V")
10+
{
11+
SetupClassMethods();
12+
}
13+
14+
FAndroidSentryMetric::FAndroidSentryMetric(jobject metricEvent)
15+
: FSentryJavaObjectWrapper(SentryJavaClasses::SentryMetricsEvent, metricEvent)
16+
{
17+
SetupClassMethods();
18+
}
19+
20+
void FAndroidSentryMetric::SetupClassMethods()
21+
{
22+
SetNameMethod = GetMethod("setName", "(Ljava/lang/String;)V");
23+
GetNameMethod = GetMethod("getName", "()Ljava/lang/String;");
24+
SetTypeMethod = GetMethod("setType", "(Ljava/lang/String;)V");
25+
GetTypeMethod = GetMethod("getType", "()Ljava/lang/String;");
26+
SetValueMethod = GetMethod("setValue", "(Ljava/lang/Double;)V");
27+
GetValueMethod = GetMethod("getValue", "()Ljava/lang/Double;");
28+
SetUnitMethod = GetMethod("setUnit", "(Ljava/lang/String;)V");
29+
GetUnitMethod = GetMethod("getUnit", "()Ljava/lang/String;");
30+
}
31+
32+
void FAndroidSentryMetric::SetName(const FString& name)
33+
{
34+
CallMethod<void>(SetNameMethod, *GetJString(name));
35+
}
36+
37+
FString FAndroidSentryMetric::GetName() const
38+
{
39+
return CallMethod<FString>(GetNameMethod);
40+
}
41+
42+
void FAndroidSentryMetric::SetType(const FString& type)
43+
{
44+
CallMethod<void>(SetTypeMethod, *GetJString(type));
45+
}
46+
47+
FString FAndroidSentryMetric::GetType() const
48+
{
49+
return CallMethod<FString>(GetTypeMethod);
50+
}
51+
52+
void FAndroidSentryMetric::SetValue(float value)
53+
{
54+
TSharedPtr<FSentryJavaObjectWrapper> javaDouble = MakeShareable(new FSentryJavaObjectWrapper(SentryJavaClasses::Double, "(D)V", static_cast<double>(value)));
55+
CallMethod<void>(SetValueMethod, javaDouble->GetJObject());
56+
}
57+
58+
float FAndroidSentryMetric::GetValue() const
59+
{
60+
auto valueObject = CallObjectMethod<jobject>(GetValueMethod);
61+
if (!valueObject)
62+
{
63+
return 0.0f;
64+
}
65+
66+
FSentryJavaObjectWrapper valueWrapper(SentryJavaClasses::Double, *valueObject);
67+
FSentryJavaMethod floatValueMethod = valueWrapper.GetMethod("floatValue", "()F");
68+
return valueWrapper.CallMethod<float>(floatValueMethod);
69+
}
70+
71+
void FAndroidSentryMetric::SetUnit(const FString& unit)
72+
{
73+
CallMethod<void>(SetUnitMethod, *GetJString(unit));
74+
}
75+
76+
FString FAndroidSentryMetric::GetUnit() const
77+
{
78+
return CallMethod<FString>(GetUnitMethod);
79+
}
80+
81+
void FAndroidSentryMetric::SetAttribute(const FString& key, const FSentryVariant& value)
82+
{
83+
TSharedPtr<FSentryJavaObjectWrapper> attribute = FAndroidSentryConverters::VariantToNative(value);
84+
85+
if (!attribute)
86+
{
87+
return;
88+
}
89+
90+
CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "setMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;Ljava/lang/Object;)V",
91+
GetJObject(), *GetJString(key), attribute->GetJObject());
92+
}
93+
94+
FSentryVariant FAndroidSentryMetric::GetAttribute(const FString& key) const
95+
{
96+
auto attribute = CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "getMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)Ljava/lang/Object;",
97+
GetJObject(), *GetJString(key));
98+
99+
if (!attribute)
100+
{
101+
return FSentryVariant();
102+
}
103+
104+
return FAndroidSentryConverters::VariantToUnreal(*attribute);
105+
}
106+
107+
bool FAndroidSentryMetric::TryGetAttribute(const FString& key, FSentryVariant& value) const
108+
{
109+
auto attribute = CallStaticObjectMethod<jobject>(SentryJavaClasses::SentryBridgeJava, "getMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)Ljava/lang/Object;",
110+
GetJObject(), *GetJString(key));
111+
112+
if (!attribute)
113+
{
114+
return false;
115+
}
116+
117+
value = FAndroidSentryConverters::VariantToUnreal(*attribute);
118+
119+
return true;
120+
}
121+
122+
void FAndroidSentryMetric::RemoveAttribute(const FString& key)
123+
{
124+
CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "removeMetricAttribute", "(Lio/sentry/SentryMetricsEvent;Ljava/lang/String;)V",
125+
GetJObject(), *GetJString(key));
126+
}
127+
128+
void FAndroidSentryMetric::AddAttributes(const TMap<FString, FSentryVariant>& attributes)
129+
{
130+
for (const auto& pair : attributes)
131+
{
132+
SetAttribute(pair.Key, pair.Value);
133+
}
134+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2025 Sentry. All Rights Reserved.
2+
3+
#pragma once
4+
5+
#include "Interface/SentryMetricInterface.h"
6+
7+
#include "Infrastructure/AndroidSentryJavaObjectWrapper.h"
8+
9+
class FAndroidSentryMetric : public ISentryMetric, public FSentryJavaObjectWrapper
10+
{
11+
public:
12+
FAndroidSentryMetric();
13+
FAndroidSentryMetric(jobject metricEvent);
14+
15+
void SetupClassMethods();
16+
17+
virtual void SetName(const FString& name) override;
18+
virtual FString GetName() const override;
19+
virtual void SetType(const FString& type) override;
20+
virtual FString GetType() const override;
21+
virtual void SetValue(float value) override;
22+
virtual float GetValue() const override;
23+
virtual void SetUnit(const FString& unit) override;
24+
virtual FString GetUnit() const override;
25+
26+
virtual void SetAttribute(const FString& key, const FSentryVariant& value) override;
27+
virtual FSentryVariant GetAttribute(const FString& key) const override;
28+
virtual bool TryGetAttribute(const FString& key, FSentryVariant& value) const override;
29+
virtual void RemoveAttribute(const FString& key) override;
30+
virtual void AddAttributes(const TMap<FString, FSentryVariant>& attributes) override;
31+
32+
private:
33+
FSentryJavaMethod SetNameMethod;
34+
FSentryJavaMethod GetNameMethod;
35+
FSentryJavaMethod SetTypeMethod;
36+
FSentryJavaMethod GetTypeMethod;
37+
FSentryJavaMethod SetValueMethod;
38+
FSentryJavaMethod GetValueMethod;
39+
FSentryJavaMethod SetUnitMethod;
40+
FSentryJavaMethod GetUnitMethod;
41+
};
42+
43+
typedef FAndroidSentryMetric FPlatformSentryMetric;

plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ FAndroidSentrySubsystem::~FAndroidSentrySubsystem()
4545
SentryJavaClasses::ClearJavaClassRefsCache();
4646
}
4747

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

@@ -67,6 +67,7 @@ void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings,
6767
SettingsJson->SetBoolField(TEXT("enableAnrTracking"), settings->EnableAppNotRespondingTracking);
6868
SettingsJson->SetBoolField(TEXT("enableAutoLogAttachment"), settings->EnableAutoLogAttachment);
6969
SettingsJson->SetBoolField(TEXT("enableStructuredLogging"), settings->EnableStructuredLogging);
70+
SettingsJson->SetBoolField(TEXT("enableMetrics"), settings->EnableMetrics);
7071
if (settings->EnableTracing && settings->SamplingType == ESentryTracesSamplingType::UniformSampleRate)
7172
{
7273
SettingsJson->SetNumberField(TEXT("tracesSampleRate"), settings->TracesSampleRate);
@@ -87,6 +88,10 @@ void FAndroidSentrySubsystem::InitWithSettings(const USentrySettings* settings,
8788
{
8889
SettingsJson->SetNumberField(TEXT("beforeLogHandler"), (jlong)beforeLogHandler);
8990
}
91+
if (beforeMetricHandler != nullptr)
92+
{
93+
SettingsJson->SetNumberField(TEXT("beforeMetricHandler"), (jlong)beforeMetricHandler);
94+
}
9095

9196
FString SettingsJsonStr;
9297
TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&SettingsJsonStr);
@@ -194,6 +199,27 @@ void FAndroidSentrySubsystem::AddLog(const FString& Message, ESentryLevel Level,
194199
}
195200
}
196201

202+
void FAndroidSentrySubsystem::AddCount(const FString& Key, int32 Value, const TMap<FString, FSentryVariant>& Attributes)
203+
{
204+
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
205+
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricCount", "(Ljava/lang/String;DLjava/util/HashMap;)V",
206+
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), attributesMap->GetJObject());
207+
}
208+
209+
void FAndroidSentrySubsystem::AddDistribution(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes)
210+
{
211+
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
212+
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricDistribution", "(Ljava/lang/String;DLjava/lang/String;Ljava/util/HashMap;)V",
213+
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), *FSentryJavaObjectWrapper::GetJString(Unit), attributesMap->GetJObject());
214+
}
215+
216+
void FAndroidSentrySubsystem::AddGauge(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes)
217+
{
218+
TSharedPtr<FSentryJavaObjectWrapper> attributesMap = FAndroidSentryConverters::VariantMapToNative(Attributes);
219+
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::SentryBridgeJava, "metricGauge", "(Ljava/lang/String;DLjava/lang/String;Ljava/util/HashMap;)V",
220+
*FSentryJavaObjectWrapper::GetJString(Key), static_cast<double>(Value), *FSentryJavaObjectWrapper::GetJString(Unit), attributesMap->GetJObject());
221+
}
222+
197223
void FAndroidSentrySubsystem::ClearBreadcrumbs()
198224
{
199225
FSentryJavaObjectWrapper::CallStaticMethod<void>(SentryJavaClasses::Sentry, "clearBreadcrumbs", "()V");

plugin-dev/Source/Sentry/Private/Android/AndroidSentrySubsystem.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ class FAndroidSentrySubsystem : public ISentrySubsystem
1010
FAndroidSentrySubsystem();
1111
~FAndroidSentrySubsystem();
1212

13-
virtual void InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryTraceSampler* traceSampler) override;
13+
virtual void InitWithSettings(const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryBeforeLogHandler* beforeLogHandler, USentryBeforeMetricHandler* beforeMetricHandler, USentryTraceSampler* traceSampler) override;
1414
virtual void Close() override;
1515
virtual bool IsEnabled() override;
1616
virtual ESentryCrashedLastRun IsCrashedLastRun() override;
1717
virtual void AddBreadcrumb(TSharedPtr<ISentryBreadcrumb> breadcrumb) override;
1818
virtual void AddBreadcrumbWithParams(const FString& Message, const FString& Category, const FString& Type, const TMap<FString, FSentryVariant>& Data, ESentryLevel Level) override;
1919
virtual void AddLog(const FString& Message, ESentryLevel Level, const TMap<FString, FSentryVariant>& Attributes) override;
20+
virtual void AddCount(const FString& Key, int32 Value, const TMap<FString, FSentryVariant>& Attributes) override;
21+
virtual void AddDistribution(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes) override;
22+
virtual void AddGauge(const FString& Key, float Value, const FString& Unit, const TMap<FString, FSentryVariant>& Attributes) override;
2023
virtual void ClearBreadcrumbs() override;
2124
virtual void AddAttachment(TSharedPtr<ISentryAttachment> attachment) override;
2225
virtual void RemoveAttachment(TSharedPtr<ISentryAttachment> attachment) override;

plugin-dev/Source/Sentry/Private/Android/Infrastructure/AndroidSentryJavaClasses.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const FSentryJavaClass SentryJavaClasses::TransactionOptions = FSentryJavaClass
2929
const FSentryJavaClass SentryJavaClasses::SentryTraceHeader = FSentryJavaClass { "io/sentry/SentryTraceHeader", ESentryJavaClassType::External };
3030
const FSentryJavaClass SentryJavaClasses::SentryLogEvent = FSentryJavaClass { "io/sentry/SentryLogEvent", ESentryJavaClassType::External };
3131
const FSentryJavaClass SentryJavaClasses::SentryLogLevel = FSentryJavaClass { "io/sentry/SentryLogLevel", ESentryJavaClassType::External };
32+
const FSentryJavaClass SentryJavaClasses::SentryMetricsEvent = FSentryJavaClass { "io/sentry/SentryMetricsEvent", ESentryJavaClassType::External };
3233

3334
// System Java classes definitions
3435
const FSentryJavaClass SentryJavaClasses::ArrayList = FSentryJavaClass { "java/util/ArrayList", ESentryJavaClassType::System };
@@ -73,6 +74,7 @@ void SentryJavaClasses::InitJavaClassRefsCache()
7374
JavaClassRefsCache.Add(SentryTraceHeader.Name, FindJavaClassRef(SentryTraceHeader));
7475
JavaClassRefsCache.Add(SentryLogEvent.Name, FindJavaClassRef(SentryLogEvent));
7576
JavaClassRefsCache.Add(SentryLogLevel.Name, FindJavaClassRef(SentryLogLevel));
77+
JavaClassRefsCache.Add(SentryMetricsEvent.Name, FindJavaClassRef(SentryMetricsEvent));
7678

7779
// System Java classes definitions
7880
JavaClassRefsCache.Add(ArrayList.Name, FindJavaClassRef(ArrayList));

plugin-dev/Source/Sentry/Private/Android/Infrastructure/AndroidSentryJavaClasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct SentryJavaClasses
2929
const static FSentryJavaClass SentryTraceHeader;
3030
const static FSentryJavaClass SentryLogEvent;
3131
const static FSentryJavaClass SentryLogLevel;
32+
const static FSentryJavaClass SentryMetricsEvent;
3233

3334
// System Java classes
3435
const static FSentryJavaClass ArrayList;

0 commit comments

Comments
 (0)