From e156d3ca8d99b8f18bee49f49d7e1a055086162b Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 17 Dec 2025 12:44:31 +0100 Subject: [PATCH 1/3] Metrics Options --- sentry/api/sentry.api | 18 +++- .../main/java/io/sentry/SentryOptions.java | 87 ++++++++++++++++--- 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index f6729869eb..b72982774d 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -3420,6 +3420,7 @@ public class io/sentry/SentryOptions { public fun getMaxRequestBodySize ()Lio/sentry/SentryOptions$RequestSize; public fun getMaxSpans ()I public fun getMaxTraceFileSize ()J + public fun getMetrics ()Lio/sentry/SentryOptions$Metrics; public fun getModulesLoader ()Lio/sentry/internal/modules/IModulesLoader; public fun getOnDiscard ()Lio/sentry/SentryOptions$OnDiscardCallback; public fun getOnOversizedEvent ()Lio/sentry/SentryOptions$OnOversizedEventCallback; @@ -3572,6 +3573,7 @@ public class io/sentry/SentryOptions { public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V public fun setMaxSpans (I)V public fun setMaxTraceFileSize (J)V + public fun setMetrics (Lio/sentry/SentryOptions$Metrics;)V public fun setModulesLoader (Lio/sentry/internal/modules/IModulesLoader;)V public fun setOnDiscard (Lio/sentry/SentryOptions$OnDiscardCallback;)V public fun setOnOversizedEvent (Lio/sentry/SentryOptions$OnOversizedEventCallback;)V @@ -3626,10 +3628,6 @@ public abstract interface class io/sentry/SentryOptions$BeforeBreadcrumbCallback public abstract fun execute (Lio/sentry/Breadcrumb;Lio/sentry/Hint;)Lio/sentry/Breadcrumb; } -public abstract interface class io/sentry/SentryOptions$BeforeEmitMetricCallback { - public abstract fun execute (Ljava/lang/String;Ljava/util/Map;)Z -} - public abstract interface class io/sentry/SentryOptions$BeforeEnvelopeCallback { public abstract fun execute (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V } @@ -3683,6 +3681,18 @@ public abstract interface class io/sentry/SentryOptions$Logs$BeforeSendLogCallba public abstract fun execute (Lio/sentry/SentryLogEvent;)Lio/sentry/SentryLogEvent; } +public final class io/sentry/SentryOptions$Metrics { + public fun ()V + public fun getBeforeSend ()Lio/sentry/SentryOptions$Metrics$BeforeSendMetricCallback; + public fun isEnabled ()Z + public fun setBeforeSend (Lio/sentry/SentryOptions$Metrics$BeforeSendMetricCallback;)V + public fun setEnabled (Z)V +} + +public abstract interface class io/sentry/SentryOptions$Metrics$BeforeSendMetricCallback { + public abstract fun execute (Ljava/lang/Object;)Ljava/lang/Object; +} + public abstract interface class io/sentry/SentryOptions$OnDiscardCallback { public abstract fun execute (Lio/sentry/clientreport/DiscardReason;Lio/sentry/DataCategory;Ljava/lang/Long;)V } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 835411cb61..2575328c70 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -624,6 +624,8 @@ public class SentryOptions { private @NotNull SentryOptions.Logs logs = new SentryOptions.Logs(); + private @NotNull SentryOptions.Metrics metrics = new SentryOptions.Metrics(); + private @NotNull ISocketTagger socketTagger = NoOpSocketTagger.getInstance(); /** Runtime manager to manage runtime policies, like StrictMode on Android. */ @@ -3261,20 +3263,6 @@ public interface BeforeEnvelopeCallback { void execute(@NotNull SentryEnvelope envelope, @Nullable Hint hint); } - /** The BeforeEmitMetric callback */ - @ApiStatus.Experimental - public interface BeforeEmitMetricCallback { - - /** - * A callback which gets called right before a metric is about to be emitted. - * - * @param key the metric key - * @param tags the metric tags - * @return true if the metric should be emitted, false otherwise - */ - boolean execute(@NotNull String key, @Nullable Map tags); - } - /** * Creates SentryOptions instance without initializing any of the internal parts. * @@ -3537,6 +3525,16 @@ public void setLogs(@NotNull SentryOptions.Logs logs) { this.logs = logs; } + @ApiStatus.Experimental + public @NotNull SentryOptions.Metrics getMetrics() { + return metrics; + } + + @ApiStatus.Experimental + public void setMetrics(@NotNull SentryOptions.Metrics metrics) { + this.metrics = metrics; + } + public static final class Proxy { private @Nullable String host; private @Nullable String port; @@ -3741,6 +3739,67 @@ public interface BeforeSendLogCallback { } } + public static final class Metrics { + + /** Whether Sentry Metrics feature is enabled and metrics are sent to Sentry. */ + private boolean enable = false; + + /** + * This function is called with a metric key and tags and can return false to skip sending the + * metric + */ + private @Nullable BeforeSendMetricCallback beforeSend; + + /** + * Whether Sentry Metrics feature is enabled and metrics are sent to Sentry. + * + * @return true if Sentry Metrics should be enabled + */ + public boolean isEnabled() { + return enable; + } + + /** + * Whether Sentry Metrics feature is enabled and metrics are sent to Sentry. + * + * @param enableMetrics true if Sentry Metrics should be enabled + */ + public void setEnabled(boolean enableMetrics) { + this.enable = enableMetrics; + } + + /** + * Returns the BeforeSendMetric callback + * + * @return the beforeSend callback or null if not set + */ + public @Nullable BeforeSendMetricCallback getBeforeSend() { + return beforeSend; + } + + /** + * Sets the beforeSend callback for metrics + * + * @param beforeSend the beforeSend callback for metrics + */ + public void setBeforeSend(@Nullable BeforeSendMetricCallback beforeSend) { + this.beforeSend = beforeSend; + } + + public interface BeforeSendMetricCallback { + + /** + * A callback which gets called right before a metric is about to be sent. + * + * @param metric the metric + * @return the original metric, mutated metric or null if metric was dropped + */ + // TODO replace with SentryMetric + @Nullable + Object execute(@NotNull Object metric); + } + } + @ApiStatus.Experimental public @NotNull DistributionOptions getDistribution() { return distribution; From b0ec8ebc20a0f8b97426b89415e1d0e97570bf85 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 17 Dec 2025 14:51:32 +0100 Subject: [PATCH 2/3] MetricsApi stub --- sentry/api/sentry.api | 22 +++++++++++++++++++ .../src/main/java/io/sentry/HubAdapter.java | 6 +++++ .../main/java/io/sentry/HubScopesWrapper.java | 6 +++++ sentry/src/main/java/io/sentry/IScopes.java | 4 ++++ sentry/src/main/java/io/sentry/NoOpHub.java | 7 ++++++ .../src/main/java/io/sentry/NoOpScopes.java | 7 ++++++ sentry/src/main/java/io/sentry/Scopes.java | 9 ++++++++ .../main/java/io/sentry/ScopesAdapter.java | 6 +++++ sentry/src/main/java/io/sentry/Sentry.java | 6 +++++ .../java/io/sentry/metrics/IMetricsApi.java | 11 ++++++++++ .../java/io/sentry/metrics/MetricsApi.java | 18 +++++++++++++++ .../io/sentry/metrics/NoOpMetricsApi.java | 16 ++++++++++++++ 12 files changed, 118 insertions(+) create mode 100644 sentry/src/main/java/io/sentry/metrics/IMetricsApi.java create mode 100644 sentry/src/main/java/io/sentry/metrics/MetricsApi.java create mode 100644 sentry/src/main/java/io/sentry/metrics/NoOpMetricsApi.java diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index b72982774d..f947368b75 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -661,6 +661,7 @@ public final class io/sentry/HubAdapter : io/sentry/IHub { public fun isHealthy ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -732,6 +733,7 @@ public final class io/sentry/HubScopesWrapper : io/sentry/IHub { public fun isHealthy ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -992,6 +994,7 @@ public abstract interface class io/sentry/IScopes { public fun isNoOp ()Z public abstract fun logger ()Lio/sentry/logger/ILoggerApi; public abstract fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public abstract fun metrics ()Lio/sentry/metrics/IMetricsApi; public abstract fun popScope ()V public abstract fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public abstract fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -1565,6 +1568,7 @@ public final class io/sentry/NoOpHub : io/sentry/IHub { public fun isNoOp ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -1741,6 +1745,7 @@ public final class io/sentry/NoOpScopes : io/sentry/IScopes { public fun isNoOp ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -2456,6 +2461,7 @@ public final class io/sentry/Scopes : io/sentry/IScopes { public fun isHealthy ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -2528,6 +2534,7 @@ public final class io/sentry/ScopesAdapter : io/sentry/IScopes { public fun isHealthy ()Z public fun logger ()Lio/sentry/logger/ILoggerApi; public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun metrics ()Lio/sentry/metrics/IMetricsApi; public fun popScope ()V public fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -2648,6 +2655,7 @@ public final class io/sentry/Sentry { public static fun isEnabled ()Z public static fun isHealthy ()Z public static fun logger ()Lio/sentry/logger/ILoggerApi; + public static fun metrics ()Lio/sentry/metrics/IMetricsApi; public static fun popScope ()V public static fun pushIsolationScope ()Lio/sentry/ISentryLifecycleToken; public static fun pushScope ()Lio/sentry/ISentryLifecycleToken; @@ -5123,6 +5131,20 @@ public final class io/sentry/logger/SentryLogParameters { public fun setTimestamp (Lio/sentry/SentryDate;)V } +public abstract interface class io/sentry/metrics/IMetricsApi { + public abstract fun count (Ljava/lang/String;)V +} + +public final class io/sentry/metrics/MetricsApi : io/sentry/metrics/IMetricsApi { + public fun (Lio/sentry/Scopes;)V + public fun count (Ljava/lang/String;)V +} + +public final class io/sentry/metrics/NoOpMetricsApi : io/sentry/metrics/IMetricsApi { + public fun count (Ljava/lang/String;)V + public static fun getInstance ()Lio/sentry/metrics/NoOpMetricsApi; +} + public final class io/sentry/opentelemetry/OpenTelemetryUtil { public fun ()V public static fun applyIgnoredSpanOrigins (Lio/sentry/SentryOptions;)V diff --git a/sentry/src/main/java/io/sentry/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java index 31a2e219cd..5715d06114 100644 --- a/sentry/src/main/java/io/sentry/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.logger.ILoggerApi; +import io.sentry.metrics.IMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -389,6 +390,11 @@ public void reportFullyDisplayed() { return Sentry.getCurrentScopes().logger(); } + @Override + public @NotNull IMetricsApi metrics() { + return Sentry.getCurrentScopes().metrics(); + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) { Sentry.addFeatureFlag(flag, result); diff --git a/sentry/src/main/java/io/sentry/HubScopesWrapper.java b/sentry/src/main/java/io/sentry/HubScopesWrapper.java index d15ed72ee4..c04aad9ed8 100644 --- a/sentry/src/main/java/io/sentry/HubScopesWrapper.java +++ b/sentry/src/main/java/io/sentry/HubScopesWrapper.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.logger.ILoggerApi; +import io.sentry.metrics.IMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -374,6 +375,11 @@ public void reportFullyDisplayed() { return scopes.logger(); } + @Override + public @NotNull IMetricsApi metrics() { + return scopes.metrics(); + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) { scopes.addFeatureFlag(flag, result); diff --git a/sentry/src/main/java/io/sentry/IScopes.java b/sentry/src/main/java/io/sentry/IScopes.java index bf78d28ecd..0a7c86fa8e 100644 --- a/sentry/src/main/java/io/sentry/IScopes.java +++ b/sentry/src/main/java/io/sentry/IScopes.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.logger.ILoggerApi; +import io.sentry.metrics.IMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -744,5 +745,8 @@ default boolean isNoOp() { @NotNull ILoggerApi logger(); + @NotNull + IMetricsApi metrics(); + void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result); } diff --git a/sentry/src/main/java/io/sentry/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java index 811e1d297a..2885d8017d 100644 --- a/sentry/src/main/java/io/sentry/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -2,6 +2,8 @@ import io.sentry.logger.ILoggerApi; import io.sentry.logger.NoOpLoggerApi; +import io.sentry.metrics.IMetricsApi; +import io.sentry.metrics.NoOpMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -331,6 +333,11 @@ public boolean isNoOp() { return NoOpLoggerApi.getInstance(); } + @Override + public @NotNull IMetricsApi metrics() { + return NoOpMetricsApi.getInstance(); + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) {} } diff --git a/sentry/src/main/java/io/sentry/NoOpScopes.java b/sentry/src/main/java/io/sentry/NoOpScopes.java index 40777da892..5abb20226a 100644 --- a/sentry/src/main/java/io/sentry/NoOpScopes.java +++ b/sentry/src/main/java/io/sentry/NoOpScopes.java @@ -2,6 +2,8 @@ import io.sentry.logger.ILoggerApi; import io.sentry.logger.NoOpLoggerApi; +import io.sentry.metrics.IMetricsApi; +import io.sentry.metrics.NoOpMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -329,6 +331,11 @@ public boolean isNoOp() { return NoOpLoggerApi.getInstance(); } + @Override + public @NotNull IMetricsApi metrics() { + return NoOpMetricsApi.getInstance(); + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) {} } diff --git a/sentry/src/main/java/io/sentry/Scopes.java b/sentry/src/main/java/io/sentry/Scopes.java index c8afde59cc..374ecbfdb5 100644 --- a/sentry/src/main/java/io/sentry/Scopes.java +++ b/sentry/src/main/java/io/sentry/Scopes.java @@ -5,6 +5,8 @@ import io.sentry.hints.SessionStartHint; import io.sentry.logger.ILoggerApi; import io.sentry.logger.LoggerApi; +import io.sentry.metrics.IMetricsApi; +import io.sentry.metrics.MetricsApi; import io.sentry.protocol.*; import io.sentry.transport.RateLimiter; import io.sentry.util.HintUtils; @@ -31,6 +33,7 @@ public final class Scopes implements IScopes { private final @NotNull CombinedScopeView combinedScope; private final @NotNull ILoggerApi logger; + private final @NotNull IMetricsApi metrics; public Scopes( final @NotNull IScope scope, @@ -57,6 +60,7 @@ private Scopes( validateOptions(options); this.compositePerformanceCollector = options.getCompositePerformanceCollector(); this.logger = new LoggerApi(this); + this.metrics = new MetricsApi(this); } public @NotNull String getCreator() { @@ -1220,6 +1224,11 @@ public void reportFullyDisplayed() { return logger; } + @Override + public @NotNull IMetricsApi metrics() { + return metrics; + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) { combinedScope.addFeatureFlag(flag, result); diff --git a/sentry/src/main/java/io/sentry/ScopesAdapter.java b/sentry/src/main/java/io/sentry/ScopesAdapter.java index 99e70694ee..ba7e74d23b 100644 --- a/sentry/src/main/java/io/sentry/ScopesAdapter.java +++ b/sentry/src/main/java/io/sentry/ScopesAdapter.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.logger.ILoggerApi; +import io.sentry.metrics.IMetricsApi; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -386,6 +387,11 @@ public void reportFullyDisplayed() { return Sentry.getCurrentScopes().logger(); } + @Override + public @NotNull IMetricsApi metrics() { + return Sentry.getCurrentScopes().metrics(); + } + @Override public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) { Sentry.addFeatureFlag(flag, result); diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index f726c1a602..178f97a3b3 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -14,6 +14,7 @@ import io.sentry.internal.modules.NoOpModulesLoader; import io.sentry.internal.modules.ResourcesModulesLoader; import io.sentry.logger.ILoggerApi; +import io.sentry.metrics.IMetricsApi; import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Feedback; import io.sentry.protocol.SentryId; @@ -1344,6 +1345,11 @@ public static IDistributionApi distribution() { return getCurrentScopes().getScope().getOptions().getDistributionController(); } + @NotNull + public static IMetricsApi metrics() { + return getCurrentScopes().metrics(); + } + public static void showUserFeedbackDialog() { showUserFeedbackDialog(null); } diff --git a/sentry/src/main/java/io/sentry/metrics/IMetricsApi.java b/sentry/src/main/java/io/sentry/metrics/IMetricsApi.java new file mode 100644 index 0000000000..ddd6bb9d41 --- /dev/null +++ b/sentry/src/main/java/io/sentry/metrics/IMetricsApi.java @@ -0,0 +1,11 @@ +package io.sentry.metrics; + +import org.jetbrains.annotations.NotNull; + +public interface IMetricsApi { + + void count(@NotNull final String name); + // distribution + // gauge + // +} diff --git a/sentry/src/main/java/io/sentry/metrics/MetricsApi.java b/sentry/src/main/java/io/sentry/metrics/MetricsApi.java new file mode 100644 index 0000000000..7b878de3d2 --- /dev/null +++ b/sentry/src/main/java/io/sentry/metrics/MetricsApi.java @@ -0,0 +1,18 @@ +package io.sentry.metrics; + +import io.sentry.Scopes; +import org.jetbrains.annotations.NotNull; + +public final class MetricsApi implements IMetricsApi { + + private final @NotNull Scopes scopes; + + public MetricsApi(final @NotNull Scopes scopes) { + this.scopes = scopes; + } + + @Override + public void count(@NotNull String name) { + scopes.getOptions(); + } +} diff --git a/sentry/src/main/java/io/sentry/metrics/NoOpMetricsApi.java b/sentry/src/main/java/io/sentry/metrics/NoOpMetricsApi.java new file mode 100644 index 0000000000..f6977b6953 --- /dev/null +++ b/sentry/src/main/java/io/sentry/metrics/NoOpMetricsApi.java @@ -0,0 +1,16 @@ +package io.sentry.metrics; + +import org.jetbrains.annotations.NotNull; + +public final class NoOpMetricsApi implements IMetricsApi { + private static final NoOpMetricsApi instance = new NoOpMetricsApi(); + + private NoOpMetricsApi() {} + + public static NoOpMetricsApi getInstance() { + return instance; + } + + @Override + public void count(@NotNull String name) {} +} From d3c74520c4d0be20bd07b6b256c142495afc911a Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 17 Dec 2025 16:10:40 +0100 Subject: [PATCH 3/3] Enable metrics by default --- sentry/src/main/java/io/sentry/SentryOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 2575328c70..6fa246c15c 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -3742,7 +3742,7 @@ public interface BeforeSendLogCallback { public static final class Metrics { /** Whether Sentry Metrics feature is enabled and metrics are sent to Sentry. */ - private boolean enable = false; + private boolean enable = true; /** * This function is called with a metric key and tags and can return false to skip sending the