Skip to content

fix(profiling): iOS UI profiling on v8#6012

Open
antonis wants to merge 5 commits intomainfrom
antonis/fix-ios-ui-profiling-options
Open

fix(profiling): iOS UI profiling on v8#6012
antonis wants to merge 5 commits intomainfrom
antonis/fix-ios-ui-profiling-options

Conversation

@antonis
Copy link
Copy Markdown
Contributor

@antonis antonis commented Apr 17, 2026

📢 Type of change

  • Bugfix

📜 Description

RNSentryStart.createOptionsWithDictionary — the live iOS init path reached from Sentry.init() via initNativeSdk — does not read _experiments.profilingOptions. The JS wrapper packs profilingOptions into _experiments.profilingOptions (wrapper.ts:306-312) and sends it across the bridge, but on iOS the dictionary is handed to Sentry Cocoa without the configureProfiling callback being installed. profileSessionSampleRate, lifecycle, and startOnAppStart are silently dropped.

The handling exists in SentrySDKWrapper.createOptionsWithDictionary (ios/SentrySDKWrapper.m:103-116), but that method hasn't been part of initNativeSdk's call path since #5582 moved init to RNSentryStart. #5611 then added the profiling block to SentrySDKWrapper (the already-bypassed file) a week later, so the feature has never reached Cocoa through the JS init path in any v8 release.

This PR ports the _experiments.profilingOptions handling to RNSentryStart.createOptionsWithDictionary and adds XCTest coverage — including one test against startWithOptions so the full entry point used by initNativeSdk stays pinned. The positive tests invoke the installed callback on a probe SentryProfileOptions and assert sessionSampleRate, lifecycle, and profileAppStarts all land correctly, so a future incomplete callback regresses loudly.

Scope is intentionally narrow. The same dead SentrySDKWrapper options surface also contains _experiments.enableUnhandledCPPExceptionsV2 handling that is unreached in the same way — that should be ported in a follow-up. (Top-level enableLogs in SentrySDKWrapper is redundant, not broken: Cocoa's SentryOptionsInternal.m:96 already maps it from the raw dictionary.) Cleaning up the dead SentrySDKWrapper.createOptionsWithDictionary / setupWithDictionary (and their tests) is also a good follow-up — the reason this bug shipped is precisely that those dead-code tests kept passing.

💡 Motivation and Context

iOS UI profiling is documented as available for React Native (https://docs.sentry.io/platforms/react-native/profiling/#ui-profiling-experimental), but no profilingOptions set through JS Sentry.init({ _experiments: { profilingOptions: { ... } } }) actually takes effect on iOS in any 8.x release. Users cannot opt into UI profiling via the documented path.

💚 How did you test it?

  • Added four XCTest cases under #pragma mark - RNSentryStart Tests:
    • testStartWithDictionaryInstallsConfigureProfilingFromExperimentsProfilingOptions — pins the full startWithOptions entry point used by initNativeSdk; invokes the installed callback on a probe and asserts all three fields land.
    • testStartCreateOptionsWithDictionaryProfilingOptionsInstallsConfigureProfiling — unit test for the ported block; invokes the callback on a probe and asserts all three fields.
    • testStartCreateOptionsWithDictionaryProfilingOptionsMissingDoesNotInstallConfigureProfiling + …EmptyExperimentsDoesNotInstall… — negative cases.
  • All new tests are guarded by #if SENTRY_TARGET_PROFILING_SUPPORTED matching the implementation in RNSentryExperimentalOptions.m.
  • Locally: yarn build, yarn test (210 passing), yarn circularDepCheck, ./scripts/clang-format.sh lint, yarn lint:android, yarn lint:kotlin all clean. yarn lint:oxlint has 2 pre-existing errors in sentryExpoNativeCheck.ts (unrelated; present on main). Full Cocoa XCTest run relies on CI's simulator.

📝 Checklist

  • I added tests to verify 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.
  • All tests passing
  • No breaking changes

🔮 Next steps

`RNSentryStart.createOptionsWithDictionary` (the live iOS init path
since v8.0.0) did not read `_experiments.profilingOptions`, silently
dropping `profileSessionSampleRate`, `lifecycle`, and `startOnAppStart`.
The handling existed in `SentrySDKWrapper`, but that surface hasn't
been called from `initNativeSdk` since #5582#5611 added the block
to the wrong file.

Port the handling to `RNSentryStart` and add XCTest coverage for the
`startWithOptions` entry point that `initNativeSdk` uses, so this
regression can't slip through again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

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


  • fix(profiling): iOS UI profiling on v8 by antonis in #6012
  • chore(deps): update Android SDK to v8.39.1 by github-actions in #6010
  • chore(deps): update JavaScript SDK to v10.49.0 by github-actions in #6011
  • ci: Integrate Warden for AI-powered PR code review by antonis in #6003
  • chore(lint): Fixes lint issue on main by antonis in #6013
  • feat(expo): Warn when prebuilt native projects are missing Sentry config by alwx in #5984

🤖 This preview updates automatically when you update the PR.

@antonis
Copy link
Copy Markdown
Contributor Author

antonis commented Apr 17, 2026

@sentry review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit dfbadc4. Configure here.

- Rewrite CHANGELOG entry to match the descriptive + PR-link format.
- Strengthen the two positive profiling tests to invoke the installed
  callback on a fresh SentryProfileOptions probe and assert that
  sessionSampleRate, lifecycle, and profileAppStarts land correctly,
  so a future regression that installs an incomplete callback is caught.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@antonis antonis left a comment

Choose a reason for hiding this comment

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

The linter issue should be fixed after #6013

@sentry
Copy link
Copy Markdown

sentry bot commented Apr 17, 2026

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
Sentry RN io.sentry.reactnative.sample 8.8.0 (83) Release

⚙️ sentry-react-native Build Distribution Settings

@github-actions
Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1201.30 ms 1204.27 ms 2.97 ms
Size 3.38 MiB 4.76 MiB 1.38 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3817909+dirty 1210.76 ms 1215.64 ms 4.89 ms
3ce5254+dirty 1217.70 ms 1224.69 ms 6.99 ms
04207c4+dirty 1228.55 ms 1226.04 ms -2.51 ms
7ac3378+dirty 1202.35 ms 1198.31 ms -4.04 ms
5c1e987+dirty 1208.43 ms 1220.72 ms 12.29 ms
0d9949d+dirty 1203.94 ms 1202.27 ms -1.67 ms
4953e94+dirty 1217.41 ms 1223.53 ms 6.12 ms
df5d108+dirty 1207.34 ms 1210.50 ms 3.16 ms
a50b33d+dirty 1207.11 ms 1212.10 ms 5.00 ms
3d377b5+dirty 1201.55 ms 1201.80 ms 0.25 ms

App size

Revision Plain With Sentry Diff
3817909+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3ce5254+dirty 3.38 MiB 4.76 MiB 1.38 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB
7ac3378+dirty 3.38 MiB 4.76 MiB 1.38 MiB
5c1e987+dirty 3.38 MiB 4.73 MiB 1.35 MiB
0d9949d+dirty 3.38 MiB 4.76 MiB 1.38 MiB
4953e94+dirty 3.38 MiB 4.73 MiB 1.35 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
a50b33d+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3d377b5+dirty 3.38 MiB 4.76 MiB 1.38 MiB

@github-actions
Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1217.49 ms 1218.20 ms 0.71 ms
Size 3.38 MiB 4.76 MiB 1.38 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3817909+dirty 1183.90 ms 1187.50 ms 3.60 ms
3ce5254+dirty 1219.93 ms 1221.90 ms 1.96 ms
04207c4+dirty 1191.27 ms 1189.78 ms -1.48 ms
7ac3378+dirty 1213.37 ms 1218.15 ms 4.78 ms
5c1e987+dirty 1204.30 ms 1222.15 ms 17.85 ms
0d9949d+dirty 1211.38 ms 1219.67 ms 8.29 ms
4953e94+dirty 1212.06 ms 1214.83 ms 2.77 ms
df5d108+dirty 1225.90 ms 1220.14 ms -5.76 ms
a50b33d+dirty 1197.74 ms 1197.17 ms -0.57 ms
3d377b5+dirty 1218.48 ms 1219.51 ms 1.03 ms

App size

Revision Plain With Sentry Diff
3817909+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3ce5254+dirty 3.38 MiB 4.76 MiB 1.38 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB
7ac3378+dirty 3.38 MiB 4.76 MiB 1.38 MiB
5c1e987+dirty 3.38 MiB 4.73 MiB 1.35 MiB
0d9949d+dirty 3.38 MiB 4.76 MiB 1.38 MiB
4953e94+dirty 3.38 MiB 4.73 MiB 1.35 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
a50b33d+dirty 3.38 MiB 4.73 MiB 1.35 MiB
3d377b5+dirty 3.38 MiB 4.76 MiB 1.38 MiB

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

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant