Skip to content

feat: Standalone app start tracing#7660

Merged
itaybre merged 70 commits into
mainfrom
feat/standalone-app-start-tracing
May 20, 2026
Merged

feat: Standalone app start tracing#7660
itaybre merged 70 commits into
mainfrom
feat/standalone-app-start-tracing

Conversation

@philipphofmann

@philipphofmann philipphofmann commented Mar 10, 2026

Copy link
Copy Markdown
Member

📜 Description

Send app start data as a standalone transaction instead of attaching it to the first UIViewController transaction.
Screenshot 2026-03-12 at 11 31 38

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?

  • Unit tests
  • End-to-end regression test: Ran the iOS-Swift sample app on a clean simulator with enableStandaloneAppStartTracing = false on this branch and compared against main. Both produce identical transaction structure (same operations, same hierarchy: Cold Start grouping span with 5 child phase spans under the ui.load transaction). No regression.
Regression test run 2 — 2026-03-12T10:42Z

Method

  1. Added a unique regression-test scope tag to identify each run
  2. Erased the simulator between runs for clean cold starts
  3. Built and launched iOS-Swift on each branch, waited ~15s, stopped the app
  4. Compared transactions via Sentry MCP (search_events + get_trace_details)

Results

Property Feature Branch Main Branch
Tag regression-test-feature-branch-2 regression-test-main-branch-2
Trace ID 2279393e2bdd4126a29efeda00dd946b 7a1bb60029c842fea30b0e289e507b81
Total spans 27 ¹ 26
App start spans 6 (Cold Start + 5 phases) 6 (Cold Start + 5 phases)
Transaction op ui.load ui.load

¹ The extra span is an unrelated profileLaunch file.write, not an app start span.

Full span comparison (sorted by duration desc)

Span Description Operation Feature Branch Main Branch
ErrorsViewController ui.load 1101ms 1051ms
ErrorsViewController initial display ui.load.initial_display 945ms 831ms
ErrorsViewController full display ui.load.full_display 945ms 831ms
Cold Start app.start.cold 945ms 831ms
Pre Runtime Init app.start.cold 465ms 478ms
POST http://localhost:8969/stream http.client 159ms 227ms
Application Init app.start.cold 177ms 139ms
UIKit Init app.start.cold 161ms 92ms
Initial Frame Render app.start.cold 141ms 120ms
loadView ui.load 3ms 5ms
Runtime Init to Pre Main Initializers app.start.cold 2ms 2ms
QmU-DD-itF-view-M6c-EX-0C6.nib file.read 0.7ms 0.5ms
data.data (533 bytes) file.write 0.5ms 0.2ms
Info.plist file.read 0.3ms 0.4ms
Info-8.0+.plist file.read 0.3ms 0.3ms
Sim.Touch.plist file.read 0.3ms 0.3ms
Sim.Pencil.plist file.read 0.2ms 0.3ms
viewDidAppear ui.load 0.3ms 0.2ms
layoutSubViews ui.load 0.2ms 0.2ms
viewDidLoad ui.load 0.2ms 0.2ms
layoutSubViews ui.load 0.2ms 0.2ms
viewWillLayoutSubviews ui.load 0.02ms 0.03ms
viewWillLayoutSubviews ui.load 0.02ms 0.02ms
viewWillAppear ui.load 0.02ms 0.02ms
viewDidLayoutSubviews ui.load 0.02ms 0.02ms
viewDidLayoutSubviews ui.load 0.02ms 0.02ms

Sentry links

Regression test run 1 — 2026-03-12T09:20Z

Method

  1. Added a unique regression-test scope tag to identify each run
  2. Erased the simulator between runs for clean cold starts
  3. Built and launched iOS-Swift on each branch, waited ~15s, stopped the app
  4. Compared transactions via Sentry MCP (search_events + get_trace_details)

Results

Property Feature Branch Main Branch
Tag regression-test-feature-branch regression-test-main-branch
Trace ID 3ff1c4e3c3754ab18ece26d7e0cf722a 3edc353029d34c9292f5ea85df4851ac
Total spans 26 26
App start spans 6 (Cold Start + 5 phases) 6 (Cold Start + 5 phases)
Transaction op ui.load ui.load

Full span comparison (sorted by duration desc)

Span Description Operation Feature Branch Main Branch
ErrorsViewController ui.load 1152ms 1091ms
ErrorsViewController initial display ui.load.initial_display 967ms 887ms
ErrorsViewController full display ui.load.full_display 967ms 920ms
Cold Start app.start.cold 967ms 887ms
Pre Runtime Init app.start.cold 468ms 531ms
POST http://localhost:8969/stream http.client 189ms 206ms
UIKit Init app.start.cold 188ms 102ms
Initial Frame Render app.start.cold 171ms 113ms
Application Init app.start.cold 137ms 138ms
loadView ui.load 4ms 5ms
Runtime Init to Pre Main Initializers app.start.cold 2ms 2ms
QmU-DD-itF-view-M6c-EX-0C6.nib file.read 0.5ms 0.6ms
Info.plist file.read 0.4ms 0.4ms
Info-8.0+.plist file.read 0.3ms 0.3ms
data.data (533 bytes) file.write 0.3ms 0.4ms
Sim.Pencil.plist file.read 0.3ms 0.2ms
layoutSubViews ui.load 0.3ms 0.3ms
Sim.Touch.plist file.read 0.3ms 0.2ms
viewDidAppear ui.load 0.2ms 0.2ms
viewDidLoad ui.load 0.2ms 0.2ms
layoutSubViews ui.load 0.07ms 0.08ms
viewWillLayoutSubviews ui.load 0.03ms 0.03ms
viewWillAppear ui.load 0.02ms 0.02ms
viewWillLayoutSubviews ui.load 0.02ms 0.02ms
viewDidLayoutSubviews ui.load 0.02ms 0.02ms
viewDidLayoutSubviews ui.load 0.02ms 0.02ms

Sentry links

Reproducible prompt
Run an end-to-end regression test for app start tracing. Compare the current branch
(with enableStandaloneAppStartTracing = false) against main to verify no regression
in the UIViewController app start transaction.

Steps:
1. In SentrySDKWrapper.swift, set enableStandaloneAppStartTracing = false and add a
   unique scope tag: scope.setTag(value: "regression-test-feature-branch", key: "regression-test")
2. Erase the iOS simulator (xcrun simctl shutdown <ID> && xcrun simctl erase <ID>),
   boot it, build and run iOS-Swift scheme, wait 15 seconds, stop the app
3. Revert sample app changes, stash, checkout main
4. In SentrySDKWrapper.swift on main, add scope tag:
   scope.setTag(value: "regression-test-main-branch", key: "regression-test")
5. Erase the simulator again, boot, build and run iOS-Swift, wait 15 seconds, stop
6. Revert main changes, checkout back to feature branch, pop stash
7. Use Sentry MCP search_events to find transactions with tag regression-test for
   each branch in project 5428557 (sentry-sdks org)
8. Use get_trace_details and search_events to get all spans for both traces
9. Compare: span count, span operations, span descriptions, hierarchy structure.
   Durations will differ (expected). Everything else should match.
10. Update the PR description "How did you test it?" section with the comparison.

📝 Checklist

You have to check all boxes before merging:

  • 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.

@github-actions

github-actions Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • Standalone app start tracing by philipphofmann in #7660

Internal Changes 🔧

Samples

  • Restructure samples and revert to sample-specific target names by philprime in #7659
  • Restructure iOS-Swift6 sample by philprime in #7656

Other

  • (deps) Update clang-format version by github-actions in #7675

🤖 This preview updates automatically when you update the PR.

@github-actions

github-actions Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against dffab76

@codecov

codecov Bot commented Mar 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.43820% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 85.563%. Comparing base (8180609) to head (dffab76).
⚠️ Report is 15 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...s/AppStartTracking/AppStartReportingStrategy.swift 97.674% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7660       +/-   ##
=============================================
+ Coverage   85.546%   85.563%   +0.017%     
=============================================
  Files          487       489        +2     
  Lines        29660     29835      +175     
  Branches     12889     12949       +60     
=============================================
+ Hits         25373     25528      +155     
- Misses        4237      4257       +20     
  Partials        50        50               
Files with missing lines Coverage Δ
Sources/Sentry/SentryAppStartMeasurementProvider.m 94.230% <100.000%> (+2.338%) ⬆️
Sources/Sentry/SentryBuildAppStartSpans.m 100.000% <100.000%> (ø)
.../SentryDefaultUIViewControllerPerformanceTracker.m 97.784% <100.000%> (+0.007%) ⬆️
Sources/Sentry/SentryPerformanceTracker.m 99.224% <100.000%> (+0.102%) ⬆️
Sources/Sentry/SentryTracer.m 99.049% <100.000%> (+0.791%) ⬆️
Sources/Sentry/SentryTransactionContext.m 83.478% <100.000%> (+2.105%) ⬆️
...es/Swift/Helper/SentryEnabledFeaturesBuilder.swift 100.000% <100.000%> (ø)
...tions/AppStartTracking/SentryAppStartTracker.swift 93.902% <100.000%> (+0.191%) ⬆️
Sources/Swift/Options.swift 100.000% <ø> (ø)
Sources/Swift/SentryDependencyContainer.swift 97.285% <100.000%> (+0.012%) ⬆️
... and 2 more

... and 7 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8180609...dffab76. Read the comment docs.

@philipphofmann philipphofmann added the ready-to-merge Use this label to trigger all PR workflows label Mar 10, 2026
@github-actions

github-actions Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1212.32 ms 1247.60 ms 35.29 ms
Size 24.14 KiB 1.16 MiB 1.14 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
786f763 1217.17 ms 1238.37 ms 21.20 ms
909f4ae 1222.85 ms 1253.26 ms 30.41 ms
151b3ee 1238.69 ms 1270.73 ms 32.05 ms
85ee155 1227.40 ms 1251.52 ms 24.12 ms
66415de 1221.21 ms 1253.28 ms 32.07 ms
69745fc 1226.70 ms 1259.72 ms 33.02 ms
dff20e3 1225.19 ms 1258.66 ms 33.47 ms
670aba7 1219.98 ms 1257.20 ms 37.23 ms
da35aa2 1224.21 ms 1249.00 ms 24.79 ms
ec88236 1219.04 ms 1253.69 ms 34.65 ms

App size

Revision Plain With Sentry Diff
786f763 24.14 KiB 1.15 MiB 1.13 MiB
909f4ae 24.14 KiB 1.16 MiB 1.13 MiB
151b3ee 24.14 KiB 1.15 MiB 1.13 MiB
85ee155 24.14 KiB 1.16 MiB 1.13 MiB
66415de 24.14 KiB 1.16 MiB 1.13 MiB
69745fc 24.14 KiB 1.15 MiB 1.13 MiB
dff20e3 24.14 KiB 1.15 MiB 1.13 MiB
670aba7 24.14 KiB 1.16 MiB 1.13 MiB
da35aa2 24.14 KiB 1.15 MiB 1.13 MiB
ec88236 24.14 KiB 1.15 MiB 1.13 MiB

Previous results on branch: feat/standalone-app-start-tracing

Startup times

Revision Plain With Sentry Diff
9175efb 1219.83 ms 1239.50 ms 19.67 ms
7287df6 1224.02 ms 1254.77 ms 30.75 ms
42f95dd 1222.20 ms 1257.02 ms 34.82 ms
0d2ca60 1229.17 ms 1261.09 ms 31.91 ms
50bee10 1228.36 ms 1267.13 ms 38.77 ms
edbdb50 1217.06 ms 1249.92 ms 32.86 ms
89b00b8 1218.33 ms 1255.14 ms 36.81 ms
40d30ad 1234.65 ms 1269.73 ms 35.09 ms
8b737d8 1222.43 ms 1252.96 ms 30.53 ms
98def9b 1216.00 ms 1249.29 ms 33.29 ms

App size

Revision Plain With Sentry Diff
9175efb 24.14 KiB 1.12 MiB 1.10 MiB
7287df6 24.14 KiB 1.16 MiB 1.14 MiB
42f95dd 24.14 KiB 1.16 MiB 1.14 MiB
0d2ca60 24.14 KiB 1.12 MiB 1.10 MiB
50bee10 24.14 KiB 1.16 MiB 1.13 MiB
edbdb50 24.14 KiB 1.12 MiB 1.10 MiB
89b00b8 24.14 KiB 1.16 MiB 1.13 MiB
40d30ad 24.14 KiB 1.16 MiB 1.14 MiB
8b737d8 24.14 KiB 1.12 MiB 1.10 MiB
98def9b 24.14 KiB 1.16 MiB 1.14 MiB

@philipphofmann philipphofmann left a comment

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.

Review for Claude Code.

Comment thread Sources/Sentry/SentryBuildAppStartSpans.m
Comment thread Sources/Sentry/SentryTracer.m Outdated
Comment thread Sources/Sentry/include/SentryBuildAppStartSpans.h
@sentry

sentry Bot commented Mar 10, 2026

Copy link
Copy Markdown

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

@sentry

sentry Bot commented Mar 10, 2026

Copy link
Copy Markdown

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

@sentry

sentry Bot commented Mar 10, 2026

Copy link
Copy Markdown

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.13.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@sentry

sentry Bot commented Mar 10, 2026

Copy link
Copy Markdown

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

Base automatically changed from ref/extract-app-start-measurement-provider to main March 11, 2026 10:44
…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
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
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
itaybre added 2 commits May 11, 2026 18:57
The assertion checked "app.vitals.start.warm.value" which is a span
data key only set in standalone mode. The ui.load transaction uses
"app_start_warm" as its measurement key.
Comment thread Sources/Swift/Integrations/AppStartTracking/AppStartReportingStrategy.swift Outdated
Comment thread Sources/Sentry/SentryPerformanceTracker.m Outdated
Comment thread Sources/Sentry/SentryPerformanceTracker.m
itaybre added 4 commits May 12, 2026 17:18
SentryAppStartMeasurementProvider is only available on UIKit
platforms. Without the guard, macOS builds fail.
Use a named ObjC category (SwiftPrivate) with rawNameSource: to
give a distinct selector, replacing the standalone C functions and
eliminating SentryTransactionContextFactory.h.
Comment thread Sources/Sentry/SentryBuildAppStartSpans.m
@itaybre

itaybre commented May 15, 2026

Copy link
Copy Markdown
Contributor

Example App Start

  • Trace ID is linked to ui.load
  • Has attributes app.vitals.start.screen, app.vitals.start.type, app.vitals.start.warm.value and app.vitals.start.value
image

@philprime philprime left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved so you can move on, but I did leave a couple of feedback points to consider as you believe fit

Comment thread Sources/Sentry/SentryAppStartMeasurementProvider.m
Comment thread Sources/Sentry/SentryDefaultUIViewControllerPerformanceTracker.m
Comment thread Sources/Sentry/SentryPerformanceTracker.m
Comment thread Sources/Sentry/SentrySpanOperation.m
Comment thread CHANGELOG.md Outdated
Comment thread Sources/Sentry/SentryAppStartMeasurementProvider.m Outdated
Comment thread Sources/Sentry/SentryAppStartMeasurementProvider.m

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0e5330b. Configure here.

Comment thread Sources/Sentry/SentryAppStartMeasurementProvider.m
@itaybre
itaybre force-pushed the feat/standalone-app-start-tracing branch from 0e5330b to c3d31c1 Compare May 20, 2026 12:58
The standalone strategy now owns marking the measurement as read,
co-locating the responsibility with the code that consumes it.
@itaybre
itaybre enabled auto-merge (squash) May 20, 2026 14:07
@itaybre
itaybre merged commit 89aaba2 into main May 20, 2026
255 of 258 checks passed
@itaybre
itaybre deleted the feat/standalone-app-start-tracing branch May 20, 2026 14:53
@itaybre
itaybre restored the feat/standalone-app-start-tracing branch May 20, 2026 15:17
itaybre added a commit to getsentry/sentry-docs that referenced this pull request May 28, 2026
## DESCRIBE YOUR PR

Document new experimental option for the Apple/Cocoa SDK and how to
sample standalone app starts

- **`experimental.enableStandaloneAppStartTracing`** (shipped in
[9.14.0](getsentry/sentry-cocoa#7660)): When
enabled, the SDK sends app start data as a dedicated `app.start`
transaction instead of attaching it as spans to the first
UIViewController transaction.

## IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs
to go live.
- [ ] Urgent deadline (GA date, etc.):
- [ ] Other deadline:
- [x] None: Not urgent, can wait up to 1 week+

## SLA

- Teamwork makes the dream work, so please add a reviewer to your PRs.
- Please give the docs team up to 1 week to review your PR unless you've
added an urgent due date to it.
Thanks in advance for your help!

## PRE-MERGE CHECKLIST

*Make sure you've checked the following before merging your changes:*

- [ ] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter
experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs
team](https://github.com/orgs/getsentry/teams/docs)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Send standalone app start transactions

5 participants