![]() |
IOS Streaming Browser 1.0
An IOS streaming browser to stream the display to others or to a projector
|
#import <DDLog.h>
Public Member Functions | |
(id< DDLogFormatter >) | - logFormatter |
(void) | - setLogFormatter: |
Protected Attributes | |
id< DDLogFormatter > | formatter |
The DDLogger protocol specifies that an optional formatter can be added to a logger. Most (but not all) loggers will want to support formatters.
However, writting getters and setters in a thread safe manner, while still maintaining maximum speed for the logging process, is a difficult task.
To do it right, the implementation of the getter/setter has strict requiremenets:
To simplify things, an abstract logger is provided that implements the getter and setter.
Logger implementations may simply extend this class, and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their logMessage method!
- (id< DDLogFormatter >) logFormatter |
Gets the logFormatter returns id <DDLogFormatter>
Reimplemented from <DDLogger>.
Definition at line 1400 of file DDLog.m.
{ // This method must be thread safe and intuitive. // Therefore if somebody executes the following code: // // [logger setLogFormatter:myFormatter]; // formatter = [logger logFormatter]; // // They would expect formatter to equal myFormatter. // This functionality must be ensured by the getter and setter method. // // The thread safety must not come at a cost to the performance of the logMessage method. // This method is likely called sporadically, while the logMessage method is called repeatedly. // This means, the implementation of this method: // - Must NOT require the logMessage method to acquire a lock. // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). // // Thread safety is ensured by executing access to the formatter variable on the logging thread/queue. // This is the same thread/queue that the logMessage method operates on. // // Note: The last time I benchmarked the performance of direct access vs atomic property access, // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone. if (IS_GCD_AVAILABLE) { #if GCD_MAYBE_AVAILABLE // loggerQueue : Our own private internal queue that the logMessage method runs on. // Operations are added to this queue from the global loggingQueue. // // loggingQueue : The queue that all log messages go through before they arrive in our loggerQueue. // // It is important to note that, while the loggerQueue is used to create thread-safety for our formatter, // changes to the formatter variable are queued on the loggingQueue. // // Since this will obviously confuse the hell out of me later, here is a better description. // Imagine the following code: // // DDLogVerbose(@"log msg 1"); // DDLogVerbose(@"log msg 2"); // [logger setFormatter:myFormatter]; // DDLogVerbose(@"log msg 3"); // // Our intuitive requirement means that the new formatter will only apply to the 3rd log message. // But notice what happens if we have asynchronous logging enabled for verbose mode. // // Log msg 1 starts executing asynchronously on the loggingQueue. // The loggingQueue executes the log statement on each logger concurrently. // That means it executes log msg 1 on our loggerQueue. // While log msg 1 is executing, log msg 2 gets added to the loggingQueue. // Then the user requests that we change our formatter. // So at this exact moment, our queues look like this: // // loggerQueue : executing log msg 1, nil // loggingQueue : executing log msg 1, log msg 2, nil // // So direct access to the formatter is only available if requested from the loggerQueue. // In all other circumstances we need to go through the loggingQueue to get the proper value. if (dispatch_get_current_queue() == loggerQueue) { return formatter; } __block id <DDLogFormatter> result; dispatch_block_t block = ^{ result = [formatter retain]; }; dispatch_sync([DDLog loggingQueue], block); return [result autorelease]; #endif } else { #if GCD_MAYBE_UNAVAILABLE NSThread *loggingThread = [DDLog loggingThread]; if ([NSThread currentThread] == loggingThread) { return formatter; } NSMutableArray *resultHolder = [[NSMutableArray alloc] init]; [self performSelector:@selector(lt_getLogFormatter:) onThread:loggingThread withObject:resultHolder waitUntilDone:YES]; OSMemoryBarrier(); id <DDLogFormatter> result = [[resultHolder objectAtIndex:0] retain]; [resultHolder release]; return [result autorelease]; #endif } }
- (void) setLogFormatter: | (id <DDLogFormatter>) | logFormatter |
Set the logFormatter param id <DDLogFormatter>
Reimplemented from <DDLogger>.
Definition at line 1509 of file DDLog.m.
:(id <DDLogFormatter>)logFormatter { // This method must be thread safe and intuitive. // Therefore if somebody executes the following code: // // [logger setLogFormatter:myFormatter]; // formatter = [logger logFormatter]; // // They would expect formatter to equal myFormatter. // This functionality must be ensured by the getter and setter method. // // The thread safety must not come at a cost to the performance of the logMessage method. // This method is likely called sporadically, while the logMessage method is called repeatedly. // This means, the implementation of this method: // - Must NOT require the logMessage method to acquire a lock. // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). // // Thread safety is ensured by executing access to the formatter variable on the logging thread/queue. // This is the same thread/queue that the logMessage method operates on. // // Note: The last time I benchmarked the performance of direct access vs atomic property access, // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone. if (IS_GCD_AVAILABLE) { #if GCD_MAYBE_AVAILABLE // loggerQueue : Our own private internal queue that the logMessage method runs on. // Operations are added to this queue from the global loggingQueue. // // loggingQueue : The queue that all log messages go through before they arrive in our loggerQueue. // // It is important to note that, while the loggerQueue is used to create thread-safety for our formatter, // changes to the formatter variable are queued on the loggingQueue. // // Since this will obviously confuse the hell out of me later, here is a better description. // Imagine the following code: // // DDLogVerbose(@"log msg 1"); // DDLogVerbose(@"log msg 2"); // [logger setFormatter:myFormatter]; // DDLogVerbose(@"log msg 3"); // // Our intuitive requirement means that the new formatter will only apply to the 3rd log message. // But notice what happens if we have asynchronous logging enabled for verbose mode. // // Log msg 1 starts executing asynchronously on the loggingQueue. // The loggingQueue executes the log statement on each logger concurrently. // That means it executes log msg 1 on our loggerQueue. // While log msg 1 is executing, log msg 2 gets added to the loggingQueue. // Then the user requests that we change our formatter. // So at this exact moment, our queues look like this: // // loggerQueue : executing log msg 1, nil // loggingQueue : executing log msg 1, log msg 2, nil // // So direct access to the formatter is only available if requested from the loggerQueue. // In all other circumstances we need to go through the loggingQueue to get the proper value. dispatch_block_t block = ^{ if (formatter != logFormatter) { [formatter release]; formatter = [logFormatter retain]; } }; // END OF BLOCK if (dispatch_get_current_queue() == loggerQueue) { block(); }else{ dispatch_async([DDLog loggingQueue], block); } #endif } else { #if GCD_MAYBE_UNAVAILABLE NSThread *loggingThread = [DDLog loggingThread]; if ([NSThread currentThread] == loggingThread) { [self lt_setLogFormatter:logFormatter]; } else { // Set the log formatter on the logging threate with a specific format and don't wait for it to finish (asychronous) [self performSelector:@selector(lt_setLogFormatter:) onThread:loggingThread withObject:logFormatter waitUntilDone:NO]; } #endif } }
- (id<DDLogFormatter>) formatter [protected] |
Follows the DDLogFormatter protocol