30#define OOLOG_POISON_NSLOG 0
50#define SET_CRASH_REPORTER_INFO 1
77static void OONSLogPrintfHandler(NSString *message);
80#error Unknown platform!
86#define kFlushInterval 2.0
98- (void)asyncLogMessage:(NSString *)message;
123#if SET_CRASH_REPORTER_INFO
132 sWriteToStderr = [[NSUserDefaults standardUserDefaults] boolForKey:@"logging-echo-to-stderr"];
148 OOLog(
@"logging.nsLogFilter.install.failed",
@"Failed to install NSLog() filter; system messages will not be logged in log file.");
151 NSRecursiveLock *lock = GSLogLock();
153 _NSLog_printf_handler = OONSLogPrintfHandler;
178 NSRecursiveLock *lock = GSLogLock();
180 _NSLog_printf_handler = NULL;
200#if SET_CRASH_REPORTER_INFO
206 const char *cStr = [[string stringByAppendingString:@"\n"] UTF8String];
212#if SET_CRASH_REPORTER_INFO
222 return [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:sLogFileName];
248 NSString *logPath =
nil;
249 NSString *oldPath =
nil;
250 NSFileManager *fmgr =
nil;
253 if (
self ==
nil) OK = NO;
257 fmgr = [NSFileManager defaultManager];
261 if ([fmgr fileExistsAtPath:logPath])
263 oldPath = [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"];
264 [fmgr oo_removeItemAtPath:oldPath];
265 if (![fmgr oo_moveItemAtPath:logPath toPath:oldPath])
267 if (![fmgr oo_removeItemAtPath:logPath])
269 NSLog(
@"Log setup: could not move or delete existing log at %@, will log to stdout instead.", logPath);
276 if (OK) OK = [
self startLogging];
298 NSString *logPath =
nil;
299 NSFileManager *fmgr =
nil;
301 fmgr = [NSFileManager defaultManager];
312 threadStateMonitor = [[NSConditionLock alloc] initWithCondition:kConditionReadyToDealloc];
314 [threadStateMonitor setName:@"OOLogOutputHandler thread state monitor"];
321 [NSThread detachNewThreadSelector:@selector(loggerThread) toTarget:self withObject:nil];
327 [messageQueue enqueue:@"die"];
329 [threadStateMonitor release];
333 [threadStateMonitor unlockWithCondition:kConditionWorking];
339 OK = (logPath !=
nil);
345 OK = [fmgr createFileAtPath:logPath contents:nil attributes:nil];
348 logFile = [[NSFileHandle fileHandleForWritingAtPath:logPath] retain];
353 NSLog(
@"Log setup: could not open log at %@, will log to stdout instead.", logPath);
364 NSString *postamble =
nil;
369 postamble = [NSString stringWithFormat:@"\nClosing log at %@.", [NSDate date]];
370 [
self asyncLogMessage:postamble];
371 [messageQueue enqueue:@"die"];
372 [threadStateMonitor lockWhenCondition:kConditionReadyToDealloc];
373 [threadStateMonitor unlock];
387- (void)asyncLogMessage:(NSString *)message
394 message = [message stringByAppendingString:@"\n"];
398 NSArray *messageComponents = [message componentsSeparatedByString:@"\n"];
399 message = [messageComponents componentsJoinedByString:@"\r\n"];
402 [messageQueue enqueue:[message dataUsingEncoding:NSUTF8StringEncoding]];
407 flushTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushInterval target:self selector:@selector(flushLog) userInfo:nil repeats:NO];
416 [messageQueue enqueue:@"flush"];
423 NSAutoreleasePool *rootPool =
nil, *pool =
nil;
426 rootPool = [[NSAutoreleasePool alloc] init];
427 [NSThread ooSetCurrentThreadName:@"OOLogOutputHandler logging thread"];
430 [messageQueue retain];
431 [threadStateMonitor lock];
432 [threadStateMonitor unlockWithCondition:kConditionWorking];
438 pool = [[NSAutoreleasePool alloc] init];
440 message = [messageQueue dequeue];
442 if (!
sSaturated && [message isKindOfClass:[NSData
class]])
444 size += [message length];
449 message =
@"\r\n\r\n\r\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\r\n";
451 message =
@"\n\n\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\n";
453 message = [message dataUsingEncoding:NSUTF8StringEncoding];
456 [logFile writeData:message];
458 else if ([message isEqual:
@"flush"])
460 [logFile synchronizeFile];
462 else if ([message isEqual:
@"die"])
470 @catch (NSException *exception) {}
474 [messageQueue release];
475 [threadStateMonitor lock];
476 [threadStateMonitor unlockWithCondition:kConditionReadyToDealloc];
509 CFBundleRef foundationBundle = NULL;
513 foundationBundle = CFBundleGetBundleWithIdentifier(CFSTR(
"com.apple.Foundation"));
514 if (foundationBundle != NULL)
516 getter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR(
"_NSLogCStringFunction"));
517 setter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR(
"_NSSetLogCStringFunction"));
519 if (getter != NULL && setter != NULL)
538static void OONSLogPrintfHandler(NSString *message)
551 BOOL exists, directory;
552 NSFileManager *fmgr = [NSFileManager defaultManager];
554 exists = [fmgr fileExistsAtPath:path isDirectory:&directory];
556 if (exists && !directory)
558 NSLog(
@"Log setup: expected %@ to be a folder, but it is a file.", path);
563 if (![fmgr oo_createDirectoryAtPath:path attributes:
nil])
565 NSLog(
@"Log setup: could not create folder %@.", path);
581 static NSString *basePath =
nil;
586 basePath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
589 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
593 basePath = [basePath stringByAppendingPathComponent:GetAppName()];
606 OSStatus (*CSBackupSetItemExcluded)(NSURL *item, Boolean exclude, Boolean excludeByPath) = NULL;
607 CFBundleRef carbonCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR(
"com.apple.CoreServices.CarbonCore"));
608 if (carbonCoreBundle)
610 CSBackupSetItemExcluded = CFBundleGetFunctionPointerForName(carbonCoreBundle, CFSTR(
"CSBackupSetItemExcluded"));
611 if (CSBackupSetItemExcluded != NULL)
613 (void)CSBackupSetItemExcluded([NSURL fileURLWithPath:path], YES, NO);
621 static NSString *appName =
nil;
622 NSBundle *bundle =
nil;
626 bundle = [NSBundle mainBundle];
627 appName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
628 if (appName ==
nil) appName = [bundle bundleIdentifier];
629 if (appName ==
nil) appName =
@"<unknown application>";
640 static NSString *basePath =
nil;
645 basePath = NSHomeDirectory();
648 basePath = [basePath stringByAppendingPathComponent:@".Oolite"];
652 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
665 static NSString *basePath =
nil;
670 basePath = NSHomeDirectory();
673 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
685#if SET_CRASH_REPORTER_INFO
711 char *copy = NULL, *old = NULL;
720 if (copy == NULL)
return;
726 [sCrashReporterInfoLock lock];
730 [sCrashReporterInfoLock unlock];
733 if (old != NULL) free(old);
static void SetCrashReporterInfo(const char *info)
static LogCStringFunctionSetterProc _NSSetLogCStringFunction
@ kConditionReadyToDealloc
void OOLogOutputHandlerPrint(NSString *string)
static NSString * sLogFileName
static NSString * GetAppName(void)
static char * sOldCrashReporterInfo
void OOLogOutputHandlerStartLoggingToStdout()
NSString * OOLogHandlerGetLogPath(void)
void OOLogOutputHandlerClose(void)
static NSLock * sCrashReporterInfoLock
void OOLogOutputHandlerChangeLogFile(NSString *newLogName)
static LogCStringFunctionGetterProc _NSLogCStringFunction
static LogCStringFunctionProc sDefaultLogCStringFunction
static OOAsyncLogger * sLogger
LogCStringFunctionProc(* LogCStringFunctionGetterProc)(void)
NSString * OOLogHandlerGetLogBasePath(void)
static char ** sCrashReporterInfo
void OOLogOutputHandlerInit(void)
static BOOL sCrashReporterInfoAvailable
static void InitCrashReporterInfo(void)
static BOOL sWriteToStderr
void(* LogCStringFunctionSetterProc)(LogCStringFunctionProc)
static void LoadLogCStringFunctions(void)
static BOOL DirectoryExistCreatingIfNecessary(NSString *path)
static BOOL sWriteToStdout
static void ExcludeFromTimeMachine(NSString *path)
void(* LogCStringFunctionProc)(const char *string, unsigned length, BOOL withSyslogBanner)
void OOLogOutputHandlerStopLoggingToStdout()
static void OONSLogCStringFunction(const char *string, unsigned length, BOOL withSyslogBanner)
#define NSLog(format,...)
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
#define OOLog(class, format,...)
void void OOLogWithFunctionFileAndLine(NSString *inMessageClass, const char *inFunction, const char *inFile, unsigned long inLine, NSString *inFormat,...) OO_TAKES_FORMAT_STRING(5
OOAsyncQueue * messageQueue
void asyncLogMessage:(NSString *message)
NSConditionLock * threadStateMonitor