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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- Increase http timeouts from 5s to 30s to have a better chance of events being delivered without retry ([#4276](https://github.com/getsentry/sentry-java/pull/4276))
- Retain baggage sample rate/rand values as doubles ([#4279](https://github.com/getsentry/sentry-java/pull/4279))

### Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,8 @@ class InternalSentrySdkTest {
val propagationContext = scope.propagationContext
assertEquals(SentryId(traceId), propagationContext.traceId)
assertEquals(SpanId(spanId), propagationContext.parentSpanId)
assertEquals(sampleRate, propagationContext.baggage.sampleRateDouble)
assertEquals(sampleRand, propagationContext.baggage.sampleRandDouble)
assertEquals(sampleRate, propagationContext.baggage.sampleRate!!, 0.0001)
assertEquals(sampleRand, propagationContext.baggage.sampleRand!!, 0.0001)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ class SentrySpanProcessorTest {
assertTrue(it.parentSamplingDecision!!.sampled)
if (continuesWithFilledBaggage) {
assertEquals("2722d9f6ec019ade60c776169d9a8904", it.baggage?.traceId)
assertEquals("1", it.baggage?.sampleRate)
assertEquals(1.0, it.baggage?.sampleRate)
assertEquals("HTTP GET", it.baggage?.transaction)
assertEquals("502f25099c204a2fbf4cb16edc5975d1", it.baggage?.publicKey)
assertFalse(it.baggage!!.isMutable)
Expand Down
15 changes: 6 additions & 9 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ 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;ZZLio/sentry/ILogger;)V
public fun forceSetSampleRate (Ljava/lang/String;)V
public fun <init> (Ljava/util/Map;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/String;ZZLio/sentry/ILogger;)V
public fun forceSetSampleRate (Ljava/lang/Double;)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 @@ -47,10 +47,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 getSampleRand ()Ljava/lang/Double;
public fun getSampleRate ()Ljava/lang/Double;
public fun getSampled ()Ljava/lang/String;
public fun getThirdPartyHeader ()Ljava/lang/String;
public fun getTraceId ()Ljava/lang/String;
Expand All @@ -64,9 +62,8 @@ public final class io/sentry/Baggage {
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 setSampleRand (Ljava/lang/Double;)V
public fun setSampleRate (Ljava/lang/Double;)V
public fun setSampled (Ljava/lang/String;)V
public fun setTraceId (Ljava/lang/String;)V
public fun setTransaction (Ljava/lang/String;)V
Expand Down
110 changes: 68 additions & 42 deletions sentry/src/main/java/io/sentry/Baggage.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,22 @@ public final class Baggage {
static final @NotNull Integer MAX_BAGGAGE_LIST_MEMBER_COUNT = 64;
static final @NotNull String SENTRY_BAGGAGE_PREFIX = "sentry-";

// DecimalFormat is not thread safe
private static class DecimalFormatterThreadLocal extends ThreadLocal<DecimalFormat> {

@Override
protected DecimalFormat initialValue() {
return new DecimalFormat("#.################", DecimalFormatSymbols.getInstance(Locale.ROOT));
}
}

private static final DecimalFormatterThreadLocal decimalFormatter =
new DecimalFormatterThreadLocal();

final @NotNull Map<String, String> keyValues;
@Nullable Double sampleRate;
@Nullable Double sampleRand;

final @Nullable String thirdPartyHeader;
private boolean mutable;
private boolean shouldFreeze;
Expand Down Expand Up @@ -88,6 +103,9 @@ public static Baggage fromHeader(
final @NotNull List<String> thirdPartyKeyValueStrings = new ArrayList<>();
boolean shouldFreeze = false;

@Nullable Double sampleRate = null;
@Nullable Double sampleRand = null;

if (headerValue != null) {
try {
// see https://errorprone.info/bugpattern/StringSplitter for why limit is passed
Expand All @@ -103,8 +121,13 @@ public static Baggage fromHeader(
final String value = keyValueString.substring(separatorIndex + 1).trim();
final String valueDecoded = decode(value);

keyValues.put(keyDecoded, valueDecoded);

if (DSCKeys.SAMPLE_RATE.equals(keyDecoded)) {
sampleRate = toDouble(valueDecoded);
} else if (DSCKeys.SAMPLE_RAND.equals(keyDecoded)) {
sampleRand = toDouble(valueDecoded);
} else {
keyValues.put(keyDecoded, valueDecoded);
}
// Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting
// via OTel span attributes.
// This is done when a transaction is created via Sentry API.
Expand Down Expand Up @@ -142,7 +165,8 @@ public static Baggage fromHeader(
also we don't receive sentry-trace header here or in ctor so we can't
backfill then freeze here unless we pass sentry-trace header.
*/
return new Baggage(keyValues, thirdPartyHeader, true, shouldFreeze, logger);
return new Baggage(
keyValues, sampleRate, sampleRand, thirdPartyHeader, true, shouldFreeze, logger);
}

@ApiStatus.Internal
Expand Down Expand Up @@ -172,13 +196,15 @@ public static Baggage fromEvent(

@ApiStatus.Internal
public Baggage(final @NotNull ILogger logger) {
this(new HashMap<>(), null, true, false, logger);
this(new HashMap<>(), null, null, null, true, false, logger);
}

@ApiStatus.Internal
public Baggage(final @NotNull Baggage baggage) {
this(
baggage.keyValues,
baggage.sampleRate,
baggage.sampleRand,
baggage.thirdPartyHeader,
baggage.mutable,
baggage.shouldFreeze,
Expand All @@ -188,11 +214,15 @@ public Baggage(final @NotNull Baggage baggage) {
@ApiStatus.Internal
public Baggage(
final @NotNull Map<String, String> keyValues,
final @Nullable Double sampleRate,
final @Nullable Double sampleRand,
final @Nullable String thirdPartyHeader,
boolean isMutable,
boolean shouldFreeze,
final @NotNull ILogger logger) {
this.keyValues = keyValues;
this.sampleRate = sampleRate;
this.sampleRand = sampleRand;
this.logger = logger;
this.thirdPartyHeader = thirdPartyHeader;
this.mutable = isMutable;
Expand Down Expand Up @@ -231,8 +261,18 @@ public String getThirdPartyHeader() {
}

final Set<String> keys = new TreeSet<>(keyValues.keySet());
Copy link
Member Author

Choose a reason for hiding this comment

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

I know this is quite hacky, an alternative would be to let keyValues be a Map<String, String|Number> aka Map<String, Object>

Copy link
Member

Choose a reason for hiding this comment

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

We can revisit when more fields need to be added in the future and this current approach gets harder to maintain. I think it's fine for now.

keys.add(DSCKeys.SAMPLE_RATE);
keys.add(DSCKeys.SAMPLE_RAND);

for (final String key : keys) {
final @Nullable String value = keyValues.get(key);
final @Nullable String value;
if (DSCKeys.SAMPLE_RATE.equals(key)) {
value = sampleRateToString(sampleRate);
} else if (DSCKeys.SAMPLE_RAND.equals(key)) {
value = sampleRateToString(sampleRand);
} else {
value = keyValues.get(key);
}

if (value != null) {
if (listMemberCount >= MAX_BAGGAGE_LIST_MEMBER_COUNT) {
Expand Down Expand Up @@ -271,7 +311,6 @@ public String getThirdPartyHeader() {
}
}
}

return sb.toString();
}

Expand Down Expand Up @@ -353,8 +392,8 @@ public void setTransaction(final @Nullable String transaction) {
}

@ApiStatus.Internal
public @Nullable String getSampleRate() {
return get(DSCKeys.SAMPLE_RATE);
public @Nullable Double getSampleRate() {
return sampleRate;
}

@ApiStatus.Internal
Expand All @@ -363,28 +402,27 @@ public void setTransaction(final @Nullable String transaction) {
}

@ApiStatus.Internal
public void setSampleRate(final @Nullable String sampleRate) {
set(DSCKeys.SAMPLE_RATE, sampleRate);
}

@ApiStatus.Internal
public void forceSetSampleRate(final @Nullable String sampleRate) {
set(DSCKeys.SAMPLE_RATE, sampleRate, true);
public void setSampleRate(final @Nullable Double sampleRate) {
if (isMutable()) {
this.sampleRate = sampleRate;
}
}

@ApiStatus.Internal
public @Nullable String getSampleRand() {
return get(DSCKeys.SAMPLE_RAND);
public void forceSetSampleRate(final @Nullable Double sampleRate) {
this.sampleRate = sampleRate;
}

@ApiStatus.Internal
public void setSampleRand(final @Nullable String sampleRand) {
set(DSCKeys.SAMPLE_RAND, sampleRand);
public @Nullable Double getSampleRand() {
return sampleRand;
}

@ApiStatus.Internal
public void setSampleRandDouble(final @Nullable Double sampleRand) {
setSampleRand(sampleRateToString(sampleRand));
public void setSampleRand(final @Nullable Double sampleRand) {
if (isMutable()) {
this.sampleRand = sampleRand;
}
}

@ApiStatus.Internal
Expand Down Expand Up @@ -453,9 +491,9 @@ public void setValuesFromTransaction(
if (replayId != null && !SentryId.EMPTY_ID.equals(replayId)) {
setReplayId(replayId.toString());
}
setSampleRate(sampleRateToString(sampleRate(samplingDecision)));
setSampleRate(sampleRate(samplingDecision));
setSampled(StringUtils.toString(sampled(samplingDecision)));
setSampleRand(sampleRateToString(sampleRand(samplingDecision))); // TODO check
setSampleRand(sampleRand(samplingDecision));
}

@ApiStatus.Internal
Expand All @@ -468,11 +506,11 @@ public void setValuesFromSamplingDecision(
setSampled(StringUtils.toString(sampled(samplingDecision)));

if (samplingDecision.getSampleRand() != null) {
setSampleRand(sampleRateToString(sampleRand(samplingDecision)));
setSampleRand(sampleRand(samplingDecision));
}

if (samplingDecision.getSampleRate() != null) {
forceSetSampleRate(sampleRateToString(sampleRate(samplingDecision)));
forceSetSampleRate(sampleRate(samplingDecision));
}
}

Expand Down Expand Up @@ -513,10 +551,7 @@ public void setValuesFromScope(
if (!SampleRateUtils.isValidTracesSampleRate(sampleRateAsDouble, false)) {
return null;
}

DecimalFormat df =
new DecimalFormat("#.################", DecimalFormatSymbols.getInstance(Locale.ROOT));
return df.format(sampleRateAsDouble);
return decimalFormatter.get().format(sampleRateAsDouble);
}

private static @Nullable Boolean sampled(@Nullable TracesSamplingDecision samplingDecision) {
Expand All @@ -533,17 +568,8 @@ private static boolean isHighQualityTransactionName(
&& !TransactionNameSource.URL.equals(transactionNameSource);
}

@ApiStatus.Internal
public @Nullable Double getSampleRateDouble() {
return toDouble(getSampleRate());
}

@ApiStatus.Internal
public @Nullable Double getSampleRandDouble() {
return toDouble(getSampleRand());
}

private @Nullable Double toDouble(final @Nullable String stringValue) {
@Nullable
private static Double toDouble(final @Nullable String stringValue) {
if (stringValue != null) {
try {
double doubleValue = Double.parseDouble(stringValue);
Expand Down Expand Up @@ -573,10 +599,10 @@ public TraceContext toTraceContext() {
getEnvironment(),
getUserId(),
getTransaction(),
getSampleRate(),
sampleRateToString(getSampleRate()),
getSampled(),
replayIdString == null ? null : new SentryId(replayIdString),
getSampleRand());
sampleRateToString(getSampleRand()));
traceContext.setUnknown(getUnknown());
return traceContext;
} else {
Expand Down
8 changes: 2 additions & 6 deletions sentry/src/main/java/io/sentry/PropagationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,7 @@ public void setSampled(final @Nullable Boolean sampled) {
}

public @Nullable TraceContext traceContext() {
if (baggage != null) {
return baggage.toTraceContext();
}

return null;
return baggage.toTraceContext();
}

public @NotNull SpanContext toSpanContext() {
Expand All @@ -149,7 +145,7 @@ public void setSampled(final @Nullable Boolean sampled) {
}

public @NotNull Double getSampleRand() {
final @Nullable Double sampleRand = baggage.getSampleRandDouble();
final @Nullable Double sampleRand = baggage.getSampleRand();
// should never be null since we ensure it in ctor
return sampleRand == null ? 0.0 : sampleRand;
}
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/Scopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ && getOptions().getProfileLifecycle() == ProfileLifecycle.TRACE) {
private @NotNull Double getSampleRand(final @NotNull TransactionContext transactionContext) {
final @Nullable Baggage baggage = transactionContext.getBaggage();
if (baggage != null) {
final @Nullable Double sampleRandFromBaggageMaybe = baggage.getSampleRandDouble();
final @Nullable Double sampleRandFromBaggageMaybe = baggage.getSampleRand();
if (sampleRandFromBaggageMaybe != null) {
return sampleRandFromBaggageMaybe;
}
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/TransactionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static TransactionContext fromPropagationContext(
final @NotNull PropagationContext propagationContext) {
final @Nullable Boolean parentSampled = propagationContext.isSampled();
final @NotNull Baggage baggage = propagationContext.getBaggage();
final @Nullable Double sampleRate = baggage.getSampleRateDouble();
final @Nullable Double sampleRate = baggage.getSampleRate();
final @Nullable TracesSamplingDecision samplingDecision =
parentSampled == null
? null
Expand Down
4 changes: 2 additions & 2 deletions sentry/src/main/java/io/sentry/util/TracingUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ public static boolean isIgnored(
incomingBaggage == null ? new Baggage(NoOpLogger.getInstance()) : incomingBaggage;

if (baggage.getSampleRand() == null) {
final @Nullable Double baggageSampleRate = baggage.getSampleRateDouble();
final @Nullable Double baggageSampleRate = baggage.getSampleRate();
final @Nullable Double sampleRateMaybe =
baggageSampleRate == null ? decisionSampleRate : baggageSampleRate;
final @NotNull Double sampleRand =
SampleRateUtils.backfilledSampleRand(
decisionSampleRand, sampleRateMaybe, decisionSampled);
baggage.setSampleRandDouble(sampleRand);
baggage.setSampleRand(sampleRand);
}
if (baggage.isMutable()) {
if (baggage.isShouldFreeze()) {
Expand Down
Loading
Loading