From f8b05bd259d0d3f711022581a01d09592c9a4ef6 Mon Sep 17 00:00:00 2001 From: Robbie Hanson Date: Sat, 7 Jul 2012 12:15:09 -0700 Subject: [PATCH] Upgrading to version 1.6 of CocoaLumberjack --- Vendor/CocoaLumberjack/DDLog.h | 15 ++++- Vendor/CocoaLumberjack/DDLog.m | 16 ++++- .../Extensions/DispatchQueueLogFormatter.h | 5 +- .../Extensions/DispatchQueueLogFormatter.m | 60 +++++++++++++++++-- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/Vendor/CocoaLumberjack/DDLog.h b/Vendor/CocoaLumberjack/DDLog.h index 49befa09d0..57c2f096c0 100755 --- a/Vendor/CocoaLumberjack/DDLog.h +++ b/Vendor/CocoaLumberjack/DDLog.h @@ -427,9 +427,22 @@ NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy); * The formatter may also optionally filter the log message by returning nil, * in which case the logger will not log the message. **/ - - (NSString *)formatLogMessage:(DDLogMessage *)logMessage; +@optional + +/** + * A single formatter instance can be added to multiple loggers. + * These methods provides hooks to notify the formatter of when it's added/removed. + * + * This is primarily for thread-safety. + * If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers. + * Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter), + * it could possibly use these hooks to switch to thread-safe versions of the code. +**/ +- (void)didAddToLogger:(id )logger; +- (void)willRemoveFromLogger:(id )logger; + @end //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Vendor/CocoaLumberjack/DDLog.m b/Vendor/CocoaLumberjack/DDLog.m index d6b685f79c..9b09ac1c11 100755 --- a/Vendor/CocoaLumberjack/DDLog.m +++ b/Vendor/CocoaLumberjack/DDLog.m @@ -1022,11 +1022,21 @@ - (void)setLogFormatter:(id )logFormatter { // The design of this method is documented extensively in the logFormatter message (above in code). - dispatch_block_t block = ^{ - if (formatter != logFormatter) { + dispatch_block_t block = ^{ @autoreleasepool { + + if (formatter != logFormatter) + { + if ([formatter respondsToSelector:@selector(willRemoveFromLogger:)]) { + [formatter willRemoveFromLogger:self]; + } + formatter = logFormatter; + + if ([formatter respondsToSelector:@selector(didAddToLogger:)]) { + [formatter didAddToLogger:self]; + } } - }; + }}; dispatch_queue_t currentQueue = dispatch_get_current_queue(); if (currentQueue == loggerQueue) diff --git a/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.h b/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.h index e6c013ee54..7cc5772711 100644 --- a/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.h +++ b/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.h @@ -53,10 +53,13 @@ { @protected - NSDateFormatter *dateFormatter; + NSString *dateFormatString; @private + int32_t atomicLoggerCount; + NSDateFormatter *threadUnsafeDateFormatter; // Use [self stringFromDate] + OSSpinLock lock; NSUInteger _minQueueLength; // _prefix == Only access via atomic property diff --git a/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.m b/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.m index 8c7d8d1b0c..c8e55a1368 100644 --- a/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.m +++ b/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.m @@ -1,4 +1,5 @@ #import "DispatchQueueLogFormatter.h" +#import /** * Welcome to Cocoa Lumberjack! @@ -21,9 +22,10 @@ - (id)init { if ((self = [super init])) { - dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; - [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"]; + dateFormatString = @"yyyy-MM-dd HH:mm:ss:SSS"; + + atomicLoggerCount = 0; + threadUnsafeDateFormatter = nil; _minQueueLength = 0; _maxQueueLength = 0; @@ -73,6 +75,46 @@ - (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)lo #pragma mark DDLogFormatter //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)stringFromDate:(NSDate *)date +{ + int32_t loggerCount = OSAtomicAdd32(0, &atomicLoggerCount); + + if (loggerCount <= 1) + { + // Single-threaded mode. + + if (threadUnsafeDateFormatter == nil) + { + threadUnsafeDateFormatter = [[NSDateFormatter alloc] init]; + [threadUnsafeDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [threadUnsafeDateFormatter setDateFormat:dateFormatString]; + } + + return [threadUnsafeDateFormatter stringFromDate:date]; + } + else + { + // Multi-threaded mode. + // NSDateFormatter is NOT thread-safe. + + NSString *key = @"DispatchQueueLogFormatter_NSDateFormatter"; + + NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary]; + NSDateFormatter *dateFormatter = [threadDictionary objectForKey:key]; + + if (dateFormatter == nil) + { + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setDateFormat:dateFormatString]; + + [threadDictionary setObject:dateFormatter forKey:key]; + } + + return [dateFormatter stringFromDate:date]; + } +} + - (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage { // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue @@ -180,10 +222,20 @@ - (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage - (NSString *)formatLogMessage:(DDLogMessage *)logMessage { - NSString *timestamp = [dateFormatter stringFromDate:(logMessage->timestamp)]; + NSString *timestamp = [self stringFromDate:(logMessage->timestamp)]; NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage]; return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->logMsg]; } +- (void)didAddToLogger:(id )logger +{ + OSAtomicIncrement32(&atomicLoggerCount); +} + +- (void)willRemoveFromLogger:(id )logger +{ + OSAtomicDecrement32(&atomicLoggerCount); +} + @end