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.");
151#elif GNUSTEP_BASE_LIBRARY
152 NSRecursiveLock *lock = GSLogLock();
154 _NSLog_printf_handler = OONSLogPrintfHandler;
178#elif GNUSTEP_BASE_LIBRARY
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;
258 fmgr = [NSFileManager defaultManager];
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);
277 if (OK) OK = [
self startLogging];
299 NSString *logPath =
nil;
300 NSFileManager *fmgr =
nil;
302 fmgr = [NSFileManager defaultManager];
313 threadStateMonitor = [[NSConditionLock alloc] initWithCondition:kConditionReadyToDealloc];
315 [threadStateMonitor setName:@"OOLogOutputHandler.stateMonitor"];
322 [NSThread detachNewThreadSelector:@selector(loggerThread) toTarget:self withObject:nil];
328 [messageQueue enqueue:@"die"];
330 [threadStateMonitor release];
334 [threadStateMonitor unlockWithCondition:kConditionWorking];
340 OK = (logPath !=
nil);
346 OK = [fmgr createFileAtPath:logPath contents:nil attributes:nil];
349 logFile = [[NSFileHandle fileHandleForWritingAtPath:logPath] retain];
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]];
371 [
self asyncLogMessage:postamble];
372 [messageQueue enqueue:@"die"];
373 [threadStateMonitor lockWhenCondition:kConditionReadyToDealloc];
374 [threadStateMonitor unlock];
388- (void)asyncLogMessage:(NSString *)message
395 message = [message stringByAppendingString:@"\n"];
399 NSArray *messageComponents = [message componentsSeparatedByString:@"\n"];
400 message = [messageComponents componentsJoinedByString:@"\r\n"];
403 [messageQueue enqueue:[message dataUsingEncoding:NSUTF8StringEncoding]];
408 flushTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushInterval target:self selector:@selector(flushLog) userInfo:nil repeats:NO];
417 [messageQueue enqueue:@"flush"];
424 NSAutoreleasePool *rootPool =
nil, *pool =
nil;
427 rootPool = [[NSAutoreleasePool alloc] init];
428 [NSThread ooSetCurrentThreadName:@"loggerThread"];
431 [messageQueue retain];
432 [threadStateMonitor lock];
433 [threadStateMonitor unlockWithCondition:kConditionWorking];
439 pool = [[NSAutoreleasePool alloc] init];
441 message = [messageQueue dequeue];
443 if (!
sSaturated && [message isKindOfClass:[NSData class]])
445 size += [message length];
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) {}
475 [messageQueue release];
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);
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