react-native/ReactKit/Base/RCTLog.m

87 lines
3.0 KiB
Objective-C

// Copyright 2004-present Facebook. All Rights Reserved.
#import "RCTLog.h"
#import "RCTBridge.h"
__unsafe_unretained NSString *RCTLogLevels[] = {
@"info",
@"warn",
@"error",
@"mustfix"
};
static void (^RCTInjectedLogFunction)(NSString *msg);
void RCTInjectLogFunction(void (^logFunction)(NSString *msg)) {
RCTInjectedLogFunction = logFunction;
}
static inline NSString *_RCTLogPreamble(const char *file, int lineNumber, const char *funcName)
{
NSString *threadName = [[NSThread currentThread] name];
NSString *fileName=[[NSString stringWithUTF8String:file] lastPathComponent];
if (!threadName || threadName.length <= 0) {
threadName = [NSString stringWithFormat:@"%p", [NSThread currentThread]];
}
return [NSString stringWithFormat:@"[RCTLog][tid:%@][%@:%d]>", threadName, fileName, lineNumber];
}
// TODO (#5906496): // kinda ugly that this is tied to RCTBridge
NSString *RCTLogObjects(NSArray *objects, NSString *level)
{
NSString *str = objects[0];
#if TARGET_IPHONE_SIMULATOR
if ([RCTBridge hasValidJSExecutor]) {
fprintf(stderr, "%s\n", [str UTF8String]); // don't print timestamps and other junk
[RCTBridge log:objects level:level];
} else
#endif
{
// Print normal errors with timestamps when not in simulator.
// Non errors are already compiled out above, so log as error here.
if (RCTInjectedLogFunction) {
RCTInjectedLogFunction(str);
} else {
NSLog(@">\n %@", str);
}
}
return str;
}
// Returns array of objects. First arg is a simple string to print, remaining args
// are objects to pass through to the debugger so they are inspectable in the console.
NSArray *RCTLogFormat(const char *file, int lineNumber, const char *funcName, NSString *format, ...)
{
va_list args;
va_start(args, format);
NSString *preamble = _RCTLogPreamble(file, lineNumber, funcName);
// Pull out NSObjects so we can pass them through as inspectable objects to the js debugger
NSArray *formatParts = [format componentsSeparatedByString:@"%"];
NSMutableArray *objects = [NSMutableArray arrayWithObject:preamble];
BOOL valid = YES;
for (int i = 0; i < formatParts.count; i++) {
if (i == 0) { // first part is always a string
[objects addObject:formatParts[i]];
} else {
if (valid && [formatParts[i] length] && [formatParts[i] characterAtIndex:0] == '@') {
id obj = va_arg(args, id);
[objects addObject:obj ?: @"null"];
[objects addObject:[formatParts[i] substringFromIndex:1]]; // remove formatting char
} else {
// We could determine the type (double, int?) of the va_arg by parsing the formatPart, but for now we just bail.
valid = NO;
[objects addObject:[NSString stringWithFormat:@"unknown object for %%%@", formatParts[i]]];
}
}
}
va_end(args);
va_start(args, format);
NSString *strOut = [preamble stringByAppendingString:[[NSString alloc] initWithFormat:format arguments:args]];
va_end(args);
NSMutableArray *objectsOut = [NSMutableArray arrayWithObject:strOut];
[objectsOut addObjectsFromArray:objects];
return objectsOut;
}