From 20f0c8c35010b2744479a3375eb9b0593746646a Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 11 Jul 2024 09:30:24 +0200 Subject: [PATCH] capture otel events --- .../OtelSentrySpanProcessor.java | 28 +++++++++++++++++++ sentry/api/sentry.api | 4 +++ .../main/java/io/sentry/ExternalOptions.java | 14 ++++++++++ .../main/java/io/sentry/SentryOptions.java | 15 ++++++++++ 4 files changed, 61 insertions(+) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java index 7439906868..b4e1ef60d2 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java @@ -8,6 +8,8 @@ import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData; import io.sentry.Baggage; import io.sentry.IScopes; import io.sentry.PropagationContext; @@ -19,7 +21,10 @@ import io.sentry.SentryTraceHeader; import io.sentry.SpanId; import io.sentry.TracesSamplingDecision; +import io.sentry.exception.ExceptionMechanismException; +import io.sentry.protocol.Mechanism; import io.sentry.protocol.SentryId; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -135,9 +140,32 @@ public void onEnd(final @NotNull ReadableSpan spanBeingEnded) { final @NotNull SentryDate finishDate = new SentryLongDate(spanBeingEnded.toSpanData().getEndEpochNanos()); sentrySpan.updateEndDate(finishDate); + + final @NotNull IScopes spanScopes = sentrySpan.getScopes(); + if (spanScopes.getOptions().isCaptureOpenTelemetryEvents()) { + final @NotNull List events = spanBeingEnded.toSpanData().getEvents(); + for (EventData event : events) { + if (event instanceof ExceptionEventData) { + final @NotNull ExceptionEventData exceptionEvent = (ExceptionEventData) event; + final @NotNull Throwable exception = exceptionEvent.getException(); + captureException(spanScopes, exception); + } + } + } } } + private void captureException(final @NotNull IScopes scopes, final @NotNull Throwable throwable) { + final Mechanism mechanism = new Mechanism(); + mechanism.setType("OpenTelemetryInstrumentation"); + mechanism.setHandled(true); + // TODO [POTEL] thread might be wrong + final Throwable mechanismException = + new ExceptionMechanismException(mechanism, throwable, Thread.currentThread()); + // TODO [POTEL] event timestamp should be taken from ExceptionEventData + scopes.captureException(mechanismException); + } + @Override public boolean isEndRequired() { return true; diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 05213c6b91..f9c997790e 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -456,11 +456,13 @@ public final class io/sentry/ExternalOptions { public fun getTracePropagationTargets ()Ljava/util/List; public fun getTracesSampleRate ()Ljava/lang/Double; public fun getTracingOrigins ()Ljava/util/List; + public fun isCaptureOpenTelemetryEvents ()Ljava/lang/Boolean; public fun isEnableBackpressureHandling ()Ljava/lang/Boolean; public fun isEnablePrettySerializationOutput ()Ljava/lang/Boolean; public fun isEnabled ()Ljava/lang/Boolean; public fun isSendDefaultPii ()Ljava/lang/Boolean; public fun isSendModules ()Ljava/lang/Boolean; + public fun setCaptureOpenTelemetryEvents (Ljava/lang/Boolean;)V public fun setCron (Lio/sentry/SentryOptions$Cron;)V public fun setDebug (Ljava/lang/Boolean;)V public fun setDist (Ljava/lang/String;)V @@ -2757,6 +2759,7 @@ public class io/sentry/SentryOptions { public fun isAttachServerName ()Z public fun isAttachStacktrace ()Z public fun isAttachThreads ()Z + public fun isCaptureOpenTelemetryEvents ()Z public fun isDebug ()Z public fun isEnableAppStartProfiling ()Z public fun isEnableAutoSessionTracking ()Z @@ -2794,6 +2797,7 @@ public class io/sentry/SentryOptions { public fun setBeforeSend (Lio/sentry/SentryOptions$BeforeSendCallback;)V public fun setBeforeSendTransaction (Lio/sentry/SentryOptions$BeforeSendTransactionCallback;)V public fun setCacheDirPath (Ljava/lang/String;)V + public fun setCaptureOpenTelemetryEvents (Z)V public fun setConnectionStatusProvider (Lio/sentry/IConnectionStatusProvider;)V public fun setConnectionTimeoutMillis (I)V public fun setCron (Lio/sentry/SentryOptions$Cron;)V diff --git a/sentry/src/main/java/io/sentry/ExternalOptions.java b/sentry/src/main/java/io/sentry/ExternalOptions.java index aa5aa43937..6e812f2c7f 100644 --- a/sentry/src/main/java/io/sentry/ExternalOptions.java +++ b/sentry/src/main/java/io/sentry/ExternalOptions.java @@ -51,6 +51,7 @@ public final class ExternalOptions { private @Nullable Boolean sendModules; private @Nullable Boolean sendDefaultPii; private @Nullable Boolean enableBackpressureHandling; + private @Nullable Boolean captureOpenTelemetryEvents; private @Nullable SentryOptions.Cron cron; @@ -139,6 +140,9 @@ public final class ExternalOptions { options.setEnableBackpressureHandling( propertiesProvider.getBooleanProperty("enable-backpressure-handling")); + options.setCaptureOpenTelemetryEvents( + propertiesProvider.getBooleanProperty("capture-opentelemetry-events")); + for (final String ignoredExceptionType : propertiesProvider.getList("ignored-exceptions-for-type")) { try { @@ -460,4 +464,14 @@ public void setEnableBackpressureHandling(final @Nullable Boolean enableBackpres public void setCron(final @Nullable SentryOptions.Cron cron) { this.cron = cron; } + + @ApiStatus.Experimental + public void setCaptureOpenTelemetryEvents(final @Nullable Boolean captureOpenTelemetryEvents) { + this.captureOpenTelemetryEvents = captureOpenTelemetryEvents; + } + + @ApiStatus.Experimental + public @Nullable Boolean isCaptureOpenTelemetryEvents() { + return captureOpenTelemetryEvents; + } } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 7e24e81dce..e743d037f3 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -489,6 +489,8 @@ public class SentryOptions { private @NotNull ScopeType defaultScopeType = ScopeType.ISOLATION; + @ApiStatus.Experimental private boolean captureOpenTelemetryEvents = false; + /** * Adds an event processor * @@ -2440,6 +2442,16 @@ public void setDefaultScopeType(final @NotNull ScopeType scopeType) { return defaultScopeType; } + @ApiStatus.Experimental + public void setCaptureOpenTelemetryEvents(final boolean captureOpenTelemetryEvents) { + this.captureOpenTelemetryEvents = captureOpenTelemetryEvents; + } + + @ApiStatus.Experimental + public boolean isCaptureOpenTelemetryEvents() { + return captureOpenTelemetryEvents; + } + /** The BeforeSend callback */ public interface BeforeSendCallback { @@ -2694,6 +2706,9 @@ public void merge(final @NotNull ExternalOptions options) { if (options.isSendDefaultPii() != null) { setSendDefaultPii(options.isSendDefaultPii()); } + if (options.isCaptureOpenTelemetryEvents() != null) { + setCaptureOpenTelemetryEvents(options.isCaptureOpenTelemetryEvents()); + } if (options.getCron() != null) { if (getCron() == null) {