Skip to content

Commit f3fe6f7

Browse files
committed
Add batch processor for Metrics
1 parent 617e851 commit f3fe6f7

File tree

12 files changed

+386
-30
lines changed

12 files changed

+386
-30
lines changed

sentry-android-core/src/test/java/io/sentry/android/core/SessionTrackingIntegrationTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import io.sentry.SentryEnvelope
1818
import io.sentry.SentryEvent
1919
import io.sentry.SentryLogEvent
2020
import io.sentry.SentryLogEvents
21+
import io.sentry.SentryMetricsEvents
2122
import io.sentry.SentryReplayEvent
2223
import io.sentry.Session
2324
import io.sentry.TraceContext
@@ -192,6 +193,10 @@ class SessionTrackingIntegrationTest {
192193
TODO("Not yet implemented")
193194
}
194195

196+
override fun captureBatchedMetricsEvents(metricsEvents: SentryMetricsEvents) {
197+
TODO("Not yet implemented")
198+
}
199+
195200
override fun getRateLimiter(): RateLimiter? {
196201
TODO("Not yet implemented")
197202
}

sentry/api/sentry.api

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ public abstract interface class io/sentry/IScopesStorage {
10291029

10301030
public abstract interface class io/sentry/ISentryClient {
10311031
public abstract fun captureBatchedLogEvents (Lio/sentry/SentryLogEvents;)V
1032+
public abstract fun captureBatchedMetricsEvents (Lio/sentry/SentryMetricsEvents;)V
10321033
public abstract fun captureCheckIn (Lio/sentry/CheckIn;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
10331034
public fun captureEnvelope (Lio/sentry/SentryEnvelope;)Lio/sentry/protocol/SentryId;
10341035
public abstract fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
@@ -2852,6 +2853,7 @@ public final class io/sentry/SentryBaseEvent$Serializer {
28522853
public final class io/sentry/SentryClient : io/sentry/ISentryClient {
28532854
public fun <init> (Lio/sentry/SentryOptions;)V
28542855
public fun captureBatchedLogEvents (Lio/sentry/SentryLogEvents;)V
2856+
public fun captureBatchedMetricsEvents (Lio/sentry/SentryMetricsEvents;)V
28552857
public fun captureCheckIn (Lio/sentry/CheckIn;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
28562858
public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
28572859
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
@@ -2938,6 +2940,7 @@ public final class io/sentry/SentryEnvelopeItem {
29382940
public static fun fromClientReport (Lio/sentry/ISerializer;Lio/sentry/clientreport/ClientReport;)Lio/sentry/SentryEnvelopeItem;
29392941
public static fun fromEvent (Lio/sentry/ISerializer;Lio/sentry/SentryBaseEvent;)Lio/sentry/SentryEnvelopeItem;
29402942
public static fun fromLogs (Lio/sentry/ISerializer;Lio/sentry/SentryLogEvents;)Lio/sentry/SentryEnvelopeItem;
2943+
public static fun fromMetrics (Lio/sentry/ISerializer;Lio/sentry/SentryMetricsEvents;)Lio/sentry/SentryEnvelopeItem;
29412944
public static fun fromProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/ISerializer;)Lio/sentry/SentryEnvelopeItem;
29422945
public static fun fromProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/ISerializer;Lio/sentry/IProfileConverter;)Lio/sentry/SentryEnvelopeItem;
29432946
public static fun fromProfilingTrace (Lio/sentry/ProfilingTraceData;JLio/sentry/ISerializer;)Lio/sentry/SentryEnvelopeItem;
@@ -3322,6 +3325,66 @@ public final class io/sentry/SentryLongDate : io/sentry/SentryDate {
33223325
public fun nanoTimestamp ()J
33233326
}
33243327

3328+
public final class io/sentry/SentryMetricsEvent : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
3329+
public fun <init> (Lio/sentry/protocol/SentryId;Lio/sentry/SentryDate;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;)V
3330+
public fun <init> (Lio/sentry/protocol/SentryId;Ljava/lang/Double;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;)V
3331+
public fun getAttributes ()Ljava/util/Map;
3332+
public fun getName ()Ljava/lang/String;
3333+
public fun getSpanId ()Lio/sentry/SpanId;
3334+
public fun getTimestamp ()Ljava/lang/Double;
3335+
public fun getType ()Ljava/lang/String;
3336+
public fun getUnit ()Ljava/lang/String;
3337+
public fun getUnknown ()Ljava/util/Map;
3338+
public fun getValue ()Ljava/lang/Double;
3339+
public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V
3340+
public fun setAttribute (Ljava/lang/String;Lio/sentry/SentryLogEventAttributeValue;)V
3341+
public fun setAttributes (Ljava/util/Map;)V
3342+
public fun setName (Ljava/lang/String;)V
3343+
public fun setSpanId (Lio/sentry/SpanId;)V
3344+
public fun setTimestamp (Ljava/lang/Double;)V
3345+
public fun setType (Ljava/lang/String;)V
3346+
public fun setUnit (Ljava/lang/String;)V
3347+
public fun setUnknown (Ljava/util/Map;)V
3348+
public fun setValue (Ljava/lang/Double;)V
3349+
}
3350+
3351+
public final class io/sentry/SentryMetricsEvent$Deserializer : io/sentry/JsonDeserializer {
3352+
public fun <init> ()V
3353+
public fun deserialize (Lio/sentry/ObjectReader;Lio/sentry/ILogger;)Lio/sentry/SentryMetricsEvent;
3354+
public synthetic fun deserialize (Lio/sentry/ObjectReader;Lio/sentry/ILogger;)Ljava/lang/Object;
3355+
}
3356+
3357+
public final class io/sentry/SentryMetricsEvent$JsonKeys {
3358+
public static final field ATTRIBUTES Ljava/lang/String;
3359+
public static final field NAME Ljava/lang/String;
3360+
public static final field SPAN_ID Ljava/lang/String;
3361+
public static final field TIMESTAMP Ljava/lang/String;
3362+
public static final field TRACE_ID Ljava/lang/String;
3363+
public static final field TYPE Ljava/lang/String;
3364+
public static final field UNIT Ljava/lang/String;
3365+
public static final field VALUE Ljava/lang/String;
3366+
public fun <init> ()V
3367+
}
3368+
3369+
public final class io/sentry/SentryMetricsEvents : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
3370+
public fun <init> (Ljava/util/List;)V
3371+
public fun getItems ()Ljava/util/List;
3372+
public fun getUnknown ()Ljava/util/Map;
3373+
public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V
3374+
public fun setUnknown (Ljava/util/Map;)V
3375+
}
3376+
3377+
public final class io/sentry/SentryMetricsEvents$Deserializer : io/sentry/JsonDeserializer {
3378+
public fun <init> ()V
3379+
public fun deserialize (Lio/sentry/ObjectReader;Lio/sentry/ILogger;)Lio/sentry/SentryMetricsEvents;
3380+
public synthetic fun deserialize (Lio/sentry/ObjectReader;Lio/sentry/ILogger;)Ljava/lang/Object;
3381+
}
3382+
3383+
public final class io/sentry/SentryMetricsEvents$JsonKeys {
3384+
public static final field ITEMS Ljava/lang/String;
3385+
public fun <init> ()V
3386+
}
3387+
33253388
public final class io/sentry/SentryNanotimeDate : io/sentry/SentryDate {
33263389
public fun <init> ()V
33273390
public fun <init> (Ljava/util/Date;J)V
@@ -3697,7 +3760,7 @@ public final class io/sentry/SentryOptions$Metrics {
36973760
}
36983761

36993762
public abstract interface class io/sentry/SentryOptions$Metrics$BeforeSendMetricCallback {
3700-
public abstract fun execute (Ljava/lang/Object;)Ljava/lang/Object;
3763+
public abstract fun execute (Lio/sentry/SentryMetricsEvents;)Lio/sentry/SentryMetricsEvents;
37013764
}
37023765

37033766
public abstract interface class io/sentry/SentryOptions$OnDiscardCallback {
@@ -5126,20 +5189,53 @@ public final class io/sentry/logger/SentryLogParameters {
51265189
public fun setTimestamp (Lio/sentry/SentryDate;)V
51275190
}
51285191

5192+
public final class io/sentry/metrics/DefaultMetricsBatchProcessorFactory : io/sentry/metrics/IMetricsBatchProcessorFactory {
5193+
public fun <init> ()V
5194+
public fun create (Lio/sentry/SentryOptions;Lio/sentry/SentryClient;)Lio/sentry/metrics/IMetricsBatchProcessor;
5195+
}
5196+
51295197
public abstract interface class io/sentry/metrics/IMetricsApi {
51305198
public abstract fun count (Ljava/lang/String;)V
51315199
}
51325200

5201+
public abstract interface class io/sentry/metrics/IMetricsBatchProcessor {
5202+
public abstract fun add (Lio/sentry/SentryMetricsEvent;)V
5203+
public abstract fun close (Z)V
5204+
public abstract fun flush (J)V
5205+
}
5206+
5207+
public abstract interface class io/sentry/metrics/IMetricsBatchProcessorFactory {
5208+
public abstract fun create (Lio/sentry/SentryOptions;Lio/sentry/SentryClient;)Lio/sentry/metrics/IMetricsBatchProcessor;
5209+
}
5210+
51335211
public final class io/sentry/metrics/MetricsApi : io/sentry/metrics/IMetricsApi {
51345212
public fun <init> (Lio/sentry/Scopes;)V
51355213
public fun count (Ljava/lang/String;)V
51365214
}
51375215

5216+
public class io/sentry/metrics/MetricsBatchProcessor : io/sentry/metrics/IMetricsBatchProcessor {
5217+
public static final field FLUSH_AFTER_MS I
5218+
public static final field MAX_BATCH_SIZE I
5219+
public static final field MAX_QUEUE_SIZE I
5220+
protected final field options Lio/sentry/SentryOptions;
5221+
public fun <init> (Lio/sentry/SentryOptions;Lio/sentry/ISentryClient;)V
5222+
public fun add (Lio/sentry/SentryMetricsEvent;)V
5223+
public fun close (Z)V
5224+
public fun flush (J)V
5225+
}
5226+
51385227
public final class io/sentry/metrics/NoOpMetricsApi : io/sentry/metrics/IMetricsApi {
51395228
public fun count (Ljava/lang/String;)V
51405229
public static fun getInstance ()Lio/sentry/metrics/NoOpMetricsApi;
51415230
}
51425231

5232+
public final class io/sentry/metrics/NoOpMetricsBatchProcessor : io/sentry/metrics/IMetricsBatchProcessor {
5233+
public fun add (Lio/sentry/SentryMetricsEvent;)V
5234+
public fun close (Z)V
5235+
public fun flush (J)V
5236+
public static fun getInstance ()Lio/sentry/metrics/NoOpMetricsBatchProcessor;
5237+
}
5238+
51435239
public final class io/sentry/opentelemetry/OpenTelemetryUtil {
51445240
public fun <init> ()V
51455241
public static fun applyIgnoredSpanOrigins (Lio/sentry/SentryOptions;)V

sentry/src/main/java/io/sentry/ISentryClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ SentryId captureProfileChunk(
308308
@ApiStatus.Internal
309309
void captureBatchedLogEvents(@NotNull SentryLogEvents logEvents);
310310

311+
@ApiStatus.Internal
312+
void captureBatchedMetricsEvents(@NotNull SentryMetricsEvents metricsEvents);
313+
311314
@ApiStatus.Internal
312315
@Nullable
313316
RateLimiter getRateLimiter();

sentry/src/main/java/io/sentry/NoOpSentryClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ public void captureBatchedLogEvents(@NotNull SentryLogEvents logEvents) {
9494
// do nothing
9595
}
9696

97+
@ApiStatus.Internal
98+
@Override
99+
public void captureBatchedMetricsEvents(@NotNull SentryMetricsEvents metricsEvents) {
100+
// do nothing
101+
}
102+
97103
@Override
98104
public @Nullable RateLimiter getRateLimiter() {
99105
return null;

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,19 @@ public void captureUserFeedback(final @NotNull UserFeedback userFeedback) {
693693
return new SentryEnvelope(envelopeHeader, envelopeItems);
694694
}
695695

696+
private @NotNull SentryEnvelope buildEnvelope(final @NotNull SentryMetricsEvents metricsEvents) {
697+
final List<SentryEnvelopeItem> envelopeItems = new ArrayList<>();
698+
699+
final SentryEnvelopeItem metricsItem =
700+
SentryEnvelopeItem.fromMetrics(options.getSerializer(), metricsEvents);
701+
envelopeItems.add(metricsItem);
702+
703+
final SentryEnvelopeHeader envelopeHeader =
704+
new SentryEnvelopeHeader(null, options.getSdkVersion(), null);
705+
706+
return new SentryEnvelope(envelopeHeader, envelopeItems);
707+
}
708+
696709
private @NotNull SentryEnvelope buildEnvelope(
697710
final @NotNull SentryReplayEvent event,
698711
final @Nullable ReplayRecording replayRecording,
@@ -1218,7 +1231,18 @@ public void captureBatchedLogEvents(final @NotNull SentryLogEvents logEvents) {
12181231
final @NotNull SentryEnvelope envelope = buildEnvelope(logEvents);
12191232
sendEnvelope(envelope, null);
12201233
} catch (IOException e) {
1221-
options.getLogger().log(SentryLevel.WARNING, e, "Capturing log failed.");
1234+
options.getLogger().log(SentryLevel.WARNING, e, "Capturing logs failed.");
1235+
}
1236+
}
1237+
1238+
@ApiStatus.Internal
1239+
@Override
1240+
public void captureBatchedMetricsEvents(final @NotNull SentryMetricsEvents metricsEvents) {
1241+
try {
1242+
final @NotNull SentryEnvelope envelope = buildEnvelope(metricsEvents);
1243+
sendEnvelope(envelope, null);
1244+
} catch (IOException e) {
1245+
options.getLogger().log(SentryLevel.WARNING, e, "Capturing metrics failed.");
12221246
}
12231247
}
12241248

sentry/src/main/java/io/sentry/SentryMetricsEvent.java

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,41 @@
22

33
import static io.sentry.DateUtils.doubleToBigDecimal;
44

5-
import org.jetbrains.annotations.NotNull;
6-
import org.jetbrains.annotations.Nullable;
7-
5+
import io.sentry.protocol.SentryId;
6+
import io.sentry.vendor.gson.stream.JsonToken;
87
import java.io.IOException;
98
import java.util.HashMap;
109
import java.util.Map;
11-
12-
import io.sentry.protocol.SentryId;
13-
import io.sentry.vendor.gson.stream.JsonToken;
10+
import org.jetbrains.annotations.NotNull;
11+
import org.jetbrains.annotations.Nullable;
1412

1513
public final class SentryMetricsEvent implements JsonUnknown, JsonSerializable {
1614

1715
private @NotNull SentryId traceId;
1816
private @Nullable SpanId spanId;
19-
/**
20-
* Timestamp in seconds (epoch time) indicating when the metric was recorded.
21-
*/
17+
18+
/** Timestamp in seconds (epoch time) indicating when the metric was recorded. */
2219
private @NotNull Double timestamp;
20+
2321
/**
24-
* The name of the metric.
25-
* This should follow a hierarchical naming convention using dots as separators
26-
* (e.g., api.response_time, db.query.duration).
22+
* The name of the metric. This should follow a hierarchical naming convention using dots as
23+
* separators (e.g., api.response_time, db.query.duration).
2724
*/
2825
private @NotNull String name;
29-
/**
30-
* The unit of measurement for the metric value.
31-
*/
26+
27+
/** The unit of measurement for the metric value. */
3228
private @Nullable String unit;
29+
3330
/**
34-
* The type of metric. One of:
35-
* - counter: A metric that increments counts
36-
* - gauge: A metric that tracks a value that can go up or down
37-
* - distribution: A metric that tracks the statistical distribution of values
31+
* The type of metric. One of: - counter: A metric that increments counts - gauge: A metric that
32+
* tracks a value that can go up or down - distribution: A metric that tracks the statistical
33+
* distribution of values
3834
*/
3935
private @NotNull String type;
36+
4037
/**
41-
* The numeric value of the metric. The interpretation depends on the metric type:
42-
* - For counter metrics: the count to increment by (should default to 1)
43-
* - For gauge metrics: the current value
38+
* The numeric value of the metric. The interpretation depends on the metric type: - For counter
39+
* metrics: the count to increment by (should default to 1) - For gauge metrics: the current value
4440
* - For distribution metrics: a single measured value
4541
*/
4642
private @NotNull Double value;
@@ -279,7 +275,8 @@ public static final class Deserializer implements JsonDeserializer<SentryMetrics
279275
throw exception;
280276
}
281277

282-
final SentryMetricsEvent logEvent = new SentryMetricsEvent(traceId, timestamp, name, type, value);
278+
final SentryMetricsEvent logEvent =
279+
new SentryMetricsEvent(traceId, timestamp, name, type, value);
283280

284281
logEvent.setAttributes(attributes);
285282
logEvent.setSpanId(spanId);

sentry/src/main/java/io/sentry/SentryMetricsEvents.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package io.sentry;
22

3-
import org.jetbrains.annotations.NotNull;
4-
import org.jetbrains.annotations.Nullable;
5-
3+
import io.sentry.vendor.gson.stream.JsonToken;
64
import java.io.IOException;
75
import java.util.HashMap;
86
import java.util.List;
97
import java.util.Map;
10-
11-
import io.sentry.vendor.gson.stream.JsonToken;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
1210

1311
public final class SentryMetricsEvents implements JsonUnknown, JsonSerializable {
1412

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.sentry.metrics;
2+
3+
import io.sentry.SentryClient;
4+
import io.sentry.SentryOptions;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public final class DefaultMetricsBatchProcessorFactory implements IMetricsBatchProcessorFactory {
8+
@Override
9+
public @NotNull IMetricsBatchProcessor create(
10+
@NotNull SentryOptions options, @NotNull SentryClient client) {
11+
return new MetricsBatchProcessor(options, client);
12+
}
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.sentry.metrics;
2+
3+
import io.sentry.SentryMetricsEvent;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
public interface IMetricsBatchProcessor {
7+
void add(@NotNull SentryMetricsEvent event);
8+
9+
void close(boolean isRestarting);
10+
11+
/**
12+
* Flushes log events.
13+
*
14+
* @param timeoutMillis time in milliseconds
15+
*/
16+
void flush(long timeoutMillis);
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.sentry.metrics;
2+
3+
import io.sentry.SentryClient;
4+
import io.sentry.SentryOptions;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public interface IMetricsBatchProcessorFactory {
8+
9+
@NotNull
10+
IMetricsBatchProcessor create(
11+
final @NotNull SentryOptions options, final @NotNull SentryClient client);
12+
}

0 commit comments

Comments
 (0)