30#define OOLOG_POISON_NSLOG 0
51#define SET_CRASH_REPORTER_INFO 1
78static void OONSLogPrintfHandler(NSString *message);
81#error Unknown platform!
87#define kFlushInterval 2.0
99- (void)asyncLogMessage:(NSString *)message;
124#if SET_CRASH_REPORTER_INFO
133 sWriteToStderr = [[NSUserDefaults standardUserDefaults] boolForKey:@"logging-echo-to-stderr"];
149 OOLog(
@"logging.nsLogFilter.install.failed",
@"Failed to install NSLog() filter; system messages will not be logged in log file.");
152 NSRecursiveLock *lock = GSLogLock();
154 _NSLog_printf_handler = OONSLogPrintfHandler;
179 NSRecursiveLock *lock = GSLogLock();
181 _NSLog_printf_handler = NULL;
201#if SET_CRASH_REPORTER_INFO
207 const char *cStr = [[string stringByAppendingString:@"\n"] UTF8String];
213#if SET_CRASH_REPORTER_INFO
223 return [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:sLogFileName];
249 NSString *logPath =
nil;
250 NSString *oldPath =
nil;
251 NSFileManager *fmgr =
nil;
254 if (
self ==
nil) OK = NO;
262 if ([fmgr fileExistsAtPath:logPath])
264 oldPath = [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"];
265 [
fmgr oo_removeItemAtPath:oldPath];
266 if (![fmgr oo_moveItemAtPath:logPath toPath:oldPath])
268 if (![fmgr oo_removeItemAtPath:logPath])
270 NSLog(
@"Log setup: could not move or delete existing log at %@, will log to stdout instead.", logPath);
299 NSString *logPath =
nil;
300 NSFileManager *fmgr =
nil;
315 [threadStateMonitor setName:@"OOLogOutputHandler thread state monitor"];
322 [
NSThread detachNewThreadSelector:@selector(loggerThread) toTarget:
self withObject:nil];
330 [threadStateMonitor release];
334 [threadStateMonitor unlockWithCondition:kConditionWorking];
340 OK = (logPath !=
nil);
346 OK = [
fmgr createFileAtPath:logPath contents:nil attributes:nil];
354 NSLog(
@"Log setup: could not open log at %@, will log to stdout instead.", logPath);
365 NSString *postamble =
nil;
370 postamble = [
NSString stringWithFormat:@"\nClosing log at %@.", [
NSDate date]];
373 [threadStateMonitor lockWhenCondition:kConditionReadyToDealloc];
374 [threadStateMonitor unlock];
388- (void)asyncLogMessage:(NSString *)message
395 message = [
message stringByAppendingString:@"\n"];
399 NSArray *messageComponents = [
message componentsSeparatedByString:@"\n"];
408 flushTimer = [
NSTimer scheduledTimerWithTimeInterval:kFlushInterval target:
self selector:@selector(flushLog) userInfo:nil repeats:NO];
424 NSAutoreleasePool *rootPool =
nil, *pool =
nil;
428 [
NSThread ooSetCurrentThreadName:@"OOLogOutputHandler logging thread"];
432 [threadStateMonitor lock];
433 [threadStateMonitor unlockWithCondition:kConditionWorking];
443 if (!
sSaturated && [message isKindOfClass:[NSData
class]])
450 message =
@"\r\n\r\n\r\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\r\n";
452 message =
@"\n\n\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\n";
454 message = [
message dataUsingEncoding:NSUTF8StringEncoding];
457 [logFile writeData:message];
459 else if ([message isEqual:
@"flush"])
461 [logFile synchronizeFile];
463 else if ([message isEqual:
@"die"])
471 @catch (NSException *exception) {}
476 [threadStateMonitor lock];
477 [threadStateMonitor unlockWithCondition:kConditionReadyToDealloc];
510 CFBundleRef foundationBundle = NULL;
514 foundationBundle = CFBundleGetBundleWithIdentifier(CFSTR(
"com.apple.Foundation"));
515 if (foundationBundle != NULL)
517 getter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR(
"_NSLogCStringFunction"));
518 setter = CFBundleGetFunctionPointerForName(foundationBundle, CFSTR(
"_NSSetLogCStringFunction"));
520 if (getter != NULL && setter != NULL)
539static void OONSLogPrintfHandler(NSString *message)
552 BOOL exists, directory;
553 NSFileManager *fmgr = [NSFileManager defaultManager];
555 exists = [fmgr fileExistsAtPath:path isDirectory:&directory];
557 if (exists && !directory)
559 NSLog(
@"Log setup: expected %@ to be a folder, but it is a file.", path);
564 if (![fmgr oo_createDirectoryAtPath:path attributes:
nil])
566 NSLog(
@"Log setup: could not create folder %@.", path);
578 OSStatus (*CSBackupSetItemExcluded)(NSURL *item, Boolean exclude, Boolean excludeByPath) = NULL;
579 CFBundleRef carbonCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR(
"com.apple.CoreServices.CarbonCore"));
580 if (carbonCoreBundle)
582 CSBackupSetItemExcluded = CFBundleGetFunctionPointerForName(carbonCoreBundle, CFSTR(
"CSBackupSetItemExcluded"));
583 if (CSBackupSetItemExcluded != NULL)
585 (void)CSBackupSetItemExcluded([NSURL fileURLWithPath:path], YES, NO);
592 static NSString *appName =
nil;
593 NSBundle *bundle =
nil;
597 bundle = [NSBundle mainBundle];
598 appName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
599 if (appName ==
nil) appName = [bundle bundleIdentifier];
600 if (appName ==
nil) appName =
@"<unknown application>";
610 static NSString *basePath =
nil;
614 const char *logdirEnv = SDL_getenv(
"OO_LOGSDIR");
618 basePath = [NSString stringWithUTF8String:logdirEnv];
624 basePath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
627 basePath = NSHomeDirectory();
630 basePath = [basePath stringByAppendingPathComponent:@".Oolite"];
634 basePath = NSHomeDirectory();
638 basePath = [basePath stringByAppendingPathComponent:@"Logs"];
643 basePath = [basePath stringByAppendingPathComponent:GetAppName()];
656#if SET_CRASH_REPORTER_INFO
682 char *copy = NULL, *old = NULL;
691 if (copy == NULL)
return;
697 [sCrashReporterInfoLock lock];
701 [sCrashReporterInfoLock unlock];
704 if (old != NULL) free(old);
void OOLogOutputHandlerClose(void)
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