Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨
Internal Changes 🔧Samples
Other
🤖 This preview updates automatically when you update the PR. |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7660 +/- ##
=============================================
+ Coverage 85.314% 85.356% +0.042%
=============================================
Files 485 486 +1
Lines 28838 28901 +63
Branches 12521 12556 +35
=============================================
+ Hits 24603 24669 +66
+ Misses 4188 4183 -5
- Partials 47 49 +2
... and 5 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b9e1a29 | 1216.41 ms | 1255.80 ms | 39.39 ms |
| d68691e | 1221.48 ms | 1248.13 ms | 26.65 ms |
| c424b6a | 1220.38 ms | 1248.18 ms | 27.80 ms |
| 5b1e2a1 | 1217.63 ms | 1245.49 ms | 27.86 ms |
| c58a1c5 | 1229.49 ms | 1251.19 ms | 21.70 ms |
| 2e5230b | 1207.41 ms | 1240.41 ms | 33.00 ms |
| b0c71c8 | 1206.29 ms | 1242.13 ms | 35.84 ms |
| 3461f50 | 1228.08 ms | 1263.37 ms | 35.29 ms |
| 7e30a5e | 1214.57 ms | 1247.78 ms | 33.21 ms |
| 1b18a2d | 1210.42 ms | 1243.47 ms | 33.05 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b9e1a29 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| d68691e | 24.14 KiB | 1.12 MiB | 1.09 MiB |
| c424b6a | 24.14 KiB | 1.06 MiB | 1.04 MiB |
| 5b1e2a1 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| c58a1c5 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| 2e5230b | 24.14 KiB | 1.04 MiB | 1.02 MiB |
| b0c71c8 | 24.14 KiB | 1.08 MiB | 1.06 MiB |
| 3461f50 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| 7e30a5e | 24.14 KiB | 1.10 MiB | 1.08 MiB |
| 1b18a2d | 24.14 KiB | 1.10 MiB | 1.07 MiB |
Previous results on branch: feat/standalone-app-start-tracing
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 92fb0d9 | 1198.41 ms | 1215.74 ms | 17.33 ms |
| c1f77f9 | 1220.31 ms | 1242.54 ms | 22.23 ms |
| 8b737d8 | 1222.43 ms | 1252.96 ms | 30.53 ms |
| edbdb50 | 1217.06 ms | 1249.92 ms | 32.86 ms |
| 0d2ca60 | 1229.17 ms | 1261.09 ms | 31.91 ms |
| 9175efb | 1219.83 ms | 1239.50 ms | 19.67 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 92fb0d9 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| c1f77f9 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| 8b737d8 | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| edbdb50 | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| 0d2ca60 | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| 9175efb | 24.14 KiB | 1.12 MiB | 1.10 MiB |
philipphofmann
left a comment
There was a problem hiding this comment.
Review for Claude Code.
.../SentryTests/Integrations/Performance/AppStartTracking/AppStartMeasurementHandlerTests.swift
Outdated
Show resolved
Hide resolved
.../SentryTests/Integrations/Performance/AppStartTracking/AppStartMeasurementHandlerTests.swift
Outdated
Show resolved
Hide resolved
Sentry Build Distribution
|
Sentry Build Distribution
|
Sentry Build Distribution
|
Sentry Build Distribution
|
…vider Move the app start measurement retrieval logic from SentryTracer into a standalone SentryAppStartMeasurementProvider class to decouple it from the tracer and prepare for a future Swift rewrite. Agent transcript: https://claudescope.sentry.dev/share/-ySeYAQr0t_-TzVJYh7grS4nvSpo6f1NKAIEUc4__60
Call SentryAppStartMeasurementProvider.reset() directly from ClearTestState and the provider tests instead of routing through SentryTracer's forwarding method. Agent transcript: https://claudescope.sentry.dev/share/L1InLC1w4Xm6HgEp2bHk-sJ2wtr9fRfQ08BpwGE4JSs
Remove unused profilerReferenceID parameter, add header docs, and fix stale TSan suppression. Agent transcript: https://claudescope.sentry.dev/share/YCbJaiw4eo47tyRGdPdNfyWa3VZueptJtPoevH1S97A
Fix trailing closure ambiguity with DispatchWorkItem and remove non-existent profilerReferenceID parameter. Agent transcript: https://claudescope.sentry.dev/share/boilLz21_S-f8uu_dcXvext-dAi2MAY8xkbK2zEafW4
Add experimental option to send standalone app start transactions instead of attaching app start data to the first UIViewController transaction. Uses a strategy pattern via AppStartMeasurementHandler protocol. The standalone handler is currently a no-op placeholder; actual transaction logic will be added in a follow-up. Refs: #6883 Agent transcript: https://claudescope.sentry.dev/share/KZR39vRrsVDqgpm56ONILZFlu1u_gpBhAnK7QrpyOH0
Create a real tracer with app.start.cold/warm operation that reuses the existing tracer pipeline for span building, measurements, context, debug images, and profiling. - Add SentrySpanOperationAppStartCold/Warm constants - Relax getAppStartMeasurement to accept app start ops - Skip intermediate root span for standalone transactions - Enable option in iOS sample app for validation Refs: #6883 Agent transcript: https://claudescope.sentry.dev/share/UaCuhStnxjQCwKH46hOsPqgeHsckPh15A0Flqw8JOPc
Move the standalone app start detection from SentryBuildAppStartSpans to SentryTracer and pass it as a BOOL parameter. Use span operation constants instead of string literals. Agent transcript: https://claudescope.sentry.dev/share/QyuEyImC81GP83tCrqUbp939ejQ3-3y_0TcwnvcejsA
Deduplicate the app start operation check in SentryTracer into a single method reused in toTransaction and getAppStartMeasurement. Agent transcript: https://claudescope.sentry.dev/share/bffTUQ5TAcp6oTyLqR8SSSjLLG4pSUsZ8l7TB7qaq1s
Also verify the trace origin is auto.app_start to more precisely identify standalone app start transactions. Agent transcript: https://claudescope.sentry.dev/share/HhoCIcB8Nh0dEd16RtFdllS_ZIxK393KCEPaOUiPp5s
Add StandaloneAppStartTransactionHelper to centralize the logic for identifying standalone app start transactions next to the code that creates them. Agent transcript: https://claudescope.sentry.dev/share/th338Y1YxxM5471m3BNGV5Az6QKNTNQzAyhCyZ9MmuM
Avoids race conditions with global static by passing the measurement directly to the tracer. Agent transcript: https://claudescope.sentry.dev/share/5dFraoe7qfSofcTRtjfi59JzjPmHtWPyBK9YLzp61_g
- Move public functions to top of SentryBuildAppStartSpans.m - Expand SentryTracer comment on race condition avoidance - Use string literals instead of constants in tests - Assert specific debug image properties in test - Add span tree examples to header doc comments Agent transcript: https://claudescope.sentry.dev/share/4RQyqJ6qxJ3uLrCpOW-w1LjUpmtGerVFCS6DIZgKRXE
The platform guards for app start cleanup in clearTestState were missing os(visionOS), causing appStartMeasurementRead to never reset between tests on visionOS. This made tests that depend on app start measurement data fail when run after other tests that consume the measurement. Agent transcript: https://claudescope.sentry.dev/share/XRVuiHsfZrr_PPrwGDvT9RkHPcp6AxGP1tIDaq2H4CU
5378661 to
027eef2
Compare
Reorder static helpers before public functions so forward declarations are unnecessary. Agent transcript: https://claudescope.sentry.dev/share/YxFRa6oUZjO-FbIdZ6tJm3NS3crlLEOkaJhSoyTlnnI
Group it with the other SENTRY_HAS_UIKIT methods at the bottom of the file. Agent transcript: https://claudescope.sentry.dev/share/l1p-jS5wvAvglbGGB7D_m6tnGYaagdHBQCTAddXclW0
- Protocol: AppStartMeasurementHandler → AppStartReportingStrategy - AttachAppStartMeasurementHandler → AttachToTransactionStrategy - SendStandaloneAppStartTransaction → StandaloneTransactionStrategy - Method: handle() → report() - Variable: measurementHandler → reportingStrategy
- Fix trailing slash typo in changelog entry - Restore enableUncaughtNSExceptionReporting in sample app - Make StandaloneAppStartTransactionHelper final - Add test for unknown app start type in StandaloneTransactionStrategy - Restore visionOS platform guard in measurement provider tests - Rename tests to follow test_when_should convention - Remove extra blank line in sentryBuildAppStartSpansInternal
Replace the class-level tearDown with per-test cleanup: - AttachToTransactionStrategy tests: reset app start measurement - StandaloneTransactionStrategy tests: reset current hub - Integration tests: full clearTestState via setUpIntegrationHub - Helper tests: no cleanup needed
- Rename tests to follow test_when_should naming convention - Fix assertion order: value first, expected second - Remove unnecessary force_unwrapping swiftlint disable
Verify the full path from SentryAppStartTracker through StandaloneTransactionStrategy captures a transaction with the correct name and operation, and does not set the global static.
Cover nil config measurement, nil measurement input, unknown start type, enhanced integration assertions, and default feature flag behavior. Agent transcript: https://claudescope.sentry.dev/share/DHthmP4l-WXLLOSec8mR7LkoGRxh5KdqGZSeF3UaXik
Remove enableStandaloneAppStartTracing from sample app since the feature isn't ready for general use yet. Restore visionOS in #endif comment to match the opening platform guard. Agent transcript: https://claudescope.sentry.dev/share/vz0QO06DfJpC3-St_cH3Br5qoqAuE2iHNNDFfK-M7uQ
📜 Description
Send app start data as a standalone transaction instead of attaching it to the first UIViewController transaction.

The measurement is passed directly via
SentryTracerConfiguration, avoiding the global static and its race conditions.We intentionally don't add public user-facing docs for this because this is more of a proof of concept for #6883 that we still need to iterate on before we want a larger audience to try it. The Sentry product doesn't handle these standalone app start transactions yet.
💡 Motivation and Context
Fixes #6883
💚 How did you test it?
enableStandaloneAppStartTracing = falseon this branch and compared againstmain. Both produce identical transaction structure (same operations, same hierarchy:Cold Startgrouping span with 5 child phase spans under theui.loadtransaction). No regression.Regression test run 2 — 2026-03-12T10:42Z
Method
regression-testscope tag to identify each runsearch_events+get_trace_details)Results
regression-test-feature-branch-2regression-test-main-branch-22279393e2bdd4126a29efeda00dd946b7a1bb60029c842fea30b0e289e507b81Cold Start+ 5 phases)Cold Start+ 5 phases)ui.loadui.load¹ The extra span is an unrelated
profileLaunchfile.write, not an app start span.Full span comparison (sorted by duration desc)
ui.loadui.load.initial_displayui.load.full_displayapp.start.coldapp.start.coldhttp.clientapp.start.coldapp.start.coldapp.start.coldui.loadapp.start.coldfile.readfile.writefile.readfile.readfile.readfile.readui.loadui.loadui.loadui.loadui.loadui.loadui.loadui.loadui.loadSentry links
Regression test run 1 — 2026-03-12T09:20Z
Method
regression-testscope tag to identify each runsearch_events+get_trace_details)Results
regression-test-feature-branchregression-test-main-branch3ff1c4e3c3754ab18ece26d7e0cf722a3edc353029d34c9292f5ea85df4851acCold Start+ 5 phases)Cold Start+ 5 phases)ui.loadui.loadFull span comparison (sorted by duration desc)
ui.loadui.load.initial_displayui.load.full_displayapp.start.coldapp.start.coldhttp.clientapp.start.coldapp.start.coldapp.start.coldui.loadapp.start.coldfile.readfile.readfile.readfile.writefile.readui.loadfile.readui.loadui.loadui.loadui.loadui.loadui.loadui.loadui.loadSentry links
Reproducible prompt
📝 Checklist
You have to check all boxes before merging:
sendDefaultPIIis enabled.