Skip to content

Commit 8400a7f

Browse files
authored
fix(compose): Ensure SentryTraced spans respect ignore-by-origin requests (#6058)
Commit fixes a bug where we set span origins for SentryTraced after their creation via the span context, resulting in our ignore-span-origins logic not being able to see them and spans being produced when they should have been ignored / suppressed. What was happening? SentryTracer checks `ignoredSpanOrigins` during span creation, before the returned span can be mutated: ```java if (SpanUtils.isIgnored(scopes.getOptions().getIgnoredSpanOrigins(), spanOptions.getOrigin())) { return NoOpSpan.getInstance(); } ``` That check reads SpanOptions.origin, not the SpanContext.origin we were setting after creation. So if a host app did this... ```kotlin options.setIgnoredSpanOrigins(listOf("auto.ui.jetpack_compose")) ``` ...it would no-op and the Compose spans were created nonetheless. The issue affected both levels of the SentryTraced span hierarchy (ie, both parent spans and child spans).
1 parent 0b2fa67 commit 8400a7f

3 files changed

Lines changed: 45 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Fixes
66

7+
- Update `SentryTraced` so that it now honors `options.setIgnoredSpanOrigins` ([#6058](https://github.com/getsentry/sentry-java/pull/6058))
78
- `SentryTraced` now checks for its owning transaction dynamically rather than once per app process. The latter caused `SentryTraced` spans to be dropped process-wide once the original transaction finished ([#6057](https://github.com/getsentry/sentry-java/pull/6057))
89
- Fix typos in Spring GraphQL integration names (`GrahQL` to `GraphQL`) ([#6061](https://github.com/getsentry/sentry-java/pull/6061))
910

sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryComposeTracing.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,15 @@ private fun recordCompositionSpan(
125125
) {
126126
val bucketSpan = BucketSpans.getOrCreateCompositionSpan(ownerSpan, startTimestamp) ?: return
127127

128-
bucketSpan.startChild(OP_COMPOSITION_SPAN, tag, startTimestamp).apply {
129-
spanContext.origin = OP_TRACE_ORIGIN
130-
finish(null, endTimestamp)
131-
}
128+
bucketSpan
129+
.startChild(
130+
OP_COMPOSITION_SPAN,
131+
tag,
132+
startTimestamp,
133+
Instrumenter.SENTRY,
134+
SpanOptions().apply { origin = OP_TRACE_ORIGIN },
135+
)
136+
.run { finish(null, endTimestamp) }
132137
}
133138

134139
/**
@@ -145,10 +150,15 @@ private fun recordRenderSpan(
145150
) {
146151
val bucketSpan = BucketSpans.getOrCreateRenderSpan(ownerSpan, startTimestamp) ?: return
147152

148-
bucketSpan.startChild(OP_RENDER_SPAN, tag, startTimestamp).apply {
149-
spanContext.origin = OP_TRACE_ORIGIN
150-
finish(null, endTimestamp)
151-
}
153+
bucketSpan
154+
.startChild(
155+
OP_RENDER_SPAN,
156+
tag,
157+
startTimestamp,
158+
Instrumenter.SENTRY,
159+
SpanOptions().apply { origin = OP_TRACE_ORIGIN },
160+
)
161+
.run { finish(null, endTimestamp) }
152162
}
153163

154164
/**
@@ -237,6 +247,7 @@ private class BucketSpans {
237247
startTimestamp,
238248
Instrumenter.SENTRY,
239249
SpanOptions().apply {
250+
origin = OP_TRACE_ORIGIN
240251
isTrimStart = true
241252
isTrimEnd = true
242253
isIdle = true
@@ -246,8 +257,6 @@ private class BucketSpans {
246257
if (bucketSpan.dropsChildSpans) {
247258
return null
248259
}
249-
250-
bucketSpan.spanContext.origin = OP_TRACE_ORIGIN
251260
setCached(WeakReference(bucketSpan))
252261
return bucketSpan
253262
}

sentry-compose/src/androidUnitTest/kotlin/io/sentry/compose/SentryTracedTest.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,26 @@ class SentryTracedTest {
128128
assertThat(tx.countSpans(OP_RENDER)).isEqualTo(0)
129129
}
130130

131+
@Test
132+
fun `does not create spans when origin is ignored`() {
133+
val tx =
134+
initSentryAndStartTransaction("tx") { options ->
135+
options.setIgnoredSpanOrigins(listOf(OP_TRACE_ORIGIN))
136+
}
137+
138+
rule.setContent {
139+
SentryTraced(tag = "product_info") { Box(Modifier.size(1.dp).testTag("content")) }
140+
}
141+
rule.waitForIdle()
142+
drawContent()
143+
144+
rule.onNodeWithTag("content").assertExists()
145+
assertThat(tx.countSpans(OP_PARENT_COMPOSITION)).isEqualTo(0)
146+
assertThat(tx.countSpans(OP_COMPOSE)).isEqualTo(0)
147+
assertThat(tx.countSpans(OP_PARENT_RENDER)).isEqualTo(0)
148+
assertThat(tx.countSpans(OP_RENDER)).isEqualTo(0)
149+
}
150+
131151
@Test
132152
fun `sibling traced composables with the same owner share the composition parent`() {
133153
val tx = initSentryAndStartTransaction("tx")
@@ -381,13 +401,17 @@ class SentryTracedTest {
381401
assertThat(renderingTx.countSpans(OP_RENDER)).isEqualTo(0)
382402
}
383403

384-
private fun initSentryAndStartTransaction(name: String): ITransaction {
404+
private fun initSentryAndStartTransaction(
405+
name: String,
406+
configureOptions: (SentryOptions) -> Unit = {},
407+
): ITransaction {
385408
lateinit var tx: ITransaction
386409
rule.runOnUiThread {
387410
Sentry.init(
388411
{ options: SentryOptions ->
389412
options.dsn = "https://key@sentry.io/proj"
390413
options.tracesSampleRate = 1.0
414+
configureOptions(options)
391415
},
392416
true,
393417
)

0 commit comments

Comments
 (0)