-
-
Notifications
You must be signed in to change notification settings - Fork 357
feat: v8: Capture app start errors before JS #5582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ructures (#4445) * Extract Android SDK Init * Update tests * Adds changelog * Fix lint issues * Rename RNSentryStart instance for clarity * Converts RNSentryStart to utility class * Update CHANGELOG.md --------- Co-authored-by: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com>
* Convert json object to writable map * Make class/methods package-private(default)
- Resolved merge conflicts across iOS, Android, and JavaScript/TypeScript code - Updated iOS implementation to use RNSentryStart API - Fixed Android compilation errors for Sentry Android SDK v7 compatibility - Removed deprecated API calls (setEnableTracing, getPackages, getIntegrations) - Updated Gradle build scripts and resolved conflict markers - All builds verified: iOS, Android, and Expo sample apps compile successfully
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 206e87e+dirty | 1197.12 ms | 1204.25 ms | 7.13 ms |
| b4fa5b4+dirty | 1213.59 ms | 1211.26 ms | -2.33 ms |
| d6aa223+dirty | 1216.76 ms | 1213.40 ms | -3.37 ms |
| 12fba4a+dirty | 1209.43 ms | 1217.08 ms | 7.65 ms |
| bc8a1ed+dirty | 1198.66 ms | 1200.60 ms | 1.94 ms |
| fa0d109+dirty | 1206.81 ms | 1205.38 ms | -1.43 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 206e87e+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| b4fa5b4+dirty | 3.44 MiB | 4.66 MiB | 1.22 MiB |
| d6aa223+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| 12fba4a+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| bc8a1ed+dirty | 3.44 MiB | 4.66 MiB | 1.22 MiB |
| fa0d109+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
Previous results on branch: antonis/capture-app-start-errors-v8
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 88812b1+dirty | 1210.98 ms | 1215.22 ms | 4.24 ms |
| 82de722+dirty | 1210.87 ms | 1217.00 ms | 6.13 ms |
| b4df5a0+dirty | 1217.06 ms | 1221.61 ms | 4.55 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 88812b1+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| 82de722+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| b4df5a0+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 206e87e+dirty | 1184.11 ms | 1183.19 ms | -0.92 ms |
| b4fa5b4+dirty | 1203.83 ms | 1207.13 ms | 3.30 ms |
| d6aa223+dirty | 1192.33 ms | 1208.17 ms | 15.84 ms |
| 12fba4a+dirty | 1214.20 ms | 1223.30 ms | 9.09 ms |
| bc8a1ed+dirty | 1194.70 ms | 1201.18 ms | 6.48 ms |
| fa0d109+dirty | 1216.02 ms | 1220.67 ms | 4.65 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 206e87e+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| b4fa5b4+dirty | 3.44 MiB | 4.66 MiB | 1.22 MiB |
| d6aa223+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| 12fba4a+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| bc8a1ed+dirty | 3.44 MiB | 4.66 MiB | 1.22 MiB |
| fa0d109+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
Previous results on branch: antonis/capture-app-start-errors-v8
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 88812b1+dirty | 1216.63 ms | 1215.55 ms | -1.08 ms |
| 82de722+dirty | 1213.09 ms | 1208.90 ms | -4.19 ms |
| b4df5a0+dirty | 1213.04 ms | 1218.59 ms | 5.55 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 88812b1+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| 82de722+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
| b4df5a0+dirty | 3.38 MiB | 4.67 MiB | 1.29 MiB |
|
@sentry review |
|
No noticeable impact on iOS, the app size increase by adding sentry on java is interesting though, but no extra impact from this PR. |
That's a good catch @lucas-zimerman 🤔 I wonder if this has to do with the Gradle Plugin bump #5578 on the v8 base branch #5501 |
| [ | ||
| "@sentry/react-native/expo", | ||
| { | ||
| "useNativeInit": true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: Do all sentry options work here? we should document this feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only added option in the plugin. I've started a documentation PR in getsentry/sentry-docs#16170
Looking at it again I think the |
lucas-zimerman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a complete PR review and also loads of tokens, I can really say, LGTM!
# Conflicts: # CHANGELOG.md
|
@sentry review |
* fix(android): Fix ConcurrentModificationException when disabling native crash handling When enableNativeCrashHandling is set to false, the code was iterating over the integrations list with a for-each loop while calling remove() directly, which causes a ConcurrentModificationException at runtime. Fixed by using Java 8's removeIf() method which safely handles iteration and removal in a single operation. This is more concise and follows modern Java best practices. Added unit tests to verify the fix and ensure integrations are properly removed without throwing exceptions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Lint fix --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java
Outdated
Show resolved
Hide resolved
…carUrl The code attempted to read defaultSidecarUrl without checking if the key exists in the options map. This caused a NoSuchKeyException crash during startup when spotlight was set to true in sentry.options.json without providing defaultSidecarUrl. Added key existence check to match iOS implementation behavior and prevent the crash while maintaining backward compatibility. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test(e2e): Add auto init from JS tests for Android Implements Android E2E testing infrastructure to verify both manual native initialization and auto initialization from JavaScript, matching the iOS implementation and resolving issue #4912. Key additions: - Jest configs for android.auto and android.manual test modes - Build scripts that toggle SENTRY_DISABLE_NATIVE_START at compile time - Test scripts to run auto and manual test suites separately - App start crash testing via flag file mechanism - TestControlModule to enable/disable crash-on-start from JS - Comprehensive E2E test documentation Unlike iOS which uses launch arguments at runtime, Android requires separate builds with different build configurations to control native initialization. Closes #4912 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(e2e): Add scrolling to find crash control buttons in Android test The crash control buttons are off-screen, so the Maestro flow needs to scroll to find them before tapping. This matches the pattern used in other Android E2E tests. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(e2e): Make Android crash flag auto-expire after one crash The crash flag file was persisting across app launches, causing the app to crash indefinitely. Now the flag auto-deletes when read, allowing: 1. First launch: Enable flag 2. Second launch: Read flag, delete it, then crash 3. Third launch: Start normally and send crash report This solves the chicken-and-egg problem where the app couldn't reach JavaScript to clear the flag because it kept crashing before JS loaded. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix(e2e): Handle wrapped exceptions in Android crash test Android wraps exceptions thrown in Application.onCreate() with: "Unable to create application... RuntimeException: <original message>" Updated the test to check if ANY exception in the chain contains our intentional crash message, rather than expecting an exact match on the first exception. Test now passes locally and should pass in CI. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Clean up notes for now --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java
Outdated
Show resolved
Hide resolved
# Conflicts: # samples/react-native/android/app/build.gradle
…ions Fixes a crash on Android startup when initializing from sentry.options.json without dsn or devServerUrl fields. The code was calling getString() on ReadableMap without checking if the keys exist first, which throws NoSuchKeyException for missing keys. Both fields are optional in configuration files, so the code now checks for key existence before accessing values, returning null when keys are missing. This matches the pattern used throughout the rest of the file and is already handled correctly by the null-checks in the breadcrumb filter logic. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
<!-- Use this checklist to make sure your PR is ready for merge. You may delete any sections you don't need. --> ## DESCRIBE YOUR PR *Tell us what you're changing and why. If your PR **resolves an issue**, please link it so it closes automatically.* ## 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.): <!-- ENTER DATE HERE --> - [ ] Other deadline: <!-- ENTER DATE HERE --> - [x] None: Not urgent, can wait up to 1 week+ After getsentry/sentry-react-native#5582 is released ## 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) ## LEGAL BOILERPLATE <!-- Sentry employees and contractors can delete or ignore this section. --> Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. ## EXTRA RESOURCES - [Sentry Docs contributor guide](https://docs.sentry.io/contributing/)
📢 Type of change
📜 Description
Follow up to #4472 (v6) > #5470 (v7) targeting v8 #5501
Capture App Start errors and crashes by initializing Sentry from
sentry.options.json(#4472)Create
sentry.options.jsonin the React Native project root and set options the same as you currently have inSentry.initin JS.{ "dsn": "https://key@example.io/value", }Initialize Sentry on the native layers by newly provided native methods.
Add RNSentrySDK APIs support to @sentry/react-native/expo plugin (#4633)
useNativeInitoption to automatically initialize Sentry natively before JavaScript loads, enabling capture of app start errors{ "expo": { "plugins": [ [ "@sentry/react-native/expo", { "useNativeInit": true } ] ] } }Changes
optionsFileinto the JS bundle during Metro bundle process (#4476)startWithConfigureOptionsfor Apple platforms (#4444)initwith optionalOptionsConfiguration<SentryAndroidOptions>for Android (#4451)sentry.options.jsonfor Apple platforms (#4447)sentry.options.jsonfor Android (#4451)Sentry.initoptions in JS (#4510)Internal
Note
The feature the feature should be 100% backwards compatible and opt-in. Users who don't create sentry.options.json or call RNSentrySDK.start()/init() will experience zero changes to their existing Sentry implementation. The traditional JS-only initialization path remains fully functional and is the default behavior.
📝 Documentation PR: getsentry/sentry-docs#16170
💡 Motivation and Context
Fixes #3608
Previously, React Native apps couldn't capture errors that occurred during app startup before JavaScript initialized, because Sentry was only initialized from JavaScript code (Sentry.init()). This meant crashes during:
were never captured.
💚 How did you test it?
CI, Manually
📝 Checklist
sendDefaultPIIis enabled🔮 Next steps
#skip-changelog