diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api index 72f8400fed..f4b4c273f1 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api +++ b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api @@ -4,6 +4,11 @@ public final class io/sentry/opentelemetry/OpenTelemetryLinkErrorEventProcessor public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent; } +public final class io/sentry/opentelemetry/OtelInternalSpanDetectionUtil { + public fun ()V + public static fun isSentryRequest (Lio/sentry/IScopes;Lio/opentelemetry/api/trace/SpanKind;Lio/opentelemetry/api/common/Attributes;)Z +} + public final class io/sentry/opentelemetry/OtelSamplingUtil { public fun ()V public static fun extractSamplingDecision (Lio/opentelemetry/api/common/Attributes;)Lio/sentry/TracesSamplingDecision; diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelInternalSpanDetectionUtil.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelInternalSpanDetectionUtil.java new file mode 100644 index 0000000000..7009ed144c --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelInternalSpanDetectionUtil.java @@ -0,0 +1,66 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.semconv.SemanticAttributes; +import io.sentry.DsnUtil; +import io.sentry.IScopes; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class OtelInternalSpanDetectionUtil { + + private static final @NotNull List spanKindsConsideredForSentryRequests = + Arrays.asList(SpanKind.CLIENT, SpanKind.INTERNAL); + + @SuppressWarnings("deprecation") + public static boolean isSentryRequest( + final @NotNull IScopes scopes, + final @NotNull SpanKind spanKind, + final @NotNull Attributes attributes) { + if (!spanKindsConsideredForSentryRequests.contains(spanKind)) { + return false; + } + + final @Nullable String httpUrl = attributes.get(SemanticAttributes.HTTP_URL); + if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), httpUrl)) { + return true; + } + + final @Nullable String fullUrl = attributes.get(SemanticAttributes.URL_FULL); + if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), fullUrl)) { + return true; + } + + // TODO [POTEL] should check if enabled but multi init with different options makes testing hard + // atm + // if (scopes.getOptions().isEnableSpotlight()) { + final @Nullable String optionsSpotlightUrl = scopes.getOptions().getSpotlightConnectionUrl(); + final @NotNull String spotlightUrl = + optionsSpotlightUrl != null ? optionsSpotlightUrl : "http://localhost:8969/stream"; + + if (containsSpotlightUrl(fullUrl, spotlightUrl)) { + return true; + } + if (containsSpotlightUrl(httpUrl, spotlightUrl)) { + return true; + } + // } + + return false; + } + + private static boolean containsSpotlightUrl( + final @Nullable String requestUrl, final @NotNull String spotlightUrl) { + if (requestUrl == null) { + return false; + } + + return requestUrl.toLowerCase(Locale.ROOT).contains(spotlightUrl.toLowerCase(Locale.ROOT)); + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySampler.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySampler.java index 2ae611044b..37df216ebb 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySampler.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySampler.java @@ -1,5 +1,7 @@ package io.sentry.opentelemetry; +import static io.sentry.opentelemetry.OtelInternalSpanDetectionUtil.isSentryRequest; + import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; @@ -13,7 +15,6 @@ import io.sentry.PropagationContext; import io.sentry.SamplingContext; import io.sentry.ScopesAdapter; -import io.sentry.SentryOptions; import io.sentry.SentryTraceHeader; import io.sentry.SpanId; import io.sentry.TracesSamplingDecision; @@ -26,10 +27,10 @@ public final class SentrySampler implements Sampler { private final @NotNull SentryWeakSpanStorage spanStorage = SentryWeakSpanStorage.getInstance(); - private final @NotNull SentryOptions options; + private final @NotNull IScopes scopes; public SentrySampler(final @NotNull IScopes scopes) { - this.options = scopes.getOptions(); + this.scopes = scopes; } public SentrySampler() { @@ -44,7 +45,9 @@ public SamplingResult shouldSample( final @NotNull SpanKind spanKind, final @NotNull Attributes attributes, final @NotNull List parentLinks) { - // TODO [POTEL] use SamplingDecision.DROP sentry internal spans + if (isSentryRequest(scopes, spanKind, attributes)) { + return SamplingResult.drop(); + } // note: parentLinks seems to usually be empty final @Nullable Span parentOtelSpan = Span.fromContextOrNull(parentContext); final @Nullable OtelSpanWrapper parentSentrySpan = @@ -65,7 +68,7 @@ public SamplingResult shouldSample( private @NotNull SamplingResult handleRootOtelSpan( final @NotNull String traceId, final @NotNull Context parentContext) { - if (!options.isTraceSampling()) { + if (!scopes.getOptions().isTraceSampling()) { // TODO [POTEL] should this return RECORD_ONLY to allow tracing without performance return SamplingResult.create(SamplingDecision.DROP); } @@ -87,7 +90,10 @@ public SamplingResult shouldSample( final @NotNull TransactionContext transactionContext = TransactionContext.fromPropagationContext(propagationContext); final @NotNull TracesSamplingDecision sentryDecision = - options.getInternalTracesSampler().sample(new SamplingContext(transactionContext, null)); + scopes + .getOptions() + .getInternalTracesSampler() + .sample(new SamplingContext(transactionContext, null)); return new SentrySamplingResult(sentryDecision); } diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java index ec7ae4918b..2d82bd23b7 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java @@ -2,9 +2,9 @@ import static io.sentry.TransactionContext.DEFAULT_TRANSACTION_NAME; import static io.sentry.opentelemetry.InternalSemanticAttributes.IS_REMOTE_PARENT; +import static io.sentry.opentelemetry.OtelInternalSpanDetectionUtil.isSentryRequest; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.data.SpanData; @@ -14,7 +14,6 @@ import io.sentry.Baggage; import io.sentry.DateUtils; import io.sentry.DefaultSpanFactory; -import io.sentry.DsnUtil; import io.sentry.IScopes; import io.sentry.ISpan; import io.sentry.ITransaction; @@ -37,7 +36,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; @@ -54,9 +52,6 @@ public final class SentrySpanExporter implements SpanExporter { new SpanDescriptionExtractor(); private final @NotNull IScopes scopes; - private final @NotNull List spanKindsConsideredForSentryRequests = - Arrays.asList(SpanKind.CLIENT, SpanKind.INTERNAL); - private final @NotNull List attributeKeysToRemove = Arrays.asList( InternalSemanticAttributes.IS_REMOTE_PARENT.getKey(), @@ -134,51 +129,9 @@ private boolean isSpanTooOld(final @NotNull SpanData span, final @NotNull Sentry } private @NotNull List filterOutSentrySpans(final @NotNull Collection spans) { - return spans.stream().filter((span) -> !isSentryRequest(span)).collect(Collectors.toList()); - } - - @SuppressWarnings("deprecation") - private boolean isSentryRequest(final @NotNull SpanData spanData) { - final @NotNull SpanKind kind = spanData.getKind(); - if (!spanKindsConsideredForSentryRequests.contains(kind)) { - return false; - } - - final @Nullable String httpUrl = spanData.getAttributes().get(SemanticAttributes.HTTP_URL); - if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), httpUrl)) { - return true; - } - - final @Nullable String fullUrl = spanData.getAttributes().get(SemanticAttributes.URL_FULL); - if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), fullUrl)) { - return true; - } - - // TODO [POTEL] should check if enabled but multi init with different options makes testing hard - // atm - // if (scopes.getOptions().isEnableSpotlight()) { - final @Nullable String optionsSpotlightUrl = scopes.getOptions().getSpotlightConnectionUrl(); - final @NotNull String spotlightUrl = - optionsSpotlightUrl != null ? optionsSpotlightUrl : "http://localhost:8969/stream"; - - if (containsSpotlightUrl(fullUrl, spotlightUrl)) { - return true; - } - if (containsSpotlightUrl(httpUrl, spotlightUrl)) { - return true; - } - // } - - return false; - } - - private boolean containsSpotlightUrl( - final @Nullable String requestUrl, final @NotNull String spotlightUrl) { - if (requestUrl == null) { - return false; - } - - return requestUrl.toLowerCase(Locale.ROOT).contains(spotlightUrl.toLowerCase(Locale.ROOT)); + return spans.stream() + .filter((span) -> !isSentryRequest(scopes, span.getKind(), span.getAttributes())) + .collect(Collectors.toList()); } private List maybeSend(final @NotNull List spans) {