diff --git a/Libraries/AppRegistry/AppRegistry.js b/Libraries/AppRegistry/AppRegistry.js index f36f88132..63bd1d9a0 100644 --- a/Libraries/AppRegistry/AppRegistry.js +++ b/Libraries/AppRegistry/AppRegistry.js @@ -69,7 +69,7 @@ var AppRegistry = { 'Running application "' + appKey + '" with appParams: ' + JSON.stringify(appParameters) + '. ' + '__DEV__ === ' + __DEV__ + - ', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') + + ', development-level warnings are ' + (__DEV__ ? 'ON' : 'OFF') + ', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON') ); invariant( diff --git a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js index c5476eaab..fb57a956a 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js +++ b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js @@ -25,17 +25,11 @@ type Exception = { message: string; } -function handleException(e: Exception) { - var stack = parseErrorStack(e); - console.error( - 'Err0r: ' + - '\n stack: \n' + stackToString(stack) + - '\n URL: ' + e.sourceURL + - '\n line: ' + e.line + - '\n message: ' + e.message - ); - +function reportException(e: Exception, stack?: any) { if (RCTExceptionsManager) { + if (!stack) { + stack = parseErrorStack(e); + } RCTExceptionsManager.reportUnhandledException(e.message, stack); if (__DEV__) { (sourceMapPromise = sourceMapPromise || loadSourceMap()) @@ -50,6 +44,18 @@ function handleException(e: Exception) { } } +function handleException(e: Exception) { + var stack = parseErrorStack(e); + console.log( + 'Error: ' + + '\n stack: \n' + stackToString(stack) + + '\n URL: ' + e.sourceURL + + '\n line: ' + e.line + + '\n message: ' + e.message + ); + reportException(e, stack); +} + function stackToString(stack) { var maxLength = Math.max.apply(null, stack.map(frame => frame.methodName.length)); return stack.map(frame => stackFrameToString(frame, maxLength)).join('\n'); @@ -71,4 +77,4 @@ function fillSpaces(n) { return new Array(n + 1).join(' '); } -module.exports = { handleException }; +module.exports = { handleException, reportException }; diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js index 51f6809cc..bbfee4eb3 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js +++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js @@ -77,6 +77,7 @@ function handleErrorWithRedBox(e) { function setupRedBoxErrorHandler() { var ErrorUtils = require('ErrorUtils'); ErrorUtils.setGlobalHandler(handleErrorWithRedBox); + GLOBAL.reportException = require('ExceptionsManager').reportException; } /** @@ -134,8 +135,8 @@ function setupGeolocation() { } setupDocumentShim(); -setupRedBoxErrorHandler(); setupTimers(); +setupRedBoxErrorHandler(); // needs to happen after setupTimers setupAlert(); setupPromise(); setupXHR(); diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m index 86444dd2a..8f931d96a 100644 --- a/React/Executors/RCTContextExecutor.m +++ b/React/Executors/RCTContextExecutor.m @@ -74,12 +74,12 @@ static JSValueRef RCTNativeLoggingHook(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { if (argumentCount > 0) { - JSStringRef string = JSValueToStringCopy(context, arguments[0], exception); - if (!string) { + JSStringRef messageRef = JSValueToStringCopy(context, arguments[0], exception); + if (!messageRef) { return JSValueMakeUndefined(context); } - NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); - JSStringRelease(string); + NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, messageRef); + JSStringRelease(messageRef); NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: @"( stack: )?([_a-z0-9]*)@?(http://|file:///)[a-z.0-9:/_-]+/([a-z0-9_]+).includeRequire.runModule.bundle(:[0-9]+:[0-9]+)" options:NSRegularExpressionCaseInsensitive @@ -89,14 +89,11 @@ static JSValueRef RCTNativeLoggingHook(JSContextRef context, JSObjectRef object, range:(NSRange){0, message.length} withTemplate:@"[$4$5] \t$2"]; - // TODO: it would be good if log level was sent as a param, instead of this hack RCTLogLevel level = RCTLogLevelInfo; - if ([message rangeOfString:@"error" options:NSCaseInsensitiveSearch].length) { - level = RCTLogLevelError; - } else if ([message rangeOfString:@"warning" options:NSCaseInsensitiveSearch].length) { - level = RCTLogLevelWarning; + if (argumentCount > 1) { + level = MAX(level, JSValueToNumber(context, arguments[1], exception) - 1); } - _RCTLogFormat(level, NULL, -1, @"%@", message); + RCTGetLogFunction()(level, nil, nil, message); } return JSValueMakeUndefined(context); diff --git a/packager/react-packager/src/DependencyResolver/haste/polyfills/console.js b/packager/react-packager/src/DependencyResolver/haste/polyfills/console.js index 91fb970f8..4f513f45b 100644 --- a/packager/react-packager/src/DependencyResolver/haste/polyfills/console.js +++ b/packager/react-packager/src/DependencyResolver/haste/polyfills/console.js @@ -23,7 +23,7 @@ log: 1, info: 2, warn: 3, - error: 4 + error: 4, }; function setupConsole(global) { @@ -35,8 +35,10 @@ function getNativeLogFunction(level) { return function() { var str = Array.prototype.map.call(arguments, function(arg) { - if (arg == null) { - return arg === null ? 'null' : 'undefined'; + if (arg === undefined) { + return 'undefined'; + } else if (arg === null) { + return 'null'; } else if (typeof arg === 'string') { return '"' + arg + '"'; } else { @@ -48,14 +50,18 @@ if (typeof arg.toString === 'function') { try { return arg.toString(); - } catch (E) { - return 'unknown'; - } + } catch (E) {} } + return '["' + typeof arg + '" failed to stringify]'; } } }).join(', '); global.nativeLoggingHook(str, level); + if (global.reportException && level === LOG_LEVELS.error) { + var error = new Error(str); + error.framesToPop = 1; + global.reportException(error); + } }; }