Skip to content

Commit 422aa61

Browse files
adinauerclaude
andcommitted
fix(core): Keep remapped session trace baggage mutable
Copying session trace baggage for a transaction now creates mutable baggage so the transaction can populate DSC fields even if the ambient session baggage was already frozen by an earlier outgoing request. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 341ba6b commit 422aa61

3 files changed

Lines changed: 71 additions & 4 deletions

File tree

sentry/src/main/java/io/sentry/Baggage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ public Baggage(final @NotNull Baggage baggage) {
233233
baggage.sampleRate,
234234
sampleRand,
235235
baggage.thirdPartyHeader,
236-
baggage.mutable,
237-
baggage.shouldFreeze,
236+
true,
237+
false,
238238
baggage.logger);
239239
}
240240

sentry/src/test/java/io/sentry/BaggageTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ class BaggageTest {
440440
}
441441

442442
@Test
443-
fun `copy with overrides preserves frozen state`() {
443+
fun `copy with overrides creates mutable baggage`() {
444444
val baggage =
445445
Baggage.fromHeader(
446446
"sentry-sample_rand=0.1,sentry-trace_id=75302ac48a024bde9a3b3734a82e36c8",
@@ -450,7 +450,8 @@ class BaggageTest {
450450

451451
val copy = Baggage.copyWithOverrides(baggage, SentryId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 0.2)
452452

453-
assertFalse(copy.isMutable)
453+
assertTrue(copy.isMutable)
454+
assertFalse(copy.isShouldFreeze)
454455
assertEquals("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", copy.traceId)
455456
assertEquals(0.2, copy.sampleRand!!, 0.0001)
456457
assertEquals("75302ac48a024bde9a3b3734a82e36c8", baggage.traceId)

sentry/src/test/java/io/sentry/ScopesTest.kt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.sentry.test.createTestScopes
2121
import io.sentry.test.initForTest
2222
import io.sentry.util.HintUtils
2323
import io.sentry.util.StringUtils
24+
import io.sentry.util.TracingUtils
2425
import java.io.File
2526
import java.nio.file.Files
2627
import java.util.Queue
@@ -1865,6 +1866,47 @@ class ScopesTest {
18651866
assertNull(transaction.root.spanContext.parentSpanId)
18661867
}
18671868

1869+
@Test
1870+
fun `session trace transaction baggage is populated after scope baggage is frozen`() {
1871+
val scopes = generateScopes {
1872+
it.isEnableSessionTraceLifecycle = true
1873+
it.release = "1.0.0"
1874+
it.environment = "production"
1875+
}
1876+
1877+
scopes.startSession()
1878+
1879+
val sessionTraceId = AtomicReference<SentryId>()
1880+
val sessionSampleRand = AtomicReference<Double>()
1881+
val headersWithoutTransaction =
1882+
TracingUtils.traceIfAllowed(scopes, "https://sentry.io/hello", emptyList(), null)
1883+
assertNotNull(headersWithoutTransaction)
1884+
scopes.configureScope { scope ->
1885+
sessionTraceId.set(scope.propagationContext.traceId)
1886+
sessionSampleRand.set(scope.propagationContext.sampleRand)
1887+
assertFalse(scope.propagationContext.baggage!!.isMutable)
1888+
}
1889+
1890+
val firstTransaction =
1891+
scopes.startTransaction(TransactionContext("first transaction", "ui.load"))
1892+
assertSessionTraceBaggage(
1893+
firstTransaction,
1894+
scopes,
1895+
sessionTraceId.get(),
1896+
sessionSampleRand.get(),
1897+
)
1898+
firstTransaction.finish()
1899+
1900+
val secondTransaction =
1901+
scopes.startTransaction(TransactionContext("second transaction", "ui.action"))
1902+
assertSessionTraceBaggage(
1903+
secondTransaction,
1904+
scopes,
1905+
sessionTraceId.get(),
1906+
sessionSampleRand.get(),
1907+
)
1908+
}
1909+
18681910
@Test
18691911
fun `when startTransaction with bindToScope set to false, transaction is not attached to the scope`() {
18701912
val scopes = generateScopes()
@@ -4408,6 +4450,30 @@ class ScopesTest {
44084450
return createScopes(options)
44094451
}
44104452

4453+
private fun assertSessionTraceBaggage(
4454+
transaction: ITransaction,
4455+
scopes: IScopes,
4456+
sessionTraceId: SentryId,
4457+
sessionSampleRand: Double,
4458+
) {
4459+
assertTrue(transaction is SentryTracer)
4460+
assertEquals(sessionTraceId, transaction.root.spanContext.traceId)
4461+
4462+
val tracingHeaders =
4463+
TracingUtils.traceIfAllowed(scopes, "https://sentry.io/hello", emptyList(), transaction)
4464+
val baggage =
4465+
Baggage.fromHeader(tracingHeaders!!.baggageHeader!!.value, NoOpLogger.getInstance())
4466+
4467+
assertEquals(sessionTraceId.toString(), baggage.traceId)
4468+
assertEquals(transaction.name, baggage.transaction)
4469+
assertEquals("true", baggage.sampled)
4470+
assertEquals(1.0, baggage.sampleRate!!, 0.0001)
4471+
assertEquals(sessionSampleRand, baggage.sampleRand!!, 0.0001)
4472+
assertEquals("key", baggage.publicKey)
4473+
assertEquals("1.0.0", baggage.release)
4474+
assertEquals("production", baggage.environment)
4475+
}
4476+
44114477
private fun getEnabledScopes(
44124478
optionsConfiguration: Sentry.OptionsConfiguration<SentryOptions>? = null
44134479
): Triple<Scopes, ISentryClient, ILogger> {

0 commit comments

Comments
 (0)