feat(replay): Record segment names on Android#3897
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. Features
Fixes
DependenciesDeps
Internal Changes
🤖 This preview updates automatically when you update the PR. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3897 +/- ##
==========================================
+ Coverage 87.36% 91.85% +4.49%
==========================================
Files 338 105 -233
Lines 12282 3806 -8476
==========================================
- Hits 10730 3496 -7234
+ Misses 1552 310 -1242
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
Pull request overview
Adds Android session-replay support for recording span segment names by introducing a new native binding (registerSegmentName) and wiring it into the replay telemetry lifecycle so replay events can later include segment_names for Transaction Summary lookups.
Changes:
- Add
SentryNativeBinding.registerSegmentNameand implement it for Android JNI; other platforms provide a no-op. - Register the segment-root span name during
OnProcessSpaninReplayTelemetryIntegration, with integration tests covering root/child/empty and hook removal onclose(). - Bump Android
sentry-android/sentry-spotlightto8.49.0and regenerate JNI bindings.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/flutter/lib/src/integrations/replay_telemetry_integration.dart | Registers segment-root span names via lifecycle hook for replay telemetry. |
| packages/flutter/lib/src/native/sentry_native_binding.dart | Adds registerSegmentName to the native binding interface. |
| packages/flutter/lib/src/native/java/sentry_native_java.dart | Implements registerSegmentName via JNI and forwards to native replay integration. |
| packages/flutter/lib/src/native/java/binding.dart | Regenerated JNI bindings to include ReplayIntegration.registerSegmentName + related updates. |
| packages/flutter/lib/src/web/sentry_web.dart | Adds no-op registerSegmentName implementation for web binding. |
| packages/flutter/lib/src/native/sentry_native_channel.dart | Adds no-op registerSegmentName for method-channel binding. |
| packages/flutter/lib/src/native/c/sentry_native.dart | Adds no-op registerSegmentName for C/FFI binding. |
| packages/flutter/test/integrations/replay_telemetry_integration_test.dart | Adds unit tests verifying segment-name registration and callback cleanup on close. |
| packages/flutter/test/mocks.mocks.dart | Updates mock native binding with registerSegmentName. |
| packages/flutter/android/build.gradle | Bumps io.sentry:sentry-android and sentry-spotlight to 8.49.0. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e01dcdf to
4c1d390
Compare
Register streaming segment-root names with native replay so replay events include segment_names for Transaction Summary. Uses sentry-android 8.49.0 ReplayController.registerSegmentName. Fixes #3865 Co-Authored-By: Cursor Grok 4.5 <[email protected]> Co-authored-by: Cursor <[email protected]>
4c1d390 to
151a549
Compare
Android Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| fd88186 | 422.07 ms | 469.10 ms | 47.03 ms |
| d5a1225 | 377.37 ms | 366.56 ms | -10.81 ms |
| 1980dca | 354.77 ms | 346.96 ms | -7.82 ms |
| d0371bb | 426.85 ms | 437.14 ms | 10.29 ms |
| bfabaf2 | 408.04 ms | 444.38 ms | 36.34 ms |
| 7b21e8b | 467.74 ms | 466.24 ms | -1.50 ms |
| 2f63d89 | 415.95 ms | 424.21 ms | 8.26 ms |
| 0265ce5 | 406.39 ms | 418.48 ms | 12.09 ms |
| 7cfee3b | 498.78 ms | 516.98 ms | 18.20 ms |
| 6f47800 | 451.04 ms | 509.64 ms | 58.60 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| fd88186 | 13.93 MiB | 15.00 MiB | 1.06 MiB |
| d5a1225 | 14.31 MiB | 15.49 MiB | 1.19 MiB |
| 1980dca | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| d0371bb | 14.31 MiB | 15.62 MiB | 1.31 MiB |
| bfabaf2 | 13.93 MiB | 15.06 MiB | 1.13 MiB |
| 7b21e8b | 13.93 MiB | 15.00 MiB | 1.06 MiB |
| 2f63d89 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| 0265ce5 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| 7cfee3b | 6.54 MiB | 7.70 MiB | 1.17 MiB |
| 6f47800 | 6.54 MiB | 7.69 MiB | 1.15 MiB |
Previous results on branch: feat/android-replay-segment-names
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 4c1d390 | 370.08 ms | 370.52 ms | 0.44 ms |
| e01dcdf | 403.87 ms | 427.02 ms | 23.15 ms |
| e6cedf5 | 357.61 ms | 363.94 ms | 6.33 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 4c1d390 | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| e01dcdf | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| e6cedf5 | 14.55 MiB | 15.87 MiB | 1.31 MiB |
Empty names are already skipped in the Android JNI wrapper. Co-Authored-By: Cursor Grok 4.5 <[email protected]> Co-authored-by: Cursor <[email protected]>
iOS Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 73dca78 | 1246.65 ms | 1265.42 ms | 18.76 ms |
| 3f47ea3 | 1263.90 ms | 1263.87 ms | -0.02 ms |
| d379a16 | 1239.65 ms | 1237.52 ms | -2.13 ms |
| 667e3c4 | 1254.70 ms | 1268.23 ms | 13.52 ms |
| 114239b | 1225.74 ms | 1230.17 ms | 4.43 ms |
| a10aff4 | 1241.67 ms | 1255.02 ms | 13.35 ms |
| 9993fa9 | 1255.60 ms | 1254.31 ms | -1.29 ms |
| dc53d48 | 1252.06 ms | 1255.61 ms | 3.55 ms |
| c1e775e | 1263.08 ms | 1275.32 ms | 12.24 ms |
| 38a22c2 | 1257.60 ms | 1259.71 ms | 2.12 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 73dca78 | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| 3f47ea3 | 5.53 MiB | 5.96 MiB | 444.81 KiB |
| d379a16 | 5.83 MiB | 6.28 MiB | 459.63 KiB |
| 667e3c4 | 5.83 MiB | 6.28 MiB | 459.83 KiB |
| 114239b | 5.53 MiB | 5.96 MiB | 444.85 KiB |
| a10aff4 | 5.53 MiB | 6.00 MiB | 486.71 KiB |
| 9993fa9 | 5.83 MiB | 6.28 MiB | 459.39 KiB |
| dc53d48 | 5.65 MiB | 6.09 MiB | 446.96 KiB |
| c1e775e | 20.70 MiB | 22.46 MiB | 1.75 MiB |
| 38a22c2 | 5.73 MiB | 6.17 MiB | 453.62 KiB |
Previous results on branch: feat/android-replay-segment-names
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| e01dcdf | 1257.02 ms | 1249.51 ms | -7.51 ms |
| e6cedf5 | 1262.89 ms | 1269.87 ms | 6.98 ms |
| 4c1d390 | 1251.05 ms | 1254.33 ms | 3.29 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| e01dcdf | 5.83 MiB | 6.28 MiB | 459.02 KiB |
| e6cedf5 | 5.83 MiB | 6.28 MiB | 460.55 KiB |
| 4c1d390 | 5.83 MiB | 6.28 MiB | 460.54 KiB |
Co-Authored-By: Cursor Grok 4.5 <[email protected]> Co-authored-by: Cursor <[email protected]>
📜 Description
While Android session replay is recording, finishing a streaming segment-root span now registers that span's name with native replay via
ReplayController.registerSegmentName. Replay events can then carrysegment_names, so Transaction Summary can find related replays without relying onsentry.replay.idalone.Non-Android platforms get a no-op on the new binding method. Depends on sentry-android 8.49.0 already on main.
💡 Motivation and Context
Under span streaming, buffer-mode replay often leaves
sentry.replay.idpointing at missing replays, which breaks "query spans by segment name → get replay IDs → fetch replays". Recordingsegment_nameson the replay event sidesteps that.Fixes #3865
Related: getsentry/sentry-java#5763, getsentry/sentry-javascript#21851
💚 How did you test it?
replay_telemetry_integration_test.dart: segment root registers name; child/empty skip; close removes the hook📝 Checklist
sendDefaultPiiis enabled🔮 Next steps
registerSegmentNameAPI exists