Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import io.sentry.SentryEnvelope
import io.sentry.SentryEvent
import io.sentry.SentryLogEvent
import io.sentry.SentryLogEvents
import io.sentry.SentryMetricsEvent
import io.sentry.SentryMetricsEvents
import io.sentry.SentryReplayEvent
import io.sentry.Session
Expand Down Expand Up @@ -193,6 +194,10 @@ class SessionTrackingIntegrationTest {
TODO("Not yet implemented")
}

override fun captureMetric(event: SentryMetricsEvent, scope: IScope?) {
TODO("Not yet implemented")
}

override fun captureBatchedMetricsEvents(metricsEvents: SentryMetricsEvents) {
TODO("Not yet implemented")
}
Expand Down
7 changes: 6 additions & 1 deletion sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ public abstract interface class io/sentry/EventProcessor {
public fun getOrder ()Ljava/lang/Long;
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
public fun process (Lio/sentry/SentryLogEvent;)Lio/sentry/SentryLogEvent;
public fun process (Lio/sentry/SentryMetricsEvent;)Lio/sentry/SentryMetricsEvent;
public fun process (Lio/sentry/SentryReplayEvent;Lio/sentry/Hint;)Lio/sentry/SentryReplayEvent;
public fun process (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Hint;)Lio/sentry/protocol/SentryTransaction;
}
Expand Down Expand Up @@ -1045,6 +1046,7 @@ public abstract interface class io/sentry/ISentryClient {
public abstract fun captureLog (Lio/sentry/SentryLogEvent;Lio/sentry/IScope;)V
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/IScope;)Lio/sentry/protocol/SentryId;
public abstract fun captureMetric (Lio/sentry/SentryMetricsEvent;Lio/sentry/IScope;)V
public abstract fun captureProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/IScope;)Lio/sentry/protocol/SentryId;
public abstract fun captureReplayEvent (Lio/sentry/SentryReplayEvent;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureSession (Lio/sentry/Session;)V
Expand Down Expand Up @@ -2859,6 +2861,7 @@ public final class io/sentry/SentryClient : io/sentry/ISentryClient {
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureFeedback (Lio/sentry/protocol/Feedback;Lio/sentry/Hint;Lio/sentry/IScope;)Lio/sentry/protocol/SentryId;
public fun captureLog (Lio/sentry/SentryLogEvent;Lio/sentry/IScope;)V
public fun captureMetric (Lio/sentry/SentryMetricsEvent;Lio/sentry/IScope;)V
public fun captureProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/IScope;)Lio/sentry/protocol/SentryId;
public fun captureReplayEvent (Lio/sentry/SentryReplayEvent;Lio/sentry/IScope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureSession (Lio/sentry/Session;Lio/sentry/Hint;)V
Expand Down Expand Up @@ -3755,13 +3758,15 @@ public abstract interface class io/sentry/SentryOptions$Logs$BeforeSendLogCallba
public final class io/sentry/SentryOptions$Metrics {
public fun <init> ()V
public fun getBeforeSend ()Lio/sentry/SentryOptions$Metrics$BeforeSendMetricCallback;
public fun getMetricsBatchProcessorFactory ()Lio/sentry/metrics/IMetricsBatchProcessorFactory;
public fun isEnabled ()Z
public fun setBeforeSend (Lio/sentry/SentryOptions$Metrics$BeforeSendMetricCallback;)V
public fun setEnabled (Z)V
public fun setMetricsBatchProcessorFactory (Lio/sentry/metrics/IMetricsBatchProcessorFactory;)V
}

public abstract interface class io/sentry/SentryOptions$Metrics$BeforeSendMetricCallback {
public abstract fun execute (Lio/sentry/SentryMetricsEvents;)Lio/sentry/SentryMetricsEvents;
public abstract fun execute (Lio/sentry/SentryMetricsEvent;)Lio/sentry/SentryMetricsEvent;
}

public abstract interface class io/sentry/SentryOptions$OnDiscardCallback {
Expand Down
11 changes: 11 additions & 0 deletions sentry/src/main/java/io/sentry/EventProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ default SentryLogEvent process(@NotNull SentryLogEvent event) {
return event;
}

/**
* May mutate or drop a SentryMetricsEvent
*
* @param event the SentryMetricsEvent
* @return the event itself, a mutated SentryMetricsEvent or null
*/
@Nullable
default SentryMetricsEvent process(@NotNull SentryMetricsEvent event) {
return event;
}

/**
* Controls when this EventProcessor is invoked.
*
Expand Down
2 changes: 2 additions & 0 deletions sentry/src/main/java/io/sentry/ISentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ SentryId captureProfileChunk(

void captureLog(@NotNull SentryLogEvent logEvent, @Nullable IScope scope);

void captureMetric(@NotNull SentryMetricsEvent logEvent, @Nullable IScope scope);

@ApiStatus.Internal
void captureBatchedLogEvents(@NotNull SentryLogEvents logEvents);

Expand Down
5 changes: 5 additions & 0 deletions sentry/src/main/java/io/sentry/NoOpSentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public void captureLog(@NotNull SentryLogEvent logEvent, @Nullable IScope scope)
// do nothing
}

@Override
public void captureMetric(@NotNull SentryMetricsEvent metricsEvent, @Nullable IScope scope) {
// do nothing
}

@ApiStatus.Internal
@Override
public void captureBatchedLogEvents(@NotNull SentryLogEvents logEvents) {
Expand Down
96 changes: 96 additions & 0 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import io.sentry.hints.TransactionEnd;
import io.sentry.logger.ILoggerBatchProcessor;
import io.sentry.logger.NoOpLoggerBatchProcessor;
import io.sentry.metrics.IMetricsBatchProcessor;
import io.sentry.metrics.NoOpMetricsBatchProcessor;
import io.sentry.protocol.Contexts;
import io.sentry.protocol.DebugMeta;
import io.sentry.protocol.FeatureFlags;
Expand Down Expand Up @@ -42,6 +44,7 @@ public final class SentryClient implements ISentryClient {
private final @NotNull ITransport transport;
private final @NotNull SortBreadcrumbsByDate sortBreadcrumbsByDate = new SortBreadcrumbsByDate();
private final @NotNull ILoggerBatchProcessor loggerBatchProcessor;
private final @NotNull IMetricsBatchProcessor metricsBatchProcessor;

@Override
public boolean isEnabled() {
Expand All @@ -66,6 +69,12 @@ public SentryClient(final @NotNull SentryOptions options) {
} else {
loggerBatchProcessor = NoOpLoggerBatchProcessor.getInstance();
}
if (options.getMetrics().isEnabled()) {
metricsBatchProcessor =
options.getMetrics().getMetricsBatchProcessorFactory().create(options, this);
} else {
metricsBatchProcessor = NoOpMetricsBatchProcessor.getInstance();
}
}

private boolean shouldApplyScopeData(
Expand Down Expand Up @@ -506,6 +515,38 @@ private SentryLogEvent processLogEvent(
return event;
}

@Nullable
private SentryMetricsEvent processMetricsEvent(
@NotNull SentryMetricsEvent event, final @NotNull List<EventProcessor> eventProcessors) {
for (final EventProcessor processor : eventProcessors) {
try {
event = processor.process(event);
} catch (Throwable e) {
options
.getLogger()
.log(
SentryLevel.ERROR,
e,
"An exception occurred while processing metrics event by processor: %s",
processor.getClass().getName());
}

if (event == null) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"Metrics event was dropped by a processor: %s",
processor.getClass().getName());
options
.getClientReportRecorder()
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.TraceMetric);
break;
}
}
return event;
}

private @Nullable SentryTransaction processTransaction(
@NotNull SentryTransaction transaction,
final @NotNull Hint hint,
Expand Down Expand Up @@ -1235,6 +1276,40 @@ public void captureBatchedLogEvents(final @NotNull SentryLogEvents logEvents) {
}
}

@ApiStatus.Experimental
@Override
public void captureMetric(@Nullable SentryMetricsEvent metricsEvent, @Nullable IScope scope) {
if (metricsEvent != null && scope != null) {
metricsEvent = processMetricsEvent(metricsEvent, scope.getEventProcessors());
if (metricsEvent == null) {
return;
}
}

if (metricsEvent != null) {
metricsEvent = processMetricsEvent(metricsEvent, options.getEventProcessors());
if (metricsEvent == null) {
return;
}
}

if (metricsEvent != null) {
metricsEvent = executeBeforeSendMetric(metricsEvent);

if (metricsEvent == null) {
options
.getLogger()
.log(SentryLevel.DEBUG, "Metrics Event was dropped by beforeSendMetrics");
options
.getClientReportRecorder()
.recordLostEvent(DiscardReason.BEFORE_SEND, DataCategory.TraceMetric);
return;
}

metricsBatchProcessor.add(metricsEvent);
}
}

@ApiStatus.Internal
@Override
public void captureBatchedMetricsEvents(final @NotNull SentryMetricsEvents metricsEvents) {
Expand Down Expand Up @@ -1550,6 +1625,27 @@ private void sortBreadcrumbsByDate(
return event;
}

private @Nullable SentryMetricsEvent executeBeforeSendMetric(@NotNull SentryMetricsEvent event) {
final SentryOptions.Metrics.BeforeSendMetricCallback beforeSendMetric =
options.getMetrics().getBeforeSend();
if (beforeSendMetric != null) {
try {
event = beforeSendMetric.execute(event);
} catch (Throwable e) {
options
.getLogger()
.log(
SentryLevel.ERROR,
"The BeforeSendMetric callback threw an exception. Dropping metrics event.",
e);

// drop event in case of an error in beforeSendMetric due to PII concerns
event = null;
}
}
return event;
}

@Override
public void close() {
close(false);
Expand Down
18 changes: 17 additions & 1 deletion sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import io.sentry.internal.viewhierarchy.ViewHierarchyExporter;
import io.sentry.logger.DefaultLoggerBatchProcessorFactory;
import io.sentry.logger.ILoggerBatchProcessorFactory;
import io.sentry.metrics.DefaultMetricsBatchProcessorFactory;
import io.sentry.metrics.IMetricsBatchProcessorFactory;
import io.sentry.protocol.SdkVersion;
import io.sentry.protocol.SentryTransaction;
import io.sentry.transport.ITransport;
Expand Down Expand Up @@ -3750,6 +3752,9 @@ public static final class Metrics {
*/
private @Nullable BeforeSendMetricCallback beforeSend;

private @NotNull IMetricsBatchProcessorFactory metricsBatchProcessorFactory =
new DefaultMetricsBatchProcessorFactory();

/**
* Whether Sentry Metrics feature is enabled and metrics are sent to Sentry.
*
Expand Down Expand Up @@ -3786,6 +3791,17 @@ public void setBeforeSend(@Nullable BeforeSendMetricCallback beforeSend) {
this.beforeSend = beforeSend;
}

@ApiStatus.Internal
public @NotNull IMetricsBatchProcessorFactory getMetricsBatchProcessorFactory() {
return metricsBatchProcessorFactory;
}

@ApiStatus.Internal
public void setMetricsBatchProcessorFactory(
final @NotNull IMetricsBatchProcessorFactory metricsBatchProcessorFactory) {
this.metricsBatchProcessorFactory = metricsBatchProcessorFactory;
}

public interface BeforeSendMetricCallback {

/**
Expand All @@ -3795,7 +3811,7 @@ public interface BeforeSendMetricCallback {
* @return the original metric, mutated metric or null if metric was dropped
*/
@Nullable
SentryMetricsEvents execute(@NotNull SentryMetricsEvents metric);
SentryMetricsEvent execute(@NotNull SentryMetricsEvent metric);
}
}

Expand Down
Loading