Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
OOAsyncLogger Class Reference
+ Inheritance diagram for OOAsyncLogger:
+ Collaboration diagram for OOAsyncLogger:

Instance Methods

(void) - asyncLogMessage:
 
(void) - endLogging
 
(void) - changeFile
 
(BOOL) - startLogging
 
(void) - loggerThread
 
(void) - flushLog
 
(id) - init [implementation]
 
(void) - dealloc [implementation]
 

Private Attributes

OOAsyncQueuemessageQueue
 
NSConditionLock * threadStateMonitor
 
NSFileHandle * logFile
 
NSTimer * flushTimer
 

Detailed Description

Definition at line 89 of file OOLogOutputHandler.m.

Method Documentation

◆ asyncLogMessage:

- (void) asyncLogMessage: (NSString *) message

Definition at line 95 of file OOLogOutputHandler.m.

387 :(NSString *)message
388{
389 // Don't log of saturated flag is set.
390 if (sSaturated) return;
391
392 if (message != nil)
393 {
394 message = [message stringByAppendingString:@"\n"];
395
396#if OOLITE_WINDOWS
397 // Convert Unix line endings to Windows ones.
398 NSArray *messageComponents = [message componentsSeparatedByString:@"\n"];
399 message = [messageComponents componentsJoinedByString:@"\r\n"];
400#endif
401
402 [messageQueue enqueue:[message dataUsingEncoding:NSUTF8StringEncoding]];
403
404 if (flushTimer == nil)
405 {
406 // No pending flush
407 flushTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushInterval target:self selector:@selector(flushLog) userInfo:nil repeats:NO];
408 }
409 }
410}
static BOOL sSaturated
return nil

Referenced by OOLogOutputHandlerPrint().

+ Here is the caller graph for this function:

◆ changeFile

- (void) changeFile

Definition at line 95 of file OOLogOutputHandler.m.

381{
382 [self endLogging];
383 if (![self startLogging]) sWriteToStderr = YES;
384}
static BOOL sWriteToStderr

Referenced by OOLogOutputHandlerChangeLogFile().

+ Here is the caller graph for this function:

◆ dealloc

- (void) dealloc
implementation

Definition at line 95 of file OOLogOutputHandler.m.

285{
289 // We don't own a reference to flushTimer.
290
291 [super dealloc];
292}
#define DESTROY(x)
Definition OOCocoa.h:77
OOAsyncQueue * messageQueue
NSFileHandle * logFile
NSConditionLock * threadStateMonitor

◆ endLogging

- (void) endLogging

Definition at line 95 of file OOLogOutputHandler.m.

363{
364 NSString *postamble = nil;
365
367 {
368 // We're fully inited; write postamble, wait for worker thread to terminate cleanly, and close file.
369 postamble = [NSString stringWithFormat:@"\nClosing log at %@.", [NSDate date]];
370 [self asyncLogMessage:postamble];
371 [messageQueue enqueue:@"die"]; // Kill message
372 [threadStateMonitor lockWhenCondition:kConditionReadyToDealloc];
373 [threadStateMonitor unlock];
374
375 [logFile closeFile];
376 }
377}

Referenced by OOLogOutputHandlerClose().

+ Here is the caller graph for this function:

◆ flushLog

- (void) flushLog

Definition at line 95 of file OOLogOutputHandler.m.

414{
415 flushTimer = nil;
416 [messageQueue enqueue:@"flush"];
417}

◆ init

- (id) init
implementation

Definition at line 95 of file OOLogOutputHandler.m.

246{
247 BOOL OK = YES;
248 NSString *logPath = nil;
249 NSString *oldPath = nil;
250 NSFileManager *fmgr = nil;
251
252 self = [super init];
253 if (self == nil) OK = NO;
254
255 if (OK)
256 {
257 fmgr = [NSFileManager defaultManager];
258 logPath = OOLogHandlerGetLogPath();
259
260 // If there is an existing file, move it to Previous.log.
261 if ([fmgr fileExistsAtPath:logPath])
262 {
263 oldPath = [OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"];
264 [fmgr oo_removeItemAtPath:oldPath];
265 if (![fmgr oo_moveItemAtPath:logPath toPath:oldPath])
266 {
267 if (![fmgr oo_removeItemAtPath:logPath])
268 {
269 NSLog(@"Log setup: could not move or delete existing log at %@, will log to stdout instead.", logPath);
270 OK = NO;
271 }
272 }
273 }
274 }
275
276 if (OK) OK = [self startLogging];
277
278 if (!OK) DESTROY(self);
279
280 return self;
281}
NSString * OOLogHandlerGetLogPath(void)
#define NSLog(format,...)
Definition OOLogging.h:137

◆ loggerThread

- (void) loggerThread

Definition at line 95 of file OOLogOutputHandler.m.

421{
422 id message = nil;
423 NSAutoreleasePool *rootPool = nil, *pool = nil;
424 NSUInteger size = 0;
425
426 rootPool = [[NSAutoreleasePool alloc] init];
427 [NSThread ooSetCurrentThreadName:@"OOLogOutputHandler logging thread"];
428
429 // Signal readiness
430 [messageQueue retain];
431 [threadStateMonitor lock];
432 [threadStateMonitor unlockWithCondition:kConditionWorking];
433
434 @try
435 {
436 for (;;)
437 {
438 pool = [[NSAutoreleasePool alloc] init];
439
440 message = [messageQueue dequeue];
441
442 if (!sSaturated && [message isKindOfClass:[NSData class]])
443 {
444 size += [message length];
445 if (size > 1 << 30) // 1 GiB
446 {
447 sSaturated = YES;
448#if OOLITE_WINDOWS
449 message = @"\r\n\r\n\r\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\r\n";
450#else
451 message = @"\n\n\n***** LOG TRUNCATED DUE TO EXCESSIVE LENGTH *****\n";
452#endif
453 message = [message dataUsingEncoding:NSUTF8StringEncoding];
454 }
455
456 [logFile writeData:message];
457 }
458 else if ([message isEqual:@"flush"])
459 {
460 [logFile synchronizeFile];
461 }
462 else if ([message isEqual:@"die"])
463 {
464 break;
465 }
466
467 [pool release];
468 }
469 }
470 @catch (NSException *exception) {}
471 [pool release];
472
473 // Clean up; after this, ivars are out of bounds.
474 [messageQueue release];
475 [threadStateMonitor lock];
476 [threadStateMonitor unlockWithCondition:kConditionReadyToDealloc];
477
478 [rootPool release];
479}
voidpf void uLong size
Definition ioapi.h:134

◆ startLogging

- (BOOL) startLogging

Definition at line 95 of file OOLogOutputHandler.m.

296{
297 BOOL OK = YES;
298 NSString *logPath = nil;
299 NSFileManager *fmgr = nil;
300
301 fmgr = [NSFileManager defaultManager];
302
303 if (OK)
304 {
305 messageQueue = [[OOAsyncQueue alloc] init];
306 if (messageQueue == nil) OK = NO;
307 }
308
309 if (OK)
310 {
311 // set up threadStateMonitor -- used as a binary semaphore of sorts to check when the worker thread starts and stops.
312 threadStateMonitor = [[NSConditionLock alloc] initWithCondition:kConditionReadyToDealloc];
313 if (threadStateMonitor == nil) OK = NO;
314 [threadStateMonitor setName:@"OOLogOutputHandler thread state monitor"];
315 }
316
317 if (OK)
318 {
319 // Create work thread to actually handle messages.
320 // This needs to be done early to avoid messy state if something goes wrong.
321 [NSThread detachNewThreadSelector:@selector(loggerThread) toTarget:self withObject:nil];
322 // Wait for it to start.
323 if (![threadStateMonitor lockWhenCondition:kConditionWorking beforeDate:[NSDate dateWithTimeIntervalSinceNow:5.0]])
324 {
325 // If it doesn't signal a start within five seconds, assume something's wrong.
326 // Send kill signal, just in case it comes to life...
327 [messageQueue enqueue:@"die"];
328 // ...and stop -dealloc from waiting for thread death
329 [threadStateMonitor release];
331 OK = NO;
332 }
333 [threadStateMonitor unlockWithCondition:kConditionWorking];
334 }
335
336 if (OK)
337 {
338 logPath = OOLogHandlerGetLogPath();
339 OK = (logPath != nil);
340 }
341
342 if (OK)
343 {
344 // Create shiny new log file
345 OK = [fmgr createFileAtPath:logPath contents:nil attributes:nil];
346 if (OK)
347 {
348 logFile = [[NSFileHandle fileHandleForWritingAtPath:logPath] retain];
349 OK = (logFile != nil);
350 }
351 if (!OK)
352 {
353 NSLog(@"Log setup: could not open log at %@, will log to stdout instead.", logPath);
354 OK = NO;
355 }
356 }
357
358 return OK;
359}
@ kConditionWorking

Member Data Documentation

◆ flushTimer

- (NSTimer*) flushTimer
private

Definition at line 95 of file OOLogOutputHandler.m.

◆ logFile

- (NSFileHandle*) logFile
private

Definition at line 94 of file OOLogOutputHandler.m.

◆ messageQueue

- (OOAsyncQueue*) messageQueue
private

Definition at line 92 of file OOLogOutputHandler.m.

◆ threadStateMonitor

- (NSConditionLock*) threadStateMonitor
private

Definition at line 93 of file OOLogOutputHandler.m.


The documentation for this class was generated from the following file: