Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
- Add support for Spring Boot 4 and Spring 7 ([#4601](https://github.com/getsentry/sentry-java/pull/4601))
- NOTE: Our `sentry-opentelemetry-agentless-spring` is not working yet for Spring Boot 4. Please use `sentry-opentelemetry-agent` until OpenTelemetry has support for Spring Boot 4.
- Replace `UUIDGenerator` implementation with Apache licensed code ([#4662](https://github.com/getsentry/sentry-java/pull/4662))
- Add support for w3c traceparent header ([#4671](https://github.com/getsentry/sentry-java/pull/4671))
- This feature is disabled by default. If enabled, outgoing requests will include the w3c `traceparent` header.
- See https://develop.sentry.dev/sdk/telemetry/traces/distributed-tracing/#w3c-trace-context-header for more details.
```kotlin
Sentry(Android).init(context) { options ->
// ...
options.isPropagateTraceparent = true
}
```

## 8.20.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ constructor(
.toMutableList()
.apply { add(HttpHeader(baggageHeader.name, baggageHeader.value)) }
}
it.w3cTraceparentHeader?.let { w3cHeader ->
cleanedHeaders.add(HttpHeader(w3cHeader.name, w3cHeader.value))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ constructor(
.toMutableList()
.apply { add(HttpHeader(baggageHeader.name, baggageHeader.value)) }
}
it.w3cTraceparentHeader?.let { w3cHeader ->
cleanedHeaders.add(HttpHeader(w3cHeader.name, w3cHeader.value))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public val SentryKtorClientPlugin: ClientPlugin<SentryKtorClientPluginConfig> =
request.headers.remove(BaggageHeader.BAGGAGE_HEADER)
request.headers[it.name] = it.value
}
tracingHeaders.w3cTraceparentHeader?.let { request.headers[it.name] = it.value }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public open class SentryOkHttpInterceptor(
requestBuilder.removeHeader(BaggageHeader.BAGGAGE_HEADER)
requestBuilder.addHeader(it.name, it.value)
}
tracingHeaders.w3cTraceparentHeader?.let { requestBuilder.addHeader(it.name, it.value) }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,4 +645,38 @@ class SentryOkHttpInterceptorTest {
val okHttpEvent = SentryOkHttpEventListener.eventMap[call]!!
assertTrue(okHttpEvent.isEventFinished.get())
}

@Test
fun `adds W3C traceparent header when propagateTraceparent is enabled`() {
val client =
fixture.getSut(
optionsConfiguration = Sentry.OptionsConfiguration { it.isPropagateTraceparent = true }
)

fixture.server.enqueue(MockResponse().setResponseCode(200))

val request = getRequest("/test")
client.newCall(request).execute()

val recordedRequest = fixture.server.takeRequest()
assertNotNull(recordedRequest.getHeader("sentry-trace"))
assertNotNull(recordedRequest.getHeader("traceparent"))
}

@Test
fun `does not add W3C traceparent header when propagateTraceparent is disabled`() {
val client =
fixture.getSut(
optionsConfiguration = Sentry.OptionsConfiguration { it.isPropagateTraceparent = false }
)

fixture.server.enqueue(MockResponse().setResponseCode(200))

val request = getRequest("/test")
client.newCall(request).execute()

val recordedRequest = fixture.server.takeRequest()
assertNotNull(recordedRequest.getHeader("sentry-trace"))
assertNull(recordedRequest.getHeader("traceparent"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.sentry.SpanDataConvention;
import io.sentry.SpanOptions;
import io.sentry.SpanStatus;
import io.sentry.W3CTraceparentHeader;
import io.sentry.util.Objects;
import io.sentry.util.SpanUtils;
import io.sentry.util.TracingUtils;
Expand Down Expand Up @@ -137,6 +138,12 @@ public Response execute(final @NotNull Request request, final @NotNull Request.O
requestWrapper.removeHeader(BaggageHeader.BAGGAGE_HEADER);
requestWrapper.header(baggageHeader.getName(), baggageHeader.getValue());
}

final @Nullable W3CTraceparentHeader w3cTraceparentHeader =
tracingHeaders.getW3cTraceparentHeader();
if (w3cTraceparentHeader != null) {
requestWrapper.header(w3cTraceparentHeader.getName(), w3cTraceparentHeader.getValue());
}
}

return requestWrapper.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.sentry.SpanDataConvention;
import io.sentry.SpanOptions;
import io.sentry.SpanStatus;
import io.sentry.W3CTraceparentHeader;
import io.sentry.util.Objects;
import io.sentry.util.SpanUtils;
import io.sentry.util.TracingUtils;
Expand Down Expand Up @@ -113,6 +114,12 @@ private void maybeAddTracingHeaders(
if (baggageHeader != null) {
request.getHeaders().set(baggageHeader.getName(), baggageHeader.getValue());
}

final @Nullable W3CTraceparentHeader w3cTraceparentHeader =
tracingHeaders.getW3cTraceparentHeader();
if (w3cTraceparentHeader != null) {
request.getHeaders().add(w3cTraceparentHeader.getName(), w3cTraceparentHeader.getValue());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.sentry.SpanDataConvention;
import io.sentry.SpanOptions;
import io.sentry.SpanStatus;
import io.sentry.W3CTraceparentHeader;
import io.sentry.util.Objects;
import io.sentry.util.SpanUtils;
import io.sentry.util.TracingUtils;
Expand Down Expand Up @@ -113,6 +114,12 @@ private void maybeAddTracingHeaders(
if (baggageHeader != null) {
request.getHeaders().set(baggageHeader.getName(), baggageHeader.getValue());
}

final @Nullable W3CTraceparentHeader w3cTraceparentHeader =
tracingHeaders.getW3cTraceparentHeader();
if (w3cTraceparentHeader != null) {
request.getHeaders().add(w3cTraceparentHeader.getName(), w3cTraceparentHeader.getValue());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.sentry.SpanDataConvention;
import io.sentry.SpanOptions;
import io.sentry.SpanStatus;
import io.sentry.W3CTraceparentHeader;
import io.sentry.util.Objects;
import io.sentry.util.SpanUtils;
import io.sentry.util.TracingUtils;
Expand Down Expand Up @@ -105,6 +106,12 @@ private void maybeAddTracingHeaders(
if (baggageHeader != null) {
request.getHeaders().set(baggageHeader.getName(), baggageHeader.getValue());
}

final @Nullable W3CTraceparentHeader w3cTraceparentHeader =
tracingHeaders.getW3cTraceparentHeader();
if (w3cTraceparentHeader != null) {
request.getHeaders().add(w3cTraceparentHeader.getName(), w3cTraceparentHeader.getValue());
}
}
}

Expand Down
11 changes: 11 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -3405,6 +3405,7 @@ public class io/sentry/SentryOptions {
public fun isGlobalHubMode ()Ljava/lang/Boolean;
public fun isPrintUncaughtStackTrace ()Z
public fun isProfilingEnabled ()Z
public fun isPropagateTraceparent ()Z
public fun isSendClientReports ()Z
public fun isSendDefaultPii ()Z
public fun isSendModules ()Z
Expand Down Expand Up @@ -3492,6 +3493,7 @@ public class io/sentry/SentryOptions {
public fun setProfilesSampler (Lio/sentry/SentryOptions$ProfilesSamplerCallback;)V
public fun setProfilingTracesHz (I)V
public fun setProguardUuid (Ljava/lang/String;)V
public fun setPropagateTraceparent (Z)V
public fun setProxy (Lio/sentry/SentryOptions$Proxy;)V
public fun setReadTimeoutMillis (I)V
public fun setRelease (Ljava/lang/String;)V
Expand Down Expand Up @@ -4322,6 +4324,13 @@ public final class io/sentry/UserFeedback$JsonKeys {
public fun <init> ()V
}

public final class io/sentry/W3CTraceparentHeader {
public static final field TRACEPARENT_HEADER Ljava/lang/String;
public fun <init> (Lio/sentry/protocol/SentryId;Lio/sentry/SpanId;Ljava/lang/Boolean;)V
public fun getName ()Ljava/lang/String;
public fun getValue ()Ljava/lang/String;
}

public final class io/sentry/backpressure/BackpressureMonitor : io/sentry/backpressure/IBackpressureMonitor, java/lang/Runnable {
public fun <init> (Lio/sentry/SentryOptions;Lio/sentry/IScopes;)V
public fun close ()V
Expand Down Expand Up @@ -7054,8 +7063,10 @@ public final class io/sentry/util/TracingUtils {

public final class io/sentry/util/TracingUtils$TracingHeaders {
public fun <init> (Lio/sentry/SentryTraceHeader;Lio/sentry/BaggageHeader;)V
public fun <init> (Lio/sentry/SentryTraceHeader;Lio/sentry/BaggageHeader;Lio/sentry/W3CTraceparentHeader;)V
public fun getBaggageHeader ()Lio/sentry/BaggageHeader;
public fun getSentryTraceHeader ()Lio/sentry/SentryTraceHeader;
public fun getW3cTraceparentHeader ()Lio/sentry/W3CTraceparentHeader;
}

public final class io/sentry/util/UUIDGenerator {
Expand Down
21 changes: 21 additions & 0 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ public class SentryOptions {
private final @NotNull List<String> defaultTracePropagationTargets =
Collections.singletonList(DEFAULT_PROPAGATION_TARGETS);

/** Whether to propagate W3C traceparent HTTP header. */
private boolean propagateTraceparent = false;

/** Proguard UUID. */
private @Nullable String proguardUuid;

Expand Down Expand Up @@ -2110,6 +2113,24 @@ public void setTracePropagationTargets(final @Nullable List<String> tracePropaga
}
}

/**
* Returns whether W3C traceparent HTTP header propagation is enabled.
*
* @return true if enabled false otherwise
*/
public boolean isPropagateTraceparent() {
return propagateTraceparent;
}

/**
* Enables or disables W3C traceparent HTTP header propagation.
*
* @param propagateTraceparent true if enabled false otherwise
*/
public void setPropagateTraceparent(final boolean propagateTraceparent) {
this.propagateTraceparent = propagateTraceparent;
}

/**
* Returns a Proguard UUID.
*
Expand Down
32 changes: 32 additions & 0 deletions sentry/src/main/java/io/sentry/W3CTraceparentHeader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.sentry;

import io.sentry.protocol.SentryId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/** Represents W3C traceparent HTTP header. */
public final class W3CTraceparentHeader {
public static final String TRACEPARENT_HEADER = "traceparent";

private final @NotNull SentryId traceId;
private final @NotNull SpanId spanId;
private final @Nullable Boolean sampled;

public W3CTraceparentHeader(
final @NotNull SentryId traceId,
final @NotNull SpanId spanId,
final @Nullable Boolean sampled) {
this.traceId = traceId;
this.spanId = spanId;
this.sampled = sampled;
}

public @NotNull String getName() {
return TRACEPARENT_HEADER;
}

public @NotNull String getValue() {
final String sampledFlag = sampled != null && sampled ? "01" : "00";
return String.format("%s-%s-%s", traceId, spanId, sampledFlag);
}
}
47 changes: 42 additions & 5 deletions sentry/src/main/java/io/sentry/util/TracingUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import io.sentry.PropagationContext;
import io.sentry.SentryOptions;
import io.sentry.SentryTraceHeader;
import io.sentry.SpanContext;
import io.sentry.TracesSamplingDecision;
import io.sentry.W3CTraceparentHeader;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -59,8 +61,18 @@ public static void setTrace(
final @NotNull SentryOptions sentryOptions = scopes.getOptions();

if (span != null && !span.isNoOp()) {
return new TracingHeaders(
span.toSentryTrace(), span.toBaggageHeader(thirdPartyBaggageHeaders));
final @NotNull SentryTraceHeader sentryTraceHeader = span.toSentryTrace();
final @Nullable BaggageHeader baggageHeader = span.toBaggageHeader(thirdPartyBaggageHeaders);
@Nullable W3CTraceparentHeader w3cTraceparentHeader = null;

if (sentryOptions.isPropagateTraceparent()) {
final @NotNull SpanContext spanContext = span.getSpanContext();
w3cTraceparentHeader =
new W3CTraceparentHeader(
spanContext.getTraceId(), spanContext.getSpanId(), sentryTraceHeader.isSampled());
}

return new TracingHeaders(sentryTraceHeader, baggageHeader, w3cTraceparentHeader);
} else {
final @NotNull PropagationContextHolder returnValue = new PropagationContextHolder();
scopes.configureScope(
Expand All @@ -74,12 +86,22 @@ public static void setTrace(
final @NotNull BaggageHeader baggageHeader =
BaggageHeader.fromBaggageAndOutgoingHeader(baggage, thirdPartyBaggageHeaders);

return new TracingHeaders(
final @NotNull SentryTraceHeader sentryTraceHeader =
new SentryTraceHeader(
propagationContext.getTraceId(),
propagationContext.getSpanId(),
propagationContext.isSampled()),
baggageHeader);
propagationContext.isSampled());

@Nullable W3CTraceparentHeader w3cTraceparentHeader = null;
if (sentryOptions.isPropagateTraceparent()) {
w3cTraceparentHeader =
new W3CTraceparentHeader(
propagationContext.getTraceId(),
propagationContext.getSpanId(),
propagationContext.isSampled());
}

return new TracingHeaders(sentryTraceHeader, baggageHeader, w3cTraceparentHeader);
}

return null;
Expand Down Expand Up @@ -110,12 +132,23 @@ private static final class PropagationContextHolder {
public static final class TracingHeaders {
private final @NotNull SentryTraceHeader sentryTraceHeader;
private final @Nullable BaggageHeader baggageHeader;
private final @Nullable W3CTraceparentHeader w3cTraceparentHeader;

public TracingHeaders(
final @NotNull SentryTraceHeader sentryTraceHeader,
final @Nullable BaggageHeader baggageHeader) {
this.sentryTraceHeader = sentryTraceHeader;
this.baggageHeader = baggageHeader;
this.w3cTraceparentHeader = null;
}

public TracingHeaders(
final @NotNull SentryTraceHeader sentryTraceHeader,
final @Nullable BaggageHeader baggageHeader,
final @Nullable W3CTraceparentHeader w3cTraceparentHeader) {
this.sentryTraceHeader = sentryTraceHeader;
this.baggageHeader = baggageHeader;
this.w3cTraceparentHeader = w3cTraceparentHeader;
}

public @NotNull SentryTraceHeader getSentryTraceHeader() {
Expand All @@ -125,6 +158,10 @@ public TracingHeaders(
public @Nullable BaggageHeader getBaggageHeader() {
return baggageHeader;
}

public @Nullable W3CTraceparentHeader getW3cTraceparentHeader() {
return w3cTraceparentHeader;
}
}

/** Checks if a transaction is to be ignored. */
Expand Down
13 changes: 13 additions & 0 deletions sentry/src/test/java/io/sentry/SentryOptionsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,17 @@ class SentryOptionsTest {
options.deadlineTimeout = -1L
assertEquals(-1L, options.deadlineTimeout)
}

@Test
fun `propagateTraceparent option defaults to false`() {
val options = SentryOptions()
assertFalse(options.isPropagateTraceparent)
}

@Test
fun `propagateTraceparent option can be changed`() {
val options = SentryOptions()
options.isPropagateTraceparent = true
assertTrue(options.isPropagateTraceparent)
}
}
Loading
Loading