To use the ErrorManager
.
Require the configureErrorManager.js
and to set your user:
ErrorManager.setIdentifier({
id: account.data.id,
email: account.data.email,
full_name: account.data.full_name,
});
const ErrorUtils = require('ErrorUtils'); | |
import { NativeModules } from 'react-native'; | |
import parseErrorStack from 'parseErrorStack'; | |
import _ from 'underscore'; | |
const ErrorManager = NativeModules.ErrorManager; | |
let exceptionID = 0; | |
if (ErrorManager && ErrorUtils._globalHandler) { | |
const previousGlobalHandler = ErrorUtils._globalHandler; | |
const wrapGlobalHandler = (error, isFatal) => { | |
let currentExceptionID = ++exceptionID; | |
const stack = parseErrorStack(error); | |
const timeoutPromise = new Promise((resolve) => { | |
global.setTimeout(() => { | |
resolve(); | |
}, 1000); | |
}); | |
const reportExceptionPromise = new Promise((resolve) => { | |
ErrorManager.reportException(error.message, stack, currentExceptionID, {}, resolve); | |
}); | |
return Promise.race([reportExceptionPromise, timeoutPromise]).then(() => { | |
previousGlobalHandler(error, isFatal); | |
}); | |
}; | |
ErrorUtils.setGlobalHandler(wrapGlobalHandler); | |
} | |
global.notifyError = (error, errorData) => { | |
if (error instanceof Error) { | |
console.log('notifyError', error, errorData); | |
let currentExceptionID = ++exceptionID; | |
const stack = parseErrorStack(error); | |
ErrorManager.reportException( | |
error.message, | |
stack, | |
currentExceptionID, | |
// Make all values string | |
_.mapObject(errorData || {}, (val, key) => (val || 'NULL').toString()), | |
() => {} | |
); | |
} else { | |
console.warn('attempt to call notifyError without an Error', error, errorData); | |
} | |
} |
import com.bugsnag.android.Bugsnag; | |
import com.bugsnag.android.MetaData; | |
import com.bugsnag.android.Severity; | |
import com.facebook.react.bridge.*; | |
import java.io.File; | |
import java.util.HashMap; | |
public class ErrorManager extends ReactContextBaseJavaModule { | |
public ErrorManager(ReactApplicationContext reactContext) { | |
super(reactContext); | |
} | |
@Override | |
public String getName() { | |
return "ErrorManager"; | |
} | |
@ReactMethod | |
public void setIdentifier(ReadableMap params) { | |
if (!BuildConfig.NOTIFY_ERRORS) { return; } | |
Bugsnag.setUser(params.getString("id"), params.getString("email"), params.getString("full_name")); | |
} | |
@ReactMethod | |
public void reportException(String title, ReadableArray details, int exceptionId, ReadableMap errorData, Callback callback) { | |
if (!BuildConfig.NOTIFY_ERRORS) { | |
callback.invoke(); | |
return; | |
} | |
Error error = new Error(title); | |
error.setStackTrace(stackTraceToStackTraceElement(details)); | |
MetaData metaData = new MetaData(); | |
metaData.addToTab("Custom", "Stacktrace", stackTraceToString(details)); | |
ReadableMapKeySetIterator iterator = errorData.keySetIterator(); | |
while (iterator.hasNextKey()) { | |
String key = iterator.nextKey(); | |
metaData.addToTab("Custom", key, errorData.getString(key)); | |
} | |
Bugsnag.notify(title, title, stackTraceToStackTraceElement(details), Severity.ERROR, metaData); | |
callback.invoke(); | |
} | |
private StackTraceElement[] stackTraceToStackTraceElement(ReadableArray stack) { | |
StackTraceElement[] stackTraceElements = new StackTraceElement[stack.size()]; | |
for (int i = 0; i < stack.size(); i++) { | |
ReadableMap frame = stack.getMap(i); | |
stackTraceElements[i] = new StackTraceElement( | |
"ReactJS", | |
frame.getString("methodName"), | |
new File(frame.getString("file")).getName(), | |
frame.getInt("lineNumber") | |
); | |
} | |
return stackTraceElements; | |
} | |
private String stackTraceToString(ReadableArray stack) { | |
StringBuilder stringBuilder = new StringBuilder(); | |
for (int i = 0; i < stack.size(); i++) { | |
ReadableMap frame = stack.getMap(i); | |
stringBuilder.append(frame.getString("methodName")); | |
stringBuilder.append("\n "); | |
stringBuilder.append(new File(frame.getString("file")).getName()); | |
stringBuilder.append(":"); | |
stringBuilder.append(frame.getInt("lineNumber")); | |
if (frame.hasKey("column") && !frame.isNull("column")) { | |
stringBuilder | |
.append(":") | |
.append(frame.getInt("column")); | |
} | |
stringBuilder.append("\n"); | |
} | |
return stringBuilder.toString(); | |
} | |
} |
// | |
// TestRunnerManager.m | |
// Tasker | |
// | |
// Created by Jean-Richard Lai on 8/9/15. | |
// Copyright (c) 2015 TaskRabbit. All rights reserved. | |
// | |
#import "Bugsnag.h" | |
#import "ErrorManager.h" | |
@implementation ErrorManager | |
RCT_EXPORT_MODULE() | |
RCT_EXPORT_METHOD(setIdentifier:(NSDictionary*)attributes) | |
{ | |
#ifdef DEBUG | |
return; | |
#endif | |
[[Bugsnag configuration] setUser:attributes[@"id"] withName:attributes[@"email"] andEmail:attributes[@"full_name"]]; | |
} | |
RCT_EXPORT_METHOD(reportException:(NSString *)message | |
stack:(NSArray<NSDictionary *> *)stack | |
exceptionId:(nonnull NSNumber *)exceptionId | |
errorData:(NSDictionary *)errorData | |
callback:(RCTResponseSenderBlock)callback) | |
{ | |
#ifdef DEBUG | |
callback(@[]); | |
return; | |
#endif | |
NSMutableArray *frameArray = [[NSMutableArray alloc] init]; | |
NSMutableArray *stringFrameArray = [[NSMutableArray alloc] init]; | |
for (NSDictionary *stackFrame in stack) { | |
CLSStackFrame *newStackFrame = [[CLSStackFrame alloc] init]; | |
newStackFrame.fileName = [NSString stringWithFormat:@"%@ @ %zd:%zd", | |
[stackFrame[@"file"] lastPathComponent], | |
[stackFrame[@"lineNumber"] integerValue], | |
[stackFrame[@"column"] integerValue]]; | |
newStackFrame.symbol = stackFrame[@"methodName"]; | |
newStackFrame.library = @"React Native"; | |
newStackFrame.lineNumber = (uint32_t) [stackFrame[@"lineNumber"] integerValue]; | |
newStackFrame.offset = [stackFrame[@"lineNumber"] integerValue]; | |
newStackFrame.address = [stackFrame[@"lineNumber"] integerValue]; | |
[frameArray addObject:newStackFrame]; | |
[stringFrameArray addObject:[NSString stringWithFormat:@"%@ %@", newStackFrame.fileName, newStackFrame.symbol]]; | |
} | |
NSDictionary *userInfo = @{ | |
NSLocalizedDescriptionKey: NSLocalizedString([stringFrameArray componentsJoinedByString:@"\n"], nil), | |
}; | |
NSError *error = [NSError errorWithDomain:message code:-88 userInfo:userInfo]; | |
NSMutableDictionary *allErrorData = [errorData mutableCopy]; | |
[allErrorData addEntriesFromDictionary:@{@"Stacktrace": [stringFrameArray componentsJoinedByString:@"\n"]}]; | |
[Bugsnag notify:[NSException exceptionWithName:message reason:[stringFrameArray componentsJoinedByString:@"\n"] userInfo:userInfo] | |
withData:allErrorData atSeverity:BugsnagSeverityError]; | |
callback(@[]); | |
} | |
@end |