Permalink
Browse files

Upgrading to version 1.6 of CocoaLumberjack

  • Loading branch information...
1 parent 271fad0 commit f8b05bd259d0d3f711022581a01d09592c9a4ef6 @robbiehanson committed Jul 7, 2012
@@ -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 <DDLogger>)logger;
+- (void)willRemoveFromLogger:(id <DDLogger>)logger;
+
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1022,11 +1022,21 @@ - (void)setLogFormatter:(id <DDLogFormatter>)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)
@@ -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
@@ -1,4 +1,5 @@
#import "DispatchQueueLogFormatter.h"
+#import <libkern/OSAtomic.h>
/**
* 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 <DDLogger>)logger
+{
+ OSAtomicIncrement32(&atomicLoggerCount);
+}
+
+- (void)willRemoveFromLogger:(id <DDLogger>)logger
+{
+ OSAtomicDecrement32(&atomicLoggerCount);
+}
+
@end

0 comments on commit f8b05bd

Please sign in to comment.