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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- Expose new `withSentryObservableEffect` method overload that accepts `SentryNavigationListener` as a parameter ([#4143](https://github.com/getsentry/sentry-java/pull/4143))
- This allows sharing the same `SentryNavigationListener` instance across fragments and composables to preserve the trace
- (Internal) Add API to filter native debug images based on stacktrace addresses ([#4089](https://github.com/getsentry/sentry-java/pull/4089))
- Propagate sampling random value ([#4153](https://github.com/getsentry/sentry-java/pull/4153))
- The random value used for sampling traces is now sent to Sentry and attached to the `baggage` header on outgoing requests

### Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public final class io/sentry/opentelemetry/InternalSemanticAttributes {
public static final field PROFILE_SAMPLED Lio/opentelemetry/api/common/AttributeKey;
public static final field PROFILE_SAMPLE_RATE Lio/opentelemetry/api/common/AttributeKey;
public static final field SAMPLED Lio/opentelemetry/api/common/AttributeKey;
public static final field SAMPLE_RAND Lio/opentelemetry/api/common/AttributeKey;
public static final field SAMPLE_RATE Lio/opentelemetry/api/common/AttributeKey;
public fun <init> ()V
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public final class InternalSemanticAttributes {
public static final AttributeKey<Boolean> SAMPLED = AttributeKey.booleanKey("sentry.sampled");
public static final AttributeKey<Double> SAMPLE_RATE =
AttributeKey.doubleKey("sentry.sample_rate");
public static final AttributeKey<Double> SAMPLE_RAND =
AttributeKey.doubleKey("sentry.sample_rand");
public static final AttributeKey<Boolean> PARENT_SAMPLED =
AttributeKey.booleanKey("sentry.parent_sampled");
public static final AttributeKey<Boolean> PROFILE_SAMPLED =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public OtelSpanFactory() {
spanBuilder.setAttribute(InternalSemanticAttributes.SAMPLED, samplingDecision.getSampled());
spanBuilder.setAttribute(
InternalSemanticAttributes.SAMPLE_RATE, samplingDecision.getSampleRate());
spanBuilder.setAttribute(
InternalSemanticAttributes.SAMPLE_RAND, samplingDecision.getSampleRand());
spanBuilder.setAttribute(
InternalSemanticAttributes.PROFILE_SAMPLED, samplingDecision.getProfileSampled());
spanBuilder.setAttribute(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ public final class OtelSamplingUtil {
final @Nullable Boolean sampled = attributes.get(InternalSemanticAttributes.SAMPLED);
if (sampled != null) {
final @Nullable Double sampleRate = attributes.get(InternalSemanticAttributes.SAMPLE_RATE);
final @Nullable Double sampleRand = attributes.get(InternalSemanticAttributes.SAMPLE_RAND);
final @Nullable Boolean profileSampled =
attributes.get(InternalSemanticAttributes.PROFILE_SAMPLED);
final @Nullable Double profileSampleRate =
attributes.get(InternalSemanticAttributes.PROFILE_SAMPLE_RATE);

return new TracesSamplingDecision(
sampled, sampleRate, profileSampled == null ? false : profileSampled, profileSampleRate);
sampled,
sampleRate,
sampleRand,
profileSampled == null ? false : profileSampled,
profileSampleRate);
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
import io.sentry.Baggage;
import io.sentry.BaggageHeader;
import io.sentry.IScopes;
import io.sentry.PropagationContext;
import io.sentry.ScopesAdapter;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import io.sentry.SentryTraceHeader;
import io.sentry.exception.InvalidSentryTraceHeaderException;
import io.sentry.util.TracingUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -73,12 +73,17 @@ public <C> void inject(final Context context, final C carrier, final TextMapSett
return;
}

final @NotNull SentryTraceHeader sentryTraceHeader = sentrySpan.toSentryTrace();
setter.set(carrier, sentryTraceHeader.getName(), sentryTraceHeader.getValue());
final @Nullable BaggageHeader baggageHeader =
sentrySpan.toBaggageHeader(Collections.emptyList());
if (baggageHeader != null) {
setter.set(carrier, baggageHeader.getName(), baggageHeader.getValue());
// TODO can we use traceIfAllowed? do we have the URL here? need to access span attrs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left this as a TODO for the future. We could start looking at span attributes to retrieve the URL of the downstream system.

final @Nullable TracingUtils.TracingHeaders tracingHeaders =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures baggage is frozen when sending out headers. Not freezing was a bug.

TracingUtils.trace(scopes, Collections.emptyList(), sentrySpan);

if (tracingHeaders != null) {
final @NotNull SentryTraceHeader sentryTraceHeader = tracingHeaders.getSentryTraceHeader();
setter.set(carrier, sentryTraceHeader.getName(), sentryTraceHeader.getValue());
final @Nullable BaggageHeader baggageHeader = tracingHeaders.getBaggageHeader();
if (baggageHeader != null) {
setter.set(carrier, baggageHeader.getName(), baggageHeader.getValue());
}
}
}

Expand Down Expand Up @@ -125,11 +130,6 @@ public <C> Context extract(
.getLogger()
.log(SentryLevel.DEBUG, "Continuing Sentry trace %s", sentryTraceHeader.getTraceId());

final @NotNull PropagationContext propagationContext =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this causes baggage to be frozen immediately, we no longer want to do this in the propagator.

PropagationContext.fromHeaders(
scopes.getOptions().getLogger(), sentryTraceString, baggageString);
scopesToUse.getIsolationScope().setPropagationContext(propagationContext);

return modifiedContext;
} catch (InvalidSentryTraceHeaderException e) {
scopes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,10 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri
baggage = baggageFromContext;
}

final @Nullable Boolean baggageMutable =
otelSpan.getAttribute(InternalSemanticAttributes.BAGGAGE_MUTABLE);
final @Nullable String baggageString =
otelSpan.getAttribute(InternalSemanticAttributes.BAGGAGE);
if (baggageString != null) {
baggage = Baggage.fromHeader(baggageString);
if (baggageMutable == true) {
baggage.freeze();
}
}

final @Nullable Boolean sampled = isSampled(otelSpan, samplingDecision);
Expand All @@ -87,6 +82,8 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri
new PropagationContext(
new SentryId(traceId), sentrySpanId, sentryParentSpanId, baggage, sampled);

baggage = propagationContext.getBaggage();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to send the wrong baggage into the OtelSpanWrapper ctor further down.


updatePropagationContext(scopes, propagationContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public final class OtelSpanWrapper implements IOtelSpanWrapper {
private final @NotNull Contexts contexts = new Contexts();
private @Nullable String transactionName;
private @Nullable TransactionNameSource transactionNameSource;
private final @Nullable Baggage baggage;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to keep this as a property here. We can always ask the context for it.

private final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();

private final @NotNull Map<String, Object> data = new ConcurrentHashMap<>();
Expand All @@ -86,17 +85,12 @@ public OtelSpanWrapper(
this.scopes = Objects.requireNonNull(scopes, "scopes are required");
this.span = new WeakReference<>(span);
this.startTimestamp = startTimestamp;

if (parentSpan != null) {
this.baggage = parentSpan.getSpanContext().getBaggage();
} else if (baggage != null) {
this.baggage = baggage;
} else {
this.baggage = null;
}

final @Nullable Baggage baggageToUse =
baggage != null
? baggage
: (parentSpan != null ? parentSpan.getSpanContext().getBaggage() : null);
this.context =
new OtelSpanContext(span, samplingDecision, parentSpan, parentSpanId, this.baggage);
new OtelSpanContext(span, samplingDecision, parentSpan, parentSpanId, baggageToUse);
}

@Override
Expand Down Expand Up @@ -207,15 +201,16 @@ public OtelSpanWrapper(
@Override
public @Nullable TraceContext traceContext() {
if (scopes.getOptions().isTraceSampling()) {
final @Nullable Baggage baggage = context.getBaggage();
if (baggage != null) {
updateBaggageValues();
updateBaggageValues(baggage);
return baggage.toTraceContext();
}
}
return null;
}

private void updateBaggageValues() {
private void updateBaggageValues(final @NotNull Baggage baggage) {
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
if (baggage != null && baggage.isMutable()) {
final AtomicReference<SentryId> replayIdAtomicReference = new AtomicReference<>();
Expand All @@ -238,8 +233,9 @@ private void updateBaggageValues() {
@Override
public @Nullable BaggageHeader toBaggageHeader(@Nullable List<String> thirdPartyBaggageHeaders) {
if (scopes.getOptions().isTraceSampling()) {
final @Nullable Baggage baggage = context.getBaggage();
if (baggage != null) {
updateBaggageValues();
updateBaggageValues(baggage);
return BaggageHeader.fromBaggageAndOutgoingHeader(baggage, thirdPartyBaggageHeaders);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ public SamplingResult shouldSample(
scopes
.getOptions()
.getInternalTracesSampler()
.sample(new SamplingContext(transactionContext, null));
.sample(
new SamplingContext(transactionContext, null, propagationContext.getSampleRand()));

if (!sentryDecision.getSampled()) {
scopes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public Attributes getAttributes() {
return Attributes.builder()
.put(InternalSemanticAttributes.SAMPLED, sentryDecision.getSampled())
.put(InternalSemanticAttributes.SAMPLE_RATE, sentryDecision.getSampleRate())
.put(InternalSemanticAttributes.SAMPLE_RAND, sentryDecision.getSampleRand())
.put(InternalSemanticAttributes.PROFILE_SAMPLED, sentryDecision.getProfileSampled())
.put(InternalSemanticAttributes.PROFILE_SAMPLE_RATE, sentryDecision.getProfileSampleRate())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public final class SentrySpanExporter implements SpanExporter {
InternalSemanticAttributes.BAGGAGE_MUTABLE.getKey(),
InternalSemanticAttributes.SAMPLED.getKey(),
InternalSemanticAttributes.SAMPLE_RATE.getKey(),
InternalSemanticAttributes.SAMPLE_RAND.getKey(),
InternalSemanticAttributes.PROFILE_SAMPLED.getKey(),
InternalSemanticAttributes.PROFILE_SAMPLE_RATE.getKey(),
InternalSemanticAttributes.PARENT_SAMPLED.getKey(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,15 @@ class SentrySpanProcessorTest {
assertEquals("1", it.baggage?.sampleRate)
assertEquals("HTTP GET", it.baggage?.transaction)
assertEquals("502f25099c204a2fbf4cb16edc5975d1", it.baggage?.publicKey)
assertFalse(it.baggage!!.isMutable)
} else {
assertNotNull(it.baggage)
assertNull(it.baggage?.traceId)
assertNull(it.baggage?.sampleRate)
assertNull(it.baggage?.transaction)
assertNull(it.baggage?.publicKey)
assertFalse(it.baggage!!.isMutable)
assertTrue(it.baggage!!.isMutable)
}
assertFalse(it.baggage!!.isMutable)
},
check<TransactionOptions> {
assertNotNull(it.startTimestamp)
Expand All @@ -434,7 +434,7 @@ class SentrySpanProcessorTest {
assertEquals(otelSpan.spanContext.traceId, it.traceId.toString())
assertNull(it.parentSpanId)
assertNull(it.parentSamplingDecision)
assertNull(it.baggage)
assertNotNull(it.baggage)
},
check<TransactionOptions> {
assertNotNull(it.startTimestamp)
Expand Down
21 changes: 19 additions & 2 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public abstract interface class io/sentry/BackfillingEventProcessor : io/sentry/
public final class io/sentry/Baggage {
public fun <init> (Lio/sentry/Baggage;)V
public fun <init> (Lio/sentry/ILogger;)V
public fun <init> (Ljava/util/Map;Ljava/lang/String;ZLio/sentry/ILogger;)V
public fun <init> (Ljava/util/Map;Ljava/lang/String;ZZLio/sentry/ILogger;)V
public fun freeze ()V
public static fun fromEvent (Lio/sentry/SentryEvent;Lio/sentry/SentryOptions;)Lio/sentry/Baggage;
public static fun fromHeader (Ljava/lang/String;)Lio/sentry/Baggage;
Expand All @@ -46,6 +46,8 @@ public final class io/sentry/Baggage {
public fun getPublicKey ()Ljava/lang/String;
public fun getRelease ()Ljava/lang/String;
public fun getReplayId ()Ljava/lang/String;
public fun getSampleRand ()Ljava/lang/String;
public fun getSampleRandDouble ()Ljava/lang/Double;
public fun getSampleRate ()Ljava/lang/String;
public fun getSampleRateDouble ()Ljava/lang/Double;
public fun getSampled ()Ljava/lang/String;
Expand All @@ -55,11 +57,14 @@ public final class io/sentry/Baggage {
public fun getUnknown ()Ljava/util/Map;
public fun getUserId ()Ljava/lang/String;
public fun isMutable ()Z
public fun isShouldFreeze ()Z
public fun set (Ljava/lang/String;Ljava/lang/String;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setPublicKey (Ljava/lang/String;)V
public fun setRelease (Ljava/lang/String;)V
public fun setReplayId (Ljava/lang/String;)V
public fun setSampleRand (Ljava/lang/String;)V
public fun setSampleRandDouble (Ljava/lang/Double;)V
public fun setSampleRate (Ljava/lang/String;)V
public fun setSampled (Ljava/lang/String;)V
public fun setTraceId (Ljava/lang/String;)V
Expand All @@ -78,6 +83,7 @@ public final class io/sentry/Baggage$DSCKeys {
public static final field RELEASE Ljava/lang/String;
public static final field REPLAY_ID Ljava/lang/String;
public static final field SAMPLED Ljava/lang/String;
public static final field SAMPLE_RAND Ljava/lang/String;
public static final field SAMPLE_RATE Ljava/lang/String;
public static final field TRACE_ID Ljava/lang/String;
public static final field TRANSACTION Ljava/lang/String;
Expand Down Expand Up @@ -1947,10 +1953,10 @@ public final class io/sentry/PropagationContext {
public static fun fromHeaders (Lio/sentry/SentryTraceHeader;Lio/sentry/Baggage;Lio/sentry/SpanId;)Lio/sentry/PropagationContext;
public fun getBaggage ()Lio/sentry/Baggage;
public fun getParentSpanId ()Lio/sentry/SpanId;
public fun getSampleRand ()Ljava/lang/Double;
public fun getSpanId ()Lio/sentry/SpanId;
public fun getTraceId ()Lio/sentry/protocol/SentryId;
public fun isSampled ()Ljava/lang/Boolean;
public fun setBaggage (Lio/sentry/Baggage;)V
public fun setParentSpanId (Lio/sentry/SpanId;)V
public fun setSampled (Ljava/lang/Boolean;)V
public fun setSpanId (Lio/sentry/SpanId;)V
Expand Down Expand Up @@ -2007,7 +2013,9 @@ public final class io/sentry/RequestDetails {

public final class io/sentry/SamplingContext {
public fun <init> (Lio/sentry/TransactionContext;Lio/sentry/CustomSamplingContext;)V
public fun <init> (Lio/sentry/TransactionContext;Lio/sentry/CustomSamplingContext;Ljava/lang/Double;)V
public fun getCustomSamplingContext ()Lio/sentry/CustomSamplingContext;
public fun getSampleRand ()Ljava/lang/Double;
public fun getTransactionContext ()Lio/sentry/TransactionContext;
}

Expand Down Expand Up @@ -3634,6 +3642,7 @@ public final class io/sentry/TraceContext : io/sentry/JsonSerializable, io/sentr
public fun getPublicKey ()Ljava/lang/String;
public fun getRelease ()Ljava/lang/String;
public fun getReplayId ()Lio/sentry/protocol/SentryId;
public fun getSampleRand ()Ljava/lang/String;
public fun getSampleRate ()Ljava/lang/String;
public fun getSampled ()Ljava/lang/String;
public fun getTraceId ()Lio/sentry/protocol/SentryId;
Expand All @@ -3656,6 +3665,7 @@ public final class io/sentry/TraceContext$JsonKeys {
public static final field RELEASE Ljava/lang/String;
public static final field REPLAY_ID Ljava/lang/String;
public static final field SAMPLED Ljava/lang/String;
public static final field SAMPLE_RAND Ljava/lang/String;
public static final field SAMPLE_RATE Ljava/lang/String;
public static final field TRACE_ID Ljava/lang/String;
public static final field TRANSACTION Ljava/lang/String;
Expand All @@ -3672,8 +3682,11 @@ public final class io/sentry/TracesSamplingDecision {
public fun <init> (Ljava/lang/Boolean;)V
public fun <init> (Ljava/lang/Boolean;Ljava/lang/Double;)V
public fun <init> (Ljava/lang/Boolean;Ljava/lang/Double;Ljava/lang/Boolean;Ljava/lang/Double;)V
public fun <init> (Ljava/lang/Boolean;Ljava/lang/Double;Ljava/lang/Double;)V
public fun <init> (Ljava/lang/Boolean;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Boolean;Ljava/lang/Double;)V
public fun getProfileSampleRate ()Ljava/lang/Double;
public fun getProfileSampled ()Ljava/lang/Boolean;
public fun getSampleRand ()Ljava/lang/Double;
public fun getSampleRate ()Ljava/lang/Double;
public fun getSampled ()Ljava/lang/Boolean;
}
Expand Down Expand Up @@ -6275,6 +6288,8 @@ public final class io/sentry/util/Random : java/io/Serializable {

public final class io/sentry/util/SampleRateUtils {
public fun <init> ()V
public static fun backfilledSampleRand (Lio/sentry/TracesSamplingDecision;)Lio/sentry/TracesSamplingDecision;
public static fun backfilledSampleRand (Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Boolean;)Ljava/lang/Double;
public static fun isValidProfilesSampleRate (Ljava/lang/Double;)Z
public static fun isValidSampleRate (Ljava/lang/Double;)Z
public static fun isValidTracesSampleRate (Ljava/lang/Double;)Z
Expand Down Expand Up @@ -6310,6 +6325,8 @@ public final class io/sentry/util/StringUtils {

public final class io/sentry/util/TracingUtils {
public fun <init> ()V
public static fun ensureBaggage (Lio/sentry/Baggage;Lio/sentry/TracesSamplingDecision;)Lio/sentry/Baggage;
public static fun ensureBaggage (Lio/sentry/Baggage;Ljava/lang/Boolean;Ljava/lang/Double;Ljava/lang/Double;)Lio/sentry/Baggage;
public static fun isIgnored (Ljava/util/List;Ljava/lang/String;)Z
public static fun maybeUpdateBaggage (Lio/sentry/IScope;Lio/sentry/SentryOptions;)Lio/sentry/PropagationContext;
public static fun startNewTrace (Lio/sentry/IScopes;)V
Expand Down
Loading
Loading