getsentry / sentry-react-native

Official Sentry SDK for React Native
https://sentry.io
MIT License
1.56k stars 331 forks source link

How to generate source maps for Hermes iOS #3087

Closed gkartalis closed 1 year ago

gkartalis commented 1 year ago

OS:

Platform:

SDK:

SDK version: 3.2.13

react-native version: 0.69.10

Are you using Expo?

Are you using sentry.io or on-premise?

If you are using sentry.io, please post a link to your issue so we can take a look:

Link to issue

Configuration:

(@sentry/react-native)

  Sentry.init({
    dsn: sentryDSN,
    release: eigenSentryReleaseName(),
    dist: DeviceInfo.getBuildNumber(),
    enableAutoSessionTracking: true,
    autoSessionTracking: true,
    enableOutOfMemoryTracking: false,
    ...props,
  })

I have following issue:

Hello,

we recently upgraded to 0.69.10 in https://github.com/artsy/eigen/

Our issue is that when we are uploading the ios source maps to Sentry they render like this:

Screenshot 2023-05-11 at 17 41 22

They point to a different file than the one that triggered the crash.

The way we bundle and upload the app is that we use fastlane that uses the yarn bundle:ios script which bundles the app and generates the jsbundle and bytecode and finally composing the sourcemaps.

We have this open PR where we are trying to fix it.

Before we enabled hermes iOS souremaps were still off by [x]

Steps to reproduce:

After composing the source maps we upload them to sentry.

when downloading the sourcemap that was uploaded to sentry and the raw stacktrace from the issue and adding it to a stacktrace.txt file in my project and doing the following:

npx metro-symbolicate dist/main.jsbundle.map < stacktrace.txt

it parses the error weirdly and I get something like this:

 npx metro-symbolicate dist/main.jsbundle.map < stacktrace.txt
Error: Sentry test error
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at apply(native)
  at DynamicIslandStagingIndicator(null:null:null)
  at apply(native)
  at DynamicIslandStagingIndicator(null:null:null)
  at apply(native)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at forEach(native)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at apply(native)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)
  at DynamicIslandStagingIndicator(null:null:null)%

Actual result:

Screenshot 2023-05-11 at 17 41 22

Expected result:

Something more readable like:

Error: Sentry test error
  at onPress(/home/circleci/project/src/app/utils/DevMenu.tsx:235:DevMenuButtonItem.props.onPress)
  at onPressWrapped(/home/circleci/project/node_modules/@artsy/palette-mobile/dist/elements/Touchable/Touchable.js:29:onPressWrapped)
  at onPress(/home/circleci/project/node_modules/react-native/Libraries/Components/Touchable/TouchableHighlight.js:207:onPress)
  at _performTransitionSideEffects(/home/circleci/project/node_modules/react-native/Libraries/Pressability/Pressability.js:756:_performTransitionSideEffects)
  at _receiveSignal(/home/circleci/project/node_modules/react-native/Libraries/Pressability/Pressability.js:693:_receiveSignal)
  at onResponderRelease(/home/circleci/project/node_modules/react-native/Libraries/Pressability/Pressability.js:524:responderEventHandlers.onResponderRelease)
  at apply(native)
  at invokeGuardedCallbackImpl(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:22:invokeGuardedCallbackImpl)
  at apply(native)
  at invokeGuardedCallback(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:40:invokeGuardedCallback)
  at apply(native)
  at invokeGuardedCallbackAndCatchFirstError(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:53:invokeGuardedCallbackAndCatchFirstError)
  at executeDispatch(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:73:executeDispatch)
  at executeDispatchesAndReleaseTopLevel(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1125:executeDispatchesAndReleaseTopLevel)
  at forEach(native)
  at forEachAccumulated(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:361:forEachAccumulated)
  at anonymous(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1160:batchedUpdates$argument_0)
  at batchedUpdatesImpl(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:8094:batchedUpdatesImpl)
  at batchedUpdates(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1106:batchedUpdates)
  at _receiveRootNodeIDEvent(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1137:_receiveRootNodeIDEvent)
  at receiveTouches(/home/circleci/project/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1209:ReactNativePrivateInterface.RCTEventEmitter.register$argument_0.receiveTouches)
  at apply(native)
  at __callFunction(/home/circleci/project/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:417:__callFunction)
  at anonymous(/home/circleci/project/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:114:__guard$argument_0)
  at __guard(/home/circleci/project/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:368:__guard)
  at callFunctionReturnFlushedQueue(/home/circleci/project/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:113:callFunctionReturnFlushedQueue)
krystofwoldrich commented 1 year ago

Since both Sentry and metro-symbolicate doesn't generate the correct stack trace, it looks like the uploaded source map is not correct.

If I'm looking correctly you are uploading Hermes bundle and combined source map. My guess is this is the EXTRA_PACKAGER_ARGS case from our docs, try to upload only the packager bundle and source map.

It looks like you are not emitting Hermes source maps during the build. This has a side effect -> only the packager source map will work even though you are using Hermes. If you use SOURCEMAP_FILE flag during the build then the Hermes combined source map will work.

gkartalis commented 1 year ago

Still having trouble both locally and with betas. 🤔

Will try to break down what I tried out so far:

As far as I understand we are not using EXTRA_PACKAGER_ARGS so we immediately go under the second case from compile sourcemaps section with the SOURCEMAP_FILE (right?) so all steps are necessary (reminder we have all the steps in three different scripts, run via yarn bundle:ios command on the open PR.

We didn't have the SOURCEMAP_FILE flag before but we added it now to try it out here.

Theoretically that was the thing that should work right?

What we get now though is the following:

debugging locally:

npx metro-symbolicate dist/main.jsbundle.map < stacktrace.txt

// result

Error: Sentry test error
    at onPress (http:null:null:null)
    at onPressWrapped (http:null:null:null)
    at onPress (http:null:null:null)
    at _performTransitionSideEffects (http:null:null:null)
    at _receiveSignal (http:null:null:null)
    at onResponderRelease (http:null:null:null)
    at apply (native)
    at invokeGuardedCallbackProd (http:null:null:null)
    at apply (native)
    at invokeGuardedCallback (http:null:null:null)
    at apply (native)
    at invokeGuardedCallbackAndCatchFirstError (http:null:null:null)
    at executeDispatch (http:null:null:null)
    at executeDispatchesInOrder (http:null:null:null)
    at executeDispatchesAndRelease (http:null:null:null)
    at executeDispatchesAndReleaseTopLevel (http:null:null:null)
    at forEach (native)
    at forEachAccumulated (http:null:null:null)
    at runEventsInBatch (http:null:null:null)
    at runExtractedPluginEventsInBatch (http:null:null:null)
    at anonymous (http:null:null:null)
    at batchedUpdates$1 (http:null:null:null)
    at batchedUpdates (http:null:null:null)
    at _receiveRootNodeIDEvent (http:null:null:null)
    at receiveTouches (http:null:null:null)
    at apply (native)
    at __callFunction (http:null:null:null)
    at anonymous (http:null:null:null)
    at __guard (http:null:null:null)
    at callFunctionReturnFlushedQueue (http:null:null:null)%

Am I on the right direction or did I miss something?

gkartalis commented 1 year ago

On the beta side of things (same process as above) on this event it points to the correct file but it is some lines off.

It should have been DevMenu.tsx:235 but it points to DevMenu.tsx:147

Screenshot 2023-06-02 at 19 14 13

and seems like it generated two events instead of one 🤔 :

first: https://artsynet.sentry.io/issues/4223840389/events/9036f990f05a4c3e8cfda9828f97ccf8/ second: https://artsynet.sentry.io/issues/4178485690/events/475f178216c54920ba84bd282580b0de/

krystofwoldrich commented 1 year ago

@gkartalis Yes, you are definitely on the right path and the steps you have done are correct. Unfortunately, there was a bug in RN 0.69 and you need to explicitly USE_HERMES=true then you should get the stack trace symbolicated by npx metro-symbolicate dist/main.jsbundle.map < stacktrace.txt and the lines should be correct in Sentry too.

gkartalis commented 1 year ago

Tried it out with a fresh beta 🤔.

Adding the USE_HERMES=true flag didn't change anything on sentry. I guess though we are doing the hermes related stuff correctly.

Although for some extra context the problem might be lying somewhere else, before hermes our iOS stacktrace was even more off than it is now. Now it is around 100lines off while before hermes it was pointing a wrong file (only on iOS).

This is an example of how the same event looks like without hermes.

Let me know if I should close this issue.

krystofwoldrich commented 1 year ago

Just to recap after adding export USE_HERMES=true not even the local symbolication showed the correct stack trace?

I've noticed one more difference in your PR how the Xcode bundles the JS and how your script bundles the JS.

In your script, you use index.tests.ios.js but RN uses as entry file index.ios.js, this could be the reason why lines and files are off.

You can use export ENTRY_FILE=index.tests.ios.js in your Xcode project or adjust your scripts.

PS.: Yes, I believe we can close.

gkartalis commented 1 year ago

Thanks a lot! Yes local symbolication works great! Will also try out the export ENTRY_FILE=index.tests.ios.js on the same script and will update! But closing the issue for now!

Thanks a lot for the help @krystofwoldrich

gkartalis commented 1 year ago

@krystofwoldrich just an update 🤦‍♂️ The issue was our entry file. Thanks a lot again! Confirming that it works perfectly now.

Sentry event for ref