feat(flutter): Add standalone app start tracing#3853
Conversation
Opt-in enableStandaloneAppStartTracing sends app start as its own App Start transaction (op app.start) in both trace lifecycles instead of attaching the payload to the initial route's ui.load. Breakdown spans attach directly to the standalone root, each with a dedicated app.start.* operation. Core gains Hub.startIdleSpan(bindToScope:) for detached idle spans plus the new operation constants. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. Features
🤖 This preview updates automatically when you update the PR. |
🚨 Detected changes in high risk code 🚨High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3853 +/- ##
==========================================
- Coverage 87.35% 87.23% -0.12%
==========================================
Files 338 341 +3
Lines 12283 12365 +82
==========================================
+ Hits 10730 10787 +57
- Misses 1553 1578 +25
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
iOS Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0f0a415 | 1228.28 ms | 1233.51 ms | 5.23 ms |
| 5367726 | 1211.00 ms | 1216.73 ms | 5.73 ms |
| f80073a | 1249.75 ms | 1243.52 ms | -6.23 ms |
| d15266b | 1247.42 ms | 1251.29 ms | 3.87 ms |
| 2f63d89 | 1251.67 ms | 1263.94 ms | 12.27 ms |
| bfabaf2 | 1251.72 ms | 1253.38 ms | 1.67 ms |
| 8af916c | 1246.66 ms | 1240.79 ms | -5.87 ms |
| 9441966 | 1239.78 ms | 1254.00 ms | 14.22 ms |
| 54acf91 | 1257.65 ms | 1277.96 ms | 20.31 ms |
| 396cb30 | 1265.06 ms | 1265.73 ms | 0.67 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0f0a415 | 5.83 MiB | 6.28 MiB | 458.16 KiB |
| 5367726 | 5.73 MiB | 6.17 MiB | 455.87 KiB |
| f80073a | 5.73 MiB | 6.18 MiB | 464.26 KiB |
| d15266b | 5.83 MiB | 6.28 MiB | 462.36 KiB |
| 2f63d89 | 5.65 MiB | 6.09 MiB | 446.25 KiB |
| bfabaf2 | 5.53 MiB | 6.01 MiB | 487.95 KiB |
| 8af916c | 5.73 MiB | 6.18 MiB | 463.84 KiB |
| 9441966 | 5.83 MiB | 6.28 MiB | 459.62 KiB |
| 54acf91 | 20.70 MiB | 22.46 MiB | 1.75 MiB |
| 396cb30 | 5.53 MiB | 6.01 MiB | 488.17 KiB |
Register a SentryFeatures.standaloneAppStartTracing feature and call sdk.addFeature() when enableStandaloneAppStartTracing is on, so adoption is tracked in SDK analytics. Co-Authored-By: Claude <noreply@anthropic.com>
Android Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f872f8e | 402.38 ms | 416.20 ms | 13.82 ms |
| de377fd | 572.35 ms | 589.21 ms | 16.87 ms |
| 944b773 | 470.54 ms | 480.18 ms | 9.64 ms |
| d0aa4b6 | 395.66 ms | 393.13 ms | -2.53 ms |
| cba2765 | 405.98 ms | 422.02 ms | 16.04 ms |
| a34fde0 | 393.60 ms | 389.96 ms | -3.65 ms |
| c741aa5 | 360.67 ms | 367.86 ms | 7.19 ms |
| 79df88f | 355.02 ms | 354.26 ms | -0.76 ms |
| f3d7a42 | 358.26 ms | 343.32 ms | -14.94 ms |
| dfcc88b | 387.20 ms | 387.70 ms | 0.50 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f872f8e | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| de377fd | 6.54 MiB | 7.71 MiB | 1.17 MiB |
| 944b773 | 13.93 MiB | 15.00 MiB | 1.06 MiB |
| d0aa4b6 | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| cba2765 | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| a34fde0 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| c741aa5 | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| 79df88f | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| f3d7a42 | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| dfcc88b | 14.55 MiB | 15.87 MiB | 1.31 MiB |
Move standalone app start emission behind lifecycle-specific emitters so NativeAppStartIntegration owns setup-time SDK state and calls the selected emitter directly. Remove the tracker draft because native app start has a single feeder and the integration already guards duplicate timing callbacks. Co-Authored-By: Codex <noreply@openai.com>
Merge origin/feat/standalone-app-start so the local standalone work can fast-forward push without overwriting the remote main merge. Co-Authored-By: Codex <noreply@openai.com>
Move one-way design decisions into the planning skills while keeping implementation mechanics in code-guidelines. Add signal and data mapping to specs so telemetry features make independence and privacy requirements explicit before design. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Move initial ui.load ownership into the display trackers and leave standalone emitters responsible only for detached App Start roots. Keep native app start orchestration in NativeAppStartIntegration and split app-start formatting into static and stream span writers. Refs #3634 Refs #3767 Co-Authored-By: Codex <noreply@openai.com>
|
Will be replaced by another impl |
Adds opt-in standalone native app-start tracing for Flutter. With
options.enableStandaloneAppStartTracingenabled, native app start is emittedas a detached
App Starttransaction with opapp.startand originauto.app.start; with the flag disabled, native app start remains attached tothe initial
ui.loadtransaction.Architecture
This keeps each telemetry signal under one owner:
TimeToDisplayTracker/TimeToDisplayTrackerV2own the initialui.loadroot, TTID/TTFD,
currentDisplay, andreportFullyDisplayedcompatibility.StaticStandaloneAppStartEmitter/StreamStandaloneAppStartEmitterownonly the detached
App Start/app.startroot.NativeAppStartIntegrationowns native source orchestration: first-framecallback registration, duplicate processing guard, native fetch/parse, display
branch invocation, standalone branch invocation, and failure cleanup.
breakdown shape, standalone breakdown shape, app-start type data/attributes,
and finalization-time app-start vitals encoding.
In standalone mode, the
ui.loadroot still tracks TTID/TTFD but no longercarries the app-start measurement or breakdown spans. The standalone root keeps
the current public shape:
The static standalone root deliberately does not use
trimEnd: the explicitnative app-start end timestamp is authoritative, and trimming could let an
out-of-range native span stretch the transaction duration beyond the app-start
measurement.
Scope
This PR is native app start only. Generic standalone app start remains future
work and should reuse the same display-tracker entrypoints and standalone
emitter seam when conventions can represent its app-start type honestly.
#3767 extended app start remains follow-up work. The emitter seam is intended to
support that later by letting the standalone finalization policy evolve; a
session/tracker should be added then only if it owns real lifecycle state such
as extension first-wins behavior, deadline handling, or delayed finalization.
Fixes #3634
Refs #3767