Skip to content
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
### Fixes

- `SentryOptions.setTracePropagationTargets` is no longer marked internal ([#4170](https://github.com/getsentry/sentry-java/pull/4170))
- Check `tracePropagationTargets` in OpenTelemetry propagator ([#4191](https://github.com/getsentry/sentry-java/pull/4191))
- If a URL can be retrieved from OpenTelemetry span attributes, we check it against `tracePropagationTargets` before attaching `sentry-trace` and `baggage` headers to outgoing requests
- If no URL can be retrieved we always attach the headers
- Fix `ignoredErrors`, `ignoredTransactions` and `ignoredCheckIns` being unset by external options like `sentry.properties` or ENV vars ([#4207](https://github.com/getsentry/sentry-java/pull/4207))
- Whenever parsing of external options was enabled (`enableExternalConfiguration`), which is the default for many integrations, the values set on `SentryOptions` passed to `Sentry.init` would be lost
- Even if the value was not set in any external configuration it would still be set to an empty list
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
public abstract interface class io/sentry/opentelemetry/IOtelSpanWrapper : io/sentry/ISpan {
public abstract fun getData ()Ljava/util/Map;
public abstract fun getMeasurements ()Ljava/util/Map;
public abstract fun getOpenTelemetrySpanAttributes ()Lio/opentelemetry/api/common/Attributes;
public abstract fun getScopes ()Lio/sentry/IScopes;
public abstract fun getTags ()Ljava/util/Map;
public abstract fun getTraceId ()Lio/sentry/protocol/SentryId;
Expand Down Expand Up @@ -51,6 +52,7 @@ public final class io/sentry/opentelemetry/OtelStrongRefSpanWrapper : io/sentry/
public fun getDescription ()Ljava/lang/String;
public fun getFinishDate ()Lio/sentry/SentryDate;
public fun getMeasurements ()Ljava/util/Map;
public fun getOpenTelemetrySpanAttributes ()Lio/opentelemetry/api/common/Attributes;
public fun getOperation ()Ljava/lang/String;
public fun getSamplingDecision ()Lio/sentry/TracesSamplingDecision;
public fun getScopes ()Lio/sentry/IScopes;
Expand Down Expand Up @@ -177,6 +179,7 @@ public final class io/sentry/opentelemetry/SentryOtelThreadLocalStorage : io/ope
}

public final class io/sentry/opentelemetry/SentryWeakSpanStorage {
public fun clear ()V
public static fun getInstance ()Lio/sentry/opentelemetry/SentryWeakSpanStorage;
public fun getSentrySpan (Lio/opentelemetry/api/trace/SpanContext;)Lio/sentry/opentelemetry/IOtelSpanWrapper;
public fun storeSentrySpan (Lio/opentelemetry/api/trace/SpanContext;Lio/sentry/opentelemetry/IOtelSpanWrapper;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.opentelemetry;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import io.sentry.IScopes;
import io.sentry.ISpan;
Expand Down Expand Up @@ -47,4 +48,8 @@ public interface IOtelSpanWrapper extends ISpan {

@NotNull
Context storeInContext(Context context);

@ApiStatus.Internal
@Nullable
Attributes getOpenTelemetrySpanAttributes();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.opentelemetry;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.sentry.BaggageHeader;
Expand Down Expand Up @@ -303,4 +304,10 @@ public void setContext(@NotNull String key, @NotNull Object context) {
public @NotNull ISentryLifecycleToken makeCurrent() {
return delegate.makeCurrent();
}

@ApiStatus.Internal
@Override
public @Nullable Attributes getOpenTelemetrySpanAttributes() {
return delegate.getOpenTelemetrySpanAttributes();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

/**
* Weakly references wrappers for OpenTelemetry spans meaning they'll be cleaned up when the
Expand Down Expand Up @@ -44,4 +45,9 @@ public void storeSentrySpan(
final @NotNull SpanContext otelSpan, final @NotNull IOtelSpanWrapper sentrySpan) {
this.sentrySpans.put(otelSpan, sentrySpan);
}

@TestOnly
public void clear() {
sentrySpans.clear();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
public final class io/sentry/opentelemetry/OpenTelemetryAttributesExtractor {
public fun <init> ()V
public fun extract (Lio/opentelemetry/sdk/trace/data/SpanData;Lio/sentry/ISpan;Lio/sentry/IScope;)V
public fun extractUrl (Lio/opentelemetry/api/common/Attributes;)Ljava/lang/String;
}

public final class io/sentry/opentelemetry/OpenTelemetryLinkErrorEventProcessor : io/sentry/EventProcessor {
Expand Down Expand Up @@ -60,6 +61,7 @@ public final class io/sentry/opentelemetry/OtelSpanWrapper : io/sentry/opentelem
public fun getDescription ()Ljava/lang/String;
public fun getFinishDate ()Lio/sentry/SentryDate;
public fun getMeasurements ()Ljava/util/Map;
public fun getOpenTelemetrySpanAttributes ()Lio/opentelemetry/api/common/Attributes;
public fun getOperation ()Ljava/lang/String;
public fun getSamplingDecision ()Lio/sentry/TracesSamplingDecision;
public fun getScopes ()Lio/sentry/IScopes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public void extract(
addRequestAttributesToScope(attributes, scope);
}

private void addRequestAttributesToScope(Attributes attributes, IScope scope) {
private void addRequestAttributesToScope(
final @NotNull Attributes attributes, final @NotNull IScope scope) {
if (scope.getRequest() == null) {
scope.setRequest(new Request());
}
Expand All @@ -36,20 +37,13 @@ private void addRequestAttributesToScope(Attributes attributes, IScope scope) {
}

if (request.getUrl() == null) {
final @Nullable String urlFull = attributes.get(UrlAttributes.URL_FULL);
if (urlFull != null) {
final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(urlFull);
final @Nullable String url = extractUrl(attributes);
if (url != null) {
final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(url);
urlDetails.applyToRequest(request);
}
}

if (request.getUrl() == null) {
final String urlString = buildUrlString(attributes);
if (!urlString.isEmpty()) {
request.setUrl(urlString);
}
}

if (request.getQueryString() == null) {
final @Nullable String query = attributes.get(UrlAttributes.URL_QUERY);
if (query != null) {
Expand All @@ -59,6 +53,20 @@ private void addRequestAttributesToScope(Attributes attributes, IScope scope) {
}
}

public @Nullable String extractUrl(final @NotNull Attributes attributes) {
final @Nullable String urlFull = attributes.get(UrlAttributes.URL_FULL);
if (urlFull != null) {
return urlFull;
}

final String urlString = buildUrlString(attributes);
if (!urlString.isEmpty()) {
return urlString;
}

return null;
}

private @NotNull String buildUrlString(final @NotNull Attributes attributes) {
final @Nullable String scheme = attributes.get(UrlAttributes.URL_SCHEME);
final @Nullable String serverAddress = attributes.get(ServerAttributes.SERVER_ADDRESS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.sentry.opentelemetry.SentryOtelKeys.SENTRY_SCOPES_KEY;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
Expand Down Expand Up @@ -32,6 +33,8 @@ public final class OtelSentryPropagator implements TextMapPropagator {
Arrays.asList(SentryTraceHeader.SENTRY_TRACE_HEADER, BaggageHeader.BAGGAGE_HEADER);
private final @NotNull SentryWeakSpanStorage spanStorage = SentryWeakSpanStorage.getInstance();
private final @NotNull IScopes scopes;
private final @NotNull OpenTelemetryAttributesExtractor attributesExtractor =
new OpenTelemetryAttributesExtractor();

public OtelSentryPropagator() {
this(ScopesAdapter.getInstance());
Expand Down Expand Up @@ -73,9 +76,11 @@ public <C> void inject(final Context context, final C carrier, final TextMapSett
return;
}

// TODO can we use traceIfAllowed? do we have the URL here? need to access span attrs
final @Nullable String url = getUrl(sentrySpan);
final @Nullable TracingUtils.TracingHeaders tracingHeaders =
TracingUtils.trace(scopes, Collections.emptyList(), sentrySpan);
url == null
? TracingUtils.trace(scopes, Collections.emptyList(), sentrySpan)
: TracingUtils.traceIfAllowed(scopes, url, Collections.emptyList(), sentrySpan);

if (tracingHeaders != null) {
final @NotNull SentryTraceHeader sentryTraceHeader = tracingHeaders.getSentryTraceHeader();
Expand All @@ -87,6 +92,14 @@ public <C> void inject(final Context context, final C carrier, final TextMapSett
}
}

private @Nullable String getUrl(final @NotNull IOtelSpanWrapper sentrySpan) {
final @Nullable Attributes attributes = sentrySpan.getOpenTelemetrySpanAttributes();
if (attributes == null) {
return null;
}
return attributesExtractor.extractUrl(attributes);
}

@Override
public <C> Context extract(
final Context context, final C carrier, final TextMapGetter<C> getter) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.opentelemetry;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
Expand Down Expand Up @@ -198,6 +199,16 @@ public OtelSpanWrapper(
return span.get();
}

@ApiStatus.Internal
@Override
public @Nullable Attributes getOpenTelemetrySpanAttributes() {
final @Nullable ReadWriteSpan readWriteSpan = span.get();
if (readWriteSpan != null) {
return readWriteSpan.getAttributes();
}
return null;
}

@Override
public @Nullable TraceContext traceContext() {
if (scopes.getOptions().isTraceSampling()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,118 @@ class OpenTelemetryAttributesExtractorTest {
thenUrlIsNotSet()
}

@Test
fun `returns null if no URL in attributes`() {
givenAttributes(mapOf())

val url = whenExtractingUrl()

assertNull(url)
}

@Test
fun `returns full URL if present`() {
givenAttributes(
mapOf(
UrlAttributes.URL_FULL to "https://sentry.io/some/path"
)
)

val url = whenExtractingUrl()

assertEquals("https://sentry.io/some/path", url)
}

@Test
fun `returns reconstructed URL if attributes present`() {
givenAttributes(
mapOf(
UrlAttributes.URL_SCHEME to "https",
ServerAttributes.SERVER_ADDRESS to "sentry.io",
ServerAttributes.SERVER_PORT to 8082L,
UrlAttributes.URL_PATH to "/some/path"
)
)

val url = whenExtractingUrl()

assertEquals("https://sentry.io:8082/some/path", url)
}

@Test
fun `returns reconstructed URL if attributes present without port`() {
givenAttributes(
mapOf(
UrlAttributes.URL_SCHEME to "https",
ServerAttributes.SERVER_ADDRESS to "sentry.io",
UrlAttributes.URL_PATH to "/some/path"
)
)

val url = whenExtractingUrl()

assertEquals("https://sentry.io/some/path", url)
}

@Test
fun `returns null URL if scheme missing`() {
givenAttributes(
mapOf(
ServerAttributes.SERVER_ADDRESS to "sentry.io",
ServerAttributes.SERVER_PORT to 8082L,
UrlAttributes.URL_PATH to "/some/path"
)
)

val url = whenExtractingUrl()

assertNull(url)
}

@Test
fun `returns null URL if server address missing`() {
givenAttributes(
mapOf(
UrlAttributes.URL_SCHEME to "https",
ServerAttributes.SERVER_PORT to 8082L,
UrlAttributes.URL_PATH to "/some/path"
)
)

val url = whenExtractingUrl()

assertNull(url)
}

@Test
fun `returns reconstructed URL if attributes present without port and path`() {
givenAttributes(
mapOf(
UrlAttributes.URL_SCHEME to "https",
ServerAttributes.SERVER_ADDRESS to "sentry.io"
)
)

val url = whenExtractingUrl()

assertEquals("https://sentry.io", url)
}

@Test
fun `returns reconstructed URL if attributes present without path`() {
givenAttributes(
mapOf(
UrlAttributes.URL_SCHEME to "https",
ServerAttributes.SERVER_ADDRESS to "sentry.io",
ServerAttributes.SERVER_PORT to 8082L
)
)

val url = whenExtractingUrl()

assertEquals("https://sentry.io:8082", url)
}

private fun givenAttributes(map: Map<AttributeKey<out Any>, Any>) {
map.forEach { k, v ->
fixture.attributes.put(k, v)
Expand All @@ -183,6 +295,10 @@ class OpenTelemetryAttributesExtractorTest {
OpenTelemetryAttributesExtractor().extract(fixture.spanData, fixture.sentrySpan, fixture.scope)
}

private fun whenExtractingUrl(): String? {
return OpenTelemetryAttributesExtractor().extractUrl(fixture.attributes)
}

private fun thenRequestIsSet() {
assertNotNull(fixture.scope.request)
}
Expand Down
Loading
Loading