IOS Streaming Browser 1.0
An IOS streaming browser to stream the display to others or to a projector

DDAbstractLogger Class Reference

#import <DDLog.h>

Inheritance diagram for DDAbstractLogger:
Collaboration diagram for DDAbstractLogger:

Public Member Functions

(id< DDLogFormatter >) - logFormatter
(void) - setLogFormatter:

Protected Attributes

id< DDLogFormatterformatter

Detailed Description

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:

  • 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).

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!

Definition at line 657 of file DDLog.h.


Member Function Documentation

- (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
        }
}

Field Documentation

- (id<DDLogFormatter>) formatter [protected]

Follows the DDLogFormatter protocol

Definition at line 663 of file DDLog.h.


The documentation for this class was generated from the following files:
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Properties Defines