@@ -32,7 +32,22 @@ public final class Baggage {
3232 static final @ NotNull Integer MAX_BAGGAGE_LIST_MEMBER_COUNT = 64 ;
3333 static final @ NotNull String SENTRY_BAGGAGE_PREFIX = "sentry-" ;
3434
35+ // DecimalFormat is not thread safe
36+ private static class DecimalFormatterThreadLocal extends ThreadLocal <DecimalFormat > {
37+
38+ @ Override
39+ protected DecimalFormat initialValue () {
40+ return new DecimalFormat ("#.################" , DecimalFormatSymbols .getInstance (Locale .ROOT ));
41+ }
42+ }
43+
44+ private static final DecimalFormatterThreadLocal decimalFormatter =
45+ new DecimalFormatterThreadLocal ();
46+
3547 final @ NotNull Map <String , String > keyValues ;
48+ @ Nullable Double sampleRate ;
49+ @ Nullable Double sampleRand ;
50+
3651 final @ Nullable String thirdPartyHeader ;
3752 private boolean mutable ;
3853 private boolean shouldFreeze ;
@@ -88,6 +103,9 @@ public static Baggage fromHeader(
88103 final @ NotNull List <String > thirdPartyKeyValueStrings = new ArrayList <>();
89104 boolean shouldFreeze = false ;
90105
106+ @ Nullable Double sampleRate = null ;
107+ @ Nullable Double sampleRand = null ;
108+
91109 if (headerValue != null ) {
92110 try {
93111 // see https://errorprone.info/bugpattern/StringSplitter for why limit is passed
@@ -103,8 +121,13 @@ public static Baggage fromHeader(
103121 final String value = keyValueString .substring (separatorIndex + 1 ).trim ();
104122 final String valueDecoded = decode (value );
105123
106- keyValues .put (keyDecoded , valueDecoded );
107-
124+ if (DSCKeys .SAMPLE_RATE .equals (keyDecoded )) {
125+ sampleRate = toDouble (valueDecoded );
126+ } else if (DSCKeys .SAMPLE_RAND .equals (keyDecoded )) {
127+ sampleRand = toDouble (valueDecoded );
128+ } else {
129+ keyValues .put (keyDecoded , valueDecoded );
130+ }
108131 // Without ignoring SAMPLE_RAND here, we'd be freezing baggage that we're transporting
109132 // via OTel span attributes.
110133 // This is done when a transaction is created via Sentry API.
@@ -142,7 +165,8 @@ public static Baggage fromHeader(
142165 also we don't receive sentry-trace header here or in ctor so we can't
143166 backfill then freeze here unless we pass sentry-trace header.
144167 */
145- return new Baggage (keyValues , thirdPartyHeader , true , shouldFreeze , logger );
168+ return new Baggage (
169+ keyValues , sampleRate , sampleRand , thirdPartyHeader , true , shouldFreeze , logger );
146170 }
147171
148172 @ ApiStatus .Internal
@@ -172,13 +196,15 @@ public static Baggage fromEvent(
172196
173197 @ ApiStatus .Internal
174198 public Baggage (final @ NotNull ILogger logger ) {
175- this (new HashMap <>(), null , true , false , logger );
199+ this (new HashMap <>(), null , null , null , true , false , logger );
176200 }
177201
178202 @ ApiStatus .Internal
179203 public Baggage (final @ NotNull Baggage baggage ) {
180204 this (
181205 baggage .keyValues ,
206+ baggage .sampleRate ,
207+ baggage .sampleRand ,
182208 baggage .thirdPartyHeader ,
183209 baggage .mutable ,
184210 baggage .shouldFreeze ,
@@ -188,11 +214,15 @@ public Baggage(final @NotNull Baggage baggage) {
188214 @ ApiStatus .Internal
189215 public Baggage (
190216 final @ NotNull Map <String , String > keyValues ,
217+ final @ Nullable Double sampleRate ,
218+ final @ Nullable Double sampleRand ,
191219 final @ Nullable String thirdPartyHeader ,
192220 boolean isMutable ,
193221 boolean shouldFreeze ,
194222 final @ NotNull ILogger logger ) {
195223 this .keyValues = keyValues ;
224+ this .sampleRate = sampleRate ;
225+ this .sampleRand = sampleRand ;
196226 this .logger = logger ;
197227 this .thirdPartyHeader = thirdPartyHeader ;
198228 this .mutable = isMutable ;
@@ -231,8 +261,18 @@ public String getThirdPartyHeader() {
231261 }
232262
233263 final Set <String > keys = new TreeSet <>(keyValues .keySet ());
264+ keys .add (DSCKeys .SAMPLE_RATE );
265+ keys .add (DSCKeys .SAMPLE_RAND );
266+
234267 for (final String key : keys ) {
235- final @ Nullable String value = keyValues .get (key );
268+ final @ Nullable String value ;
269+ if (DSCKeys .SAMPLE_RATE .equals (key )) {
270+ value = sampleRateToString (sampleRate );
271+ } else if (DSCKeys .SAMPLE_RAND .equals (key )) {
272+ value = sampleRateToString (sampleRand );
273+ } else {
274+ value = keyValues .get (key );
275+ }
236276
237277 if (value != null ) {
238278 if (listMemberCount >= MAX_BAGGAGE_LIST_MEMBER_COUNT ) {
@@ -271,7 +311,6 @@ public String getThirdPartyHeader() {
271311 }
272312 }
273313 }
274-
275314 return sb .toString ();
276315 }
277316
@@ -353,8 +392,8 @@ public void setTransaction(final @Nullable String transaction) {
353392 }
354393
355394 @ ApiStatus .Internal
356- public @ Nullable String getSampleRate () {
357- return get ( DSCKeys . SAMPLE_RATE ) ;
395+ public @ Nullable Double getSampleRate () {
396+ return sampleRate ;
358397 }
359398
360399 @ ApiStatus .Internal
@@ -363,28 +402,27 @@ public void setTransaction(final @Nullable String transaction) {
363402 }
364403
365404 @ ApiStatus .Internal
366- public void setSampleRate (final @ Nullable String sampleRate ) {
367- set (DSCKeys .SAMPLE_RATE , sampleRate );
368- }
369-
370- @ ApiStatus .Internal
371- public void forceSetSampleRate (final @ Nullable String sampleRate ) {
372- set (DSCKeys .SAMPLE_RATE , sampleRate , true );
405+ public void setSampleRate (final @ Nullable Double sampleRate ) {
406+ if (isMutable ()) {
407+ this .sampleRate = sampleRate ;
408+ }
373409 }
374410
375411 @ ApiStatus .Internal
376- public @ Nullable String getSampleRand ( ) {
377- return get ( DSCKeys . SAMPLE_RAND ) ;
412+ public void forceSetSampleRate ( final @ Nullable Double sampleRate ) {
413+ this . sampleRate = sampleRate ;
378414 }
379415
380416 @ ApiStatus .Internal
381- public void setSampleRand ( final @ Nullable String sampleRand ) {
382- set ( DSCKeys . SAMPLE_RAND , sampleRand ) ;
417+ public @ Nullable Double getSampleRand ( ) {
418+ return sampleRand ;
383419 }
384420
385421 @ ApiStatus .Internal
386- public void setSampleRandDouble (final @ Nullable Double sampleRand ) {
387- setSampleRand (sampleRateToString (sampleRand ));
422+ public void setSampleRand (final @ Nullable Double sampleRand ) {
423+ if (isMutable ()) {
424+ this .sampleRand = sampleRand ;
425+ }
388426 }
389427
390428 @ ApiStatus .Internal
@@ -453,9 +491,9 @@ public void setValuesFromTransaction(
453491 if (replayId != null && !SentryId .EMPTY_ID .equals (replayId )) {
454492 setReplayId (replayId .toString ());
455493 }
456- setSampleRate (sampleRateToString ( sampleRate (samplingDecision ) ));
494+ setSampleRate (sampleRate (samplingDecision ));
457495 setSampled (StringUtils .toString (sampled (samplingDecision )));
458- setSampleRand (sampleRateToString ( sampleRand (samplingDecision ) )); // TODO check
496+ setSampleRand (sampleRand (samplingDecision )); // TODO check
459497 }
460498
461499 @ ApiStatus .Internal
@@ -468,11 +506,11 @@ public void setValuesFromSamplingDecision(
468506 setSampled (StringUtils .toString (sampled (samplingDecision )));
469507
470508 if (samplingDecision .getSampleRand () != null ) {
471- setSampleRand (sampleRateToString ( sampleRand (samplingDecision ) ));
509+ setSampleRand (sampleRand (samplingDecision ));
472510 }
473511
474512 if (samplingDecision .getSampleRate () != null ) {
475- forceSetSampleRate (sampleRateToString ( sampleRate (samplingDecision ) ));
513+ forceSetSampleRate (sampleRate (samplingDecision ));
476514 }
477515 }
478516
@@ -513,10 +551,7 @@ public void setValuesFromScope(
513551 if (!SampleRateUtils .isValidTracesSampleRate (sampleRateAsDouble , false )) {
514552 return null ;
515553 }
516-
517- DecimalFormat df =
518- new DecimalFormat ("#.################" , DecimalFormatSymbols .getInstance (Locale .ROOT ));
519- return df .format (sampleRateAsDouble );
554+ return decimalFormatter .get ().format (sampleRateAsDouble );
520555 }
521556
522557 private static @ Nullable Boolean sampled (@ Nullable TracesSamplingDecision samplingDecision ) {
@@ -533,17 +568,8 @@ private static boolean isHighQualityTransactionName(
533568 && !TransactionNameSource .URL .equals (transactionNameSource );
534569 }
535570
536- @ ApiStatus .Internal
537- public @ Nullable Double getSampleRateDouble () {
538- return toDouble (getSampleRate ());
539- }
540-
541- @ ApiStatus .Internal
542- public @ Nullable Double getSampleRandDouble () {
543- return toDouble (getSampleRand ());
544- }
545-
546- private @ Nullable Double toDouble (final @ Nullable String stringValue ) {
571+ @ Nullable
572+ private static Double toDouble (final @ Nullable String stringValue ) {
547573 if (stringValue != null ) {
548574 try {
549575 double doubleValue = Double .parseDouble (stringValue );
@@ -573,10 +599,10 @@ public TraceContext toTraceContext() {
573599 getEnvironment (),
574600 getUserId (),
575601 getTransaction (),
576- getSampleRate (),
602+ sampleRateToString ( getSampleRate () ),
577603 getSampled (),
578604 replayIdString == null ? null : new SentryId (replayIdString ),
579- getSampleRand ());
605+ sampleRateToString ( getSampleRand () ));
580606 traceContext .setUnknown (getUnknown ());
581607 return traceContext ;
582608 } else {
0 commit comments