Skip to content

Instantly share code, notes, and snippets.

@tianjianchn
Last active July 17, 2023 10:15
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save tianjianchn/af8bdbdf4c19135f505a59d0d637745b to your computer and use it in GitHub Desktop.
Save tianjianchn/af8bdbdf4c19135f505a59d0d637745b to your computer and use it in GitHub Desktop.
Error report util with fabric/crashlytics in react-native
/*global __DEV__*/
import StackTrace from 'stacktrace-js';
const Fabric = require('react-native-fabric');
const { Crashlytics } = Fabric;
//call this to start capturing any no-handled errors
exports.init = function(captrueOnDebugMode){
if (__DEV__ && !captrueOnDebugMode) {
return;
}
const originalHandler = global.ErrorUtils.getGlobalHandler();
function errorHandler(e) {
exports.issue(e)
if (originalHandler) {
originalHandler(e);
}
}
global.ErrorUtils.setGlobalHandler(errorHandler);
}
//user: {id: ,name: ,email: }
exports.setUser = function(user){
const {id, name, email} = {id: 'anony', name: 'anony', email: 'anony', ...user};
Crashlytics.setUserIdentifier(id+'');
Crashlytics.setUserName(name+'');
Crashlytics.setUserEmail(email+'');
}
exports.setAttrs = function(obj){
for(let kk in obj){
exports.setAttr(kk, obj[kk]);
}
}
exports.setAttr = function(key, value){
if(!key) return;
if(typeof key !== 'string') key = key + '';
let type = typeof value;
if(type==='boolean') Crashlytics.setBool(key, value);
else if(type==='number') Crashlytics.setNumber(key, value);
else if(type==='string') Crashlytics.setString(key, value);
else Crashlytics.setString(key, JSON.stringify(value));
}
//things that will be in issue's session logs
exports.log = function(value){
if(!value) return;
if(value instanceof Error){
value = value.stack || value.message;
}
if(typeof value !== 'string') value += '';
return Crashlytics.log(value);
}
//create a new issue. fileName will be the the error message as the `index.bundle.js` is meaningless
exports.issue = function(e){
return StackTrace.fromError(e, {offline: true}).then((stack)=>{
return stack.map(row=>{
let {source, lineNumber} = row;
if(!lineNumber){
lineNumber = parseInt(source.split(':').slice(-2, -1)) || 0
}
return {fileName: e.message, lineNumber, functionName: source}
})
})
.then((stack)=>{
Crashlytics.recordCustomExceptionName(e.message, e.message, stack)
})
}
exports.crash = function(){
return Crashlytics.crash();
}
@antoinerousseau
Copy link

nice gist!
next step: bundle or link the sourcemap \o/

@g6ling
Copy link

g6ling commented Oct 26, 2016

In my case, cannot execute recordCustomExceptionName.
So I changed code like this. This work well in my case, but I don't know this is good idea.

const issue = (e, isFatal, originalHandler) => {
  StackTrace.fromError(e, { offline: true }).then((stack) => (
    stack.map((row) => {
      let { lineNumber } = row;
      const { source } = row;
      if (!lineNumber) {
        lineNumber = parseInt(source.split(':').slice(-2, -1), 10) || 0;
      } return { fileName: e.message, lineNumber, functionName: source };
    })
  )).then((stack) => {
    Crashlytics.recordCustomExceptionName(e.message, e.message, stack);
    originalHandler(e, isFatal, originalHandler);
  });
};

const init() => {
if (__DEV__) {
    return;
  }

  const originalHandler = global.ErrorUtils.getGlobalHandler();
  function errorHandler(e, isFatal) {
    if (originalHandler) {
      issue(e, isFatal, originalHandler);
      // originalHandler(e, isFatal);
    }
    issue(e);
  }
  global.ErrorUtils.setGlobalHandler(errorHandler);
}

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