Skip to content

chore(compose): Update SentryTraced to emit a span only for initial composition - #6051

Open
0xadam-brown wants to merge 1 commit into
mainfrom
fix/sentry-traced-one-composition-span
Open

chore(compose): Update SentryTraced to emit a span only for initial composition#6051
0xadam-brown wants to merge 1 commit into
mainfrom
fix/sentry-traced-one-composition-span

Conversation

@0xadam-brown

@0xadam-brown 0xadam-brown commented Sep 3, 2026

Copy link
Copy Markdown
Member

📜 Description

PR updates SentryTraced to:

  1. emit a span only for initial composition, rather than for every composition of the wrapped composable; and
  2. add an origin to ui.render spans, just like we already do for composition spans.

I've also cleaned up use of ImmutableHolder and renamed it to MutableRef in response to @runningcode's reasonable thoughts here.

💡 Motivation and Context

These are behavior changes to follow the fixes in #6049.

⚠️ Item (1):

  • matches the current description we apply to the composition spans' parent ("Jetpack Compose Initial Composition");
  • helps prevent the composition parent from getting overcrowded (see the diagram in the SentryTraced KDoc for why that's the case);
  • reflects (AFAICT) the original intent of #2507; and
  • is what I'd expect developers to actually care about (chime in if you think differently!).

💚 How did you test it?

I had my clanker exercise SentryTraced composables in our sample app and verify the output.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

Fix the currently broken CompositionLocals that lead to the possibility of a stale parent transaction.

@0xadam-brown
0xadam-brown force-pushed the fix/sentry-traced-one-composition-span branch from 0f87b22 to 8b70bf7 Compare September 3, 2026 10:44
@sentry

sentry Bot commented Sep 3, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.55.0 (1) release

⚙️ sentry-android Build Distribution Settings

@0xadam-brown
0xadam-brown force-pushed the fix/sentry-traced-one-composition-span branch from 8b70bf7 to e048a34 Compare September 3, 2026 10:54
?.apply { spanContext.origin = OP_TRACE_ORIGIN }
}

@Immutable internal class ImmutableHolder<T>(var item: T)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The @Immutable annotation wasn't doing anything here as ImmutableHolder isn't snapshot state and we never pass it as an argument to a composable function.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

cc @markushi in case I'm overlooking something^^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

just for my understanding, is snapshot state something that causes a re-render?

@0xadam-brown
0xadam-brown force-pushed the fix/sentry-traced-one-composition-span branch from e048a34 to a110425 Compare September 3, 2026 11:19
@0xadam-brown
0xadam-brown marked this pull request as ready for review September 3, 2026 11:20
Base automatically changed from fix/sentry-traced-dangling-spans to main September 3, 2026 11:30
Comment thread sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryComposeTracing.kt Outdated
val parentRenderingSpan = localSentryRenderingParentSpan.current

val alreadyComposed = remember(parentCompositionSpan) { MutableRef(false) }
val alreadyRendered = remember(parentRenderingSpan) { MutableRef(false) }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Keying on the parent span doesn't actually change anything yet (though the optics are right) because our implementation of the CompositionLocals above caches the transaction seen by the first SentryTraced to enter the composition in the app's process and never lets it go. That means both that:

  1. the parents never change (making our keying on the parent spans here an optics-only update for now), and
  2. once the root transaction finishes, all spans generated by all SentryTraced composables no-op for the remainder of the app process's life.

I'll be fixing (2) in the next PR in this sequence, which will make the parent span keys meaningful.

…omposition

Commit updates SentryTraced to:

- emit a span only for initial composition, rather than for every composition of the wrapped composable; and
- add an origin to ui.render spans, just like we already do for composition spans.

Commit also cleans up use of ImmutableHolder and renames it to MutableRef.
@0xadam-brown
0xadam-brown force-pushed the fix/sentry-traced-one-composition-span branch from 277216f to b9706dc Compare September 3, 2026 12:05

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'll give it a 👍 with the caveat that I'm not a compose expert.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants