mirror of
https://github.com/status-im/react-native.git
synced 2025-01-29 02:35:41 +00:00
68bb3a7e71
Summary: @public There have been multiple instances of confusion about whether a redbox means the developer did something they shouldn't but things will keep working, or if something went horribly wrong and the app will crash in prod. This diff introduces an orange background color to the redbox for `console.error` and `RCTLogError` to indicate that something bad happened, but that the app will continue working. Test Plan: see orange error for geo permissions: {F22541375}
187 lines
4.6 KiB
Objective-C
187 lines
4.6 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "RCTAssert.h"
|
|
#import "RCTBridge.h"
|
|
#import "RCTDefines.h"
|
|
#import "RCTRedBox.h"
|
|
|
|
@interface RCTBridge (Logging)
|
|
|
|
+ (void)logMessage:(NSString *)message level:(NSString *)level;
|
|
|
|
@end
|
|
|
|
static NSString *const RCTLogPrefixStack = @"RCTLogPrefixStack";
|
|
|
|
const char *RCTLogLevels[] = {
|
|
"info",
|
|
"warn",
|
|
"error",
|
|
"mustfix"
|
|
};
|
|
|
|
static RCTLogFunction RCTCurrentLogFunction;
|
|
static RCTLogLevel RCTCurrentLogThreshold;
|
|
|
|
__attribute__((constructor))
|
|
static void RCTLogSetup()
|
|
{
|
|
RCTCurrentLogFunction = RCTDefaultLogFunction;
|
|
|
|
#if RCT_DEBUG
|
|
RCTCurrentLogThreshold = RCTLogLevelInfo - 1;
|
|
#else
|
|
RCTCurrentLogThreshold = RCTLogLevelError;
|
|
#endif
|
|
|
|
}
|
|
|
|
RCTLogFunction RCTDefaultLogFunction = ^(
|
|
RCTLogLevel level,
|
|
NSString *fileName,
|
|
NSNumber *lineNumber,
|
|
NSString *message
|
|
)
|
|
{
|
|
NSString *log = RCTFormatLog(
|
|
[NSDate date], level, fileName, lineNumber, message
|
|
);
|
|
fprintf(stderr, "%s\n", log.UTF8String);
|
|
fflush(stderr);
|
|
};
|
|
|
|
void RCTSetLogFunction(RCTLogFunction logFunction)
|
|
{
|
|
RCTCurrentLogFunction = logFunction;
|
|
}
|
|
|
|
RCTLogFunction RCTGetLogFunction()
|
|
{
|
|
return RCTCurrentLogFunction;
|
|
}
|
|
|
|
void RCTAddLogFunction(RCTLogFunction logFunction)
|
|
{
|
|
RCTLogFunction existing = RCTCurrentLogFunction;
|
|
if (existing) {
|
|
RCTCurrentLogFunction = ^(RCTLogLevel level,
|
|
NSString *fileName,
|
|
NSNumber *lineNumber,
|
|
NSString *message) {
|
|
|
|
existing(level, fileName, lineNumber, message);
|
|
logFunction(level, fileName, lineNumber, message);
|
|
};
|
|
} else {
|
|
RCTCurrentLogFunction = logFunction;
|
|
}
|
|
}
|
|
|
|
void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
|
|
{
|
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
|
NSMutableArray *prefixStack = threadDictionary[RCTLogPrefixStack];
|
|
if (!prefixStack) {
|
|
prefixStack = [[NSMutableArray alloc] init];
|
|
threadDictionary[RCTLogPrefixStack] = prefixStack;
|
|
}
|
|
[prefixStack addObject:prefix];
|
|
block();
|
|
[prefixStack removeLastObject];
|
|
}
|
|
|
|
NSString *RCTFormatLog(
|
|
NSDate *timestamp,
|
|
RCTLogLevel level,
|
|
NSString *fileName,
|
|
NSNumber *lineNumber,
|
|
NSString *message
|
|
)
|
|
{
|
|
NSMutableString *log = [[NSMutableString alloc] init];
|
|
if (timestamp) {
|
|
static NSDateFormatter *formatter;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
formatter = [[NSDateFormatter alloc] init];
|
|
formatter.dateFormat = formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS ";
|
|
});
|
|
[log appendString:[formatter stringFromDate:timestamp]];
|
|
}
|
|
if (level) {
|
|
[log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
|
|
}
|
|
|
|
[log appendFormat:@"[tid:%@]", RCTCurrentThreadName()];
|
|
|
|
if (fileName) {
|
|
fileName = [fileName lastPathComponent];
|
|
if (lineNumber) {
|
|
[log appendFormat:@"[%@:%@]", fileName, lineNumber];
|
|
} else {
|
|
[log appendFormat:@"[%@]", fileName];
|
|
}
|
|
}
|
|
if (message) {
|
|
[log appendString:@" "];
|
|
[log appendString:message];
|
|
}
|
|
return log;
|
|
}
|
|
|
|
void _RCTLogFormat(
|
|
RCTLogLevel level,
|
|
const char *fileName,
|
|
int lineNumber,
|
|
NSString *format, ...)
|
|
{
|
|
|
|
BOOL log = RCT_DEBUG || (RCTCurrentLogFunction != nil);
|
|
if (log && level >= RCTCurrentLogThreshold) {
|
|
|
|
// Get message
|
|
va_list args;
|
|
va_start(args, format);
|
|
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
|
va_end(args);
|
|
|
|
// Add prefix
|
|
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
|
|
NSArray *prefixStack = threadDictionary[RCTLogPrefixStack];
|
|
NSString *prefix = [prefixStack lastObject];
|
|
if (prefix) {
|
|
message = [prefix stringByAppendingString:message];
|
|
}
|
|
|
|
// Call log function
|
|
RCTCurrentLogFunction(
|
|
level, fileName ? @(fileName) : nil, (lineNumber >= 0) ? @(lineNumber) : nil, message
|
|
);
|
|
|
|
#if RCT_DEBUG // Red box is only available in debug mode
|
|
|
|
// Log to red box
|
|
if (level >= RCTLOG_REDBOX_LEVEL) {
|
|
if (level < RCTLOG_FATAL_LEVEL) {
|
|
[[RCTRedBox sharedInstance] setNextBackgroundColor:[UIColor colorWithRed:0.9 green:0.4 blue:0.2 alpha:1]];
|
|
}
|
|
[[RCTRedBox sharedInstance] showErrorMessage:message];
|
|
}
|
|
|
|
// Log to JS executor
|
|
[RCTBridge logMessage:message level:level ? @(RCTLogLevels[level - 1]) : @"info"];
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|