React-native-firebase: Enrich crashlytics stacktrace

Created on 9 Jun 2020  Â·  22Comments  Â·  Source: invertase/react-native-firebase

Documentation Feedback

I have successfully integrated Firebase Crashlytics within my app, but one thing disturbs me.
If you look at the results in the Firebase Console, you see a non-fatal error that I logged.
Schermafbeelding 2020-06-09 om 13 43 08

But what I couldn't find in the documentation is how to modify this. Because every error that I will log will come from io.invertase.firebase.crashlytics.JavaScriptError

In the main overview page with all the errors, you see even less data. All you see is index.android.bundle and a minified function where the error came from (.v). And if it came from an anonymous function, the method is simply .<unknown>.
Schermafbeelding 2020-06-09 om 13 53 42

Is it possible to change these values of the error log? Especially in the main view this is needed, because you won't see the difference between the errors if all you see is a minified function with index.android.bundle.

Thanks in advance.


Most helpful comment

Ok, so i went through the source code of stack-beautifier.

The regex relevant to the format returned by Crashlytics is as follows.
/^at (.*) \((.*)\:(\d+)\:(\d+)\)$/

For those of us who are using crashlytics on android will get the stack trace as txt in the below format:

Non-fatal Exception: io.invertase.firebase.crashlytics.UnhandledPromiseRejection: undefined is not an object (evaluating 'c.bodyString')
       at .<unknown>(index.android.bundle:1730:1890)
       at .p(index.android.bundle:79:423)

We need to pre-process the crashlytics trace file for stack-beautifier to parse it properly. I created a shell script to do this. Save the below code in a file called preprocess.sh

sed -i 's/\s*at/at/g' $1
sed -i 's/(/ (/g' $1
sed -i 's/:0:/:1:/g' $1 # Stack beautifier indexes lines from 1 and not 0

Run this script
bash preprocess.sh <stack trace filename>

Now, we just have to run stack-beautifier.
stack-beautifier <map file name> -t <stack trace filename>

Hope this helps someone in the future.

All 22 comments

Did you keep the sourcemap for your bundle build? Or tag the source so you could regenerate it at that point in time and de-obfuscate? You'll need to map it back in order to get the stack trace you want. None of the crash services that I'm aware of handle react-native / javascript bundle de-obfuscation automatically

I had same problem, trying to de-obfuscate. In this SO post, check the answer that helped us de-obfuscate ios crashlytics logs.

Thanks for a quick reply guys! I understand we can de-obfuscate with the sourcemap of our bundle build. The struggle we have is more about the Firebase Crashlytics overview, which will only show index.android/ios.bundle. So we cannot see any difference between two logs, except the line numbers. But there is nothing to do about this, am i correct @mikehardy?

@angelos3lex thanks for the tip! But stack-beautifier doesn't understand the stacktrace which Firebase Crashlytics gives me. Do you know what i'm doing wrong?


Stack trace

Non-fatal Exception: io.invertase.firebase.crashlytics.JavaScriptError: TEST
at .<unknown>(index.android.bundle:1221:2263)
at .p(index.android.bundle:113:423)
at .<unknown>(index.android.bundle:113:1724)
at .p(index.android.bundle:113:423)
at .o(index.android.bundle:113:900)
at .<unknown>(index.android.bundle:113:1257)
at .c(index.android.bundle:109:205)
at .b(index.android.bundle:109:1623)
at ._(index.android.bundle:109:488)
at .h(index.android.bundle:113:1241)
at ._invoke(index.android.bundle:113:1293)
at .async(index.android.bundle:113:3688)
at .onSelect(index.android.bundle:1221:2181)
at .value(index.android.bundle:1223:28310)
at .touchableHandlePress(index.android.bundle:217:2263)
at .touchableHandlePress([native code]:0:0)
at ._performSideEffectsForTransition(index.android.bundle:208:9675)
at ._performSideEffectsForTransition([native code]:0:0)
at ._receiveSignal(index.android.bundle:208:8357)
at ._receiveSignal([native code]:0:0)
at .touchableHandleResponderRelease(index.android.bundle:208:5645)
at .touchableHandleResponderRelease([native code]:0:0)
at .b(index.android.bundle:91:1197)
at .k(index.android.bundle:91:1340)
at .C(index.android.bundle:91:1394)
at .N(index.android.bundle:91:1692)
at .A(index.android.bundle:91:2482)
at .forEach([native code]:0:0)
at .z(index.android.bundle:91:2282)
at .<unknown>(index.android.bundle:91:13914)
at ._e(index.android.bundle:91:88659)
at .Ne(index.android.bundle:91:13582)
at .Ue(index.android.bundle:91:13755)
at .receiveTouches(index.android.bundle:91:14547)
at .value(index.android.bundle:27:3685)
at .<unknown>(index.android.bundle:27:841)
at .value(index.android.bundle:27:2939)
at .value(index.android.bundle:27:813)
at .value([native code]:0:0)

The package refers to the error here, but I think this is a valid format.

Thanks in advance.

@thomasblom add new line before each at ... i.e:

Non-fatal Exception: io.invertase.firebase.crashlytics.JavaScriptError: TEST 
at .(index.android.bundle:1221:2263)
at .p(index.android.bundle:113:423) 
at .(index.android.bundle:113:1724)

(No need to add all these lines, the first 4-5 at ... lines will most probably be adequate for tracking down the crash, or at least to check for the test)

@angelos3lex Sorry, my previous comment wasn't formatted the right way. I already had new lines (see my edited comment), still getting errors like this:

/usr/local/lib/node_modules/stack-beautifier/stack-beautifier.js:123
        throw new Error(`Stack trace parse error at line ${i + 1}: ${line}`);
        ^

Error: Stack trace parse error at line 2: at .(index.android.bundle:1221:2263)

Do you have any ideas?

@thomasblom I'm not sure, because on firebase console, my trace was like this:

Unhandled JS Exception: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undef..., stack:
Ol@161:86813
<unknown>@161:39525
Hr@161:48370
Cl@161:82658

and then, the outcome of the beautifier was the lines with at ... but each at ... had the actual function name in a normal readable format. So your stack trace seems a little bit different. :( Maybe this is a difference between ios and android obfuscation, and any further step is needed or smthing?!

@angelos3lex It works with a trace like yours, but of course not the right files/lines.
It's weird the package says it supports the format of my stacktrace, but it doesn't. I will look into this. Thanks anyway for your help!

@mikehardy Do you know how I can get JSC stack traces instead of the format i'm getting?

I do not, sorry. I log synthetic analytics "screen" events via react-navigation on each navigation change (the typical pattern to work around react-native using only a single activity) and typically some other data related to session state. That in combination with even objectively terrible stack traces like the above, has been enough for me to quickly inspect code and see the problem in practice so I haven't dug deeper

Feel free to continue the discussion but this isn't an issue with React Native Firebase, so I'm going to go ahead and close it.

Got such error in firebase Console
image

Yeah, I have my first live build out with the with the v8 crashlytics and I see similar on the java side @Daha62 so I can confirm that Firebase Crashlytics (the thing we just migrated to) can generate stacks like this. Why? I'm unsure in my case. I need to verify if I'm actually uploading the deobfuscation files (I may not be) etc.

Can you verify if you have sent all the de-obfuscation files up to firebase etc?

I think this has to do with your project-specific environments.
I'm on the move right now so I can't provide a proper screenshot, but my V8 test crash stack trace is fine:

Fatal Exception: java.lang.RuntimeException: Crash Test
       at io.invertase.firebase.crashlytics.ReactNativeFirebaseCrashlyticsModule$1.run(ReactNativeFirebaseCrashlyticsModule.java:45)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:193)
       at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:225)
       at java.lang.Thread.run(Thread.java:764)

Great, thanks for the success report @andersonaddo I was pretty sure it was my local project, now I know to really focus on that

Hi, will any update for this issue? or this issue has been closed permanently?

I also find my stacktraces is difficult to analyze?

    "@react-native-firebase/analytics": "^6.4.0",
    "@react-native-firebase/app": "^6.4.0",
    "@react-native-firebase/crashlytics": "^6.4.0",
    "@react-native-firebase/dynamic-links": "^6.4.0",
    "@react-native-firebase/messaging": "^6.4.0",
    "@react-native-firebase/perf": "^6.4.0",
    "@react-native-firebase/remote-config": "^6.4.0",
  • Android
    image

  • iOS
    image

@abdullahizzuddiin Firebase Crashlytics knows nothing of javascript stack traces. You will need to post-process javascript stack traces https://stackoverflow.com/questions/62214336/react-native-firebase-crashlytics-deobfuscation/62300702#62300702 was posted above and I think it's useful

There is hope perhaps, it appears that firebase crashlytics has added some ability to add information to stack frames manually which would mean it is maybe possible to construct more informative stack traces from the javascript code https://github.com/firebase/firebase-ios-sdk/issues/5975 - not sure exactly how useful it would be but if someone was interested in advancing this area we could certainly merge related PRs...

Awesome!

stack-beautifier lib worked beautifully on my Android Stacktrace.

But, is there a way to separate issues based on stacktraces?

Look at this pic,
image

So many difference crashes is grouped together on ExceptionsManagerModule.java – line 71: com.facebook.react.modules.core.ExceptionsManagerModule.reportException issue. If we look at the detail, we will find many difference stacktraces (means difference bugs) collected there.

I am happy stack-beautifier worked for you! I am not aware of away to differentiate higher layers of the stack though unfortunately, for the same reason you have to post-process javascript stacks, Firebase simply does not know about differences that are higher than the native layer, yet

There is potential to pass this information to firebase with the APIs I linked above but we don't have that feature now, and it is not under development by us or anyone proposing a PR yet that I know about

Strangely the custom stack traces thing does not appear available on Android. On iOS it was added in pod 6.21.0

https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=ios#customize-stack-traces

Hi @thomasblom did you solve the problem you were facing? I'm having the same issue.

Ok, so i went through the source code of stack-beautifier.

The regex relevant to the format returned by Crashlytics is as follows.
/^at (.*) \((.*)\:(\d+)\:(\d+)\)$/

For those of us who are using crashlytics on android will get the stack trace as txt in the below format:

Non-fatal Exception: io.invertase.firebase.crashlytics.UnhandledPromiseRejection: undefined is not an object (evaluating 'c.bodyString')
       at .<unknown>(index.android.bundle:1730:1890)
       at .p(index.android.bundle:79:423)

We need to pre-process the crashlytics trace file for stack-beautifier to parse it properly. I created a shell script to do this. Save the below code in a file called preprocess.sh

sed -i 's/\s*at/at/g' $1
sed -i 's/(/ (/g' $1
sed -i 's/:0:/:1:/g' $1 # Stack beautifier indexes lines from 1 and not 0

Run this script
bash preprocess.sh <stack trace filename>

Now, we just have to run stack-beautifier.
stack-beautifier <map file name> -t <stack trace filename>

Hope this helps someone in the future.

Was this page helpful?
0 / 5 - 0 ratings