Subversion Repositories Mobile Apps.GyroMouse

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #import "DDDispatchQueueLogFormatter.h"
  2. #import <libkern/OSAtomic.h>
  3.  
  4. /**
  5.  * Welcome to Cocoa Lumberjack!
  6.  *
  7.  * The project page has a wealth of documentation if you have any questions.
  8.  * https://github.com/CocoaLumberjack/CocoaLumberjack
  9.  *
  10.  * If you're new to the project you may wish to read the "Getting Started" wiki.
  11.  * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
  12. **/
  13.  
  14. #if ! __has_feature(objc_arc)
  15. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  16. #endif
  17.  
  18.  
  19. @implementation DDDispatchQueueLogFormatter
  20. {
  21.     int32_t atomicLoggerCount;
  22.     NSDateFormatter *threadUnsafeDateFormatter; // Use [self stringFromDate]
  23.    
  24.     OSSpinLock lock;
  25.    
  26.     NSUInteger _minQueueLength;           // _prefix == Only access via atomic property
  27.     NSUInteger _maxQueueLength;           // _prefix == Only access via atomic property
  28.     NSMutableDictionary *_replacements;   // _prefix == Only access from within spinlock
  29. }
  30.  
  31. - (id)init
  32. {
  33.     if ((self = [super init]))
  34.     {
  35.         dateFormatString = @"yyyy-MM-dd HH:mm:ss:SSS";
  36.        
  37.         atomicLoggerCount = 0;
  38.         threadUnsafeDateFormatter = nil;
  39.        
  40.         _minQueueLength = 0;
  41.         _maxQueueLength = 0;
  42.         _replacements = [[NSMutableDictionary alloc] init];
  43.        
  44.         // Set default replacements:
  45.        
  46.         _replacements[@"com.apple.main-thread"] = @"main";
  47.     }
  48.     return self;
  49. }
  50.  
  51.  
  52. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  53. #pragma mark Configuration
  54. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  55.  
  56. @synthesize minQueueLength = _minQueueLength;
  57. @synthesize maxQueueLength = _maxQueueLength;
  58.  
  59. - (NSString *)replacementStringForQueueLabel:(NSString *)longLabel
  60. {
  61.     NSString *result = nil;
  62.    
  63.     OSSpinLockLock(&lock);
  64.     {
  65.         result = _replacements[longLabel];
  66.     }
  67.     OSSpinLockUnlock(&lock);
  68.    
  69.     return result;
  70. }
  71.  
  72. - (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel
  73. {
  74.     OSSpinLockLock(&lock);
  75.     {
  76.         if (shortLabel)
  77.             _replacements[longLabel] = shortLabel;
  78.         else
  79.             [_replacements removeObjectForKey:longLabel];
  80.     }
  81.     OSSpinLockUnlock(&lock);
  82. }
  83.  
  84. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  85. #pragma mark DDLogFormatter
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87.  
  88. - (NSString *)stringFromDate:(NSDate *)date
  89. {
  90.     int32_t loggerCount = OSAtomicAdd32(0, &atomicLoggerCount);
  91.    
  92.     if (loggerCount <= 1)
  93.     {
  94.         // Single-threaded mode.
  95.        
  96.         if (threadUnsafeDateFormatter == nil)
  97.         {
  98.             threadUnsafeDateFormatter = [[NSDateFormatter alloc] init];
  99.             [threadUnsafeDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
  100.             [threadUnsafeDateFormatter setDateFormat:dateFormatString];
  101.         }
  102.        
  103.         [threadUnsafeDateFormatter setCalendar:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]];
  104.         return [threadUnsafeDateFormatter stringFromDate:date];
  105.     }
  106.     else
  107.     {
  108.         // Multi-threaded mode.
  109.         // NSDateFormatter is NOT thread-safe.
  110.        
  111.         NSString *key = @"DispatchQueueLogFormatter_NSDateFormatter";
  112.        
  113.         NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
  114.         NSDateFormatter *dateFormatter = threadDictionary[key];
  115.        
  116.         if (dateFormatter == nil)
  117.         {
  118.             dateFormatter = [[NSDateFormatter alloc] init];
  119.             [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
  120.             [dateFormatter setDateFormat:dateFormatString];
  121.            
  122.             threadDictionary[key] = dateFormatter;
  123.         }
  124.        
  125.         [dateFormatter setCalendar:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]];
  126.         return [dateFormatter stringFromDate:date];
  127.     }
  128. }
  129.  
  130. - (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage
  131. {
  132.     // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue
  133.    
  134.     NSUInteger minQueueLength = self.minQueueLength;
  135.     NSUInteger maxQueueLength = self.maxQueueLength;
  136.    
  137.     // Get the name of the queue, thread, or machID (whichever we are to use).
  138.    
  139.     NSString *queueThreadLabel = nil;
  140.    
  141.     BOOL useQueueLabel = YES;
  142.     BOOL useThreadName = NO;
  143.    
  144.     if (logMessage->queueLabel)
  145.     {
  146.         // If you manually create a thread, it's dispatch_queue will have one of the thread names below.
  147.         // Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID.
  148.        
  149.         char *names[] = { "com.apple.root.low-priority",
  150.                           "com.apple.root.default-priority",
  151.                           "com.apple.root.high-priority",
  152.                           "com.apple.root.low-overcommit-priority",
  153.                           "com.apple.root.default-overcommit-priority",
  154.                           "com.apple.root.high-overcommit-priority"     };
  155.        
  156.         int length = sizeof(names) / sizeof(char *);
  157.        
  158.         int i;
  159.         for (i = 0; i < length; i++)
  160.         {
  161.             if (strcmp(logMessage->queueLabel, names[i]) == 0)
  162.             {
  163.                 useQueueLabel = NO;
  164.                 useThreadName = [logMessage->threadName length] > 0;
  165.                 break;
  166.             }
  167.         }
  168.     }
  169.     else
  170.     {
  171.         useQueueLabel = NO;
  172.         useThreadName = [logMessage->threadName length] > 0;
  173.     }
  174.    
  175.     if (useQueueLabel || useThreadName)
  176.     {
  177.         NSString *fullLabel;
  178.         NSString *abrvLabel;
  179.        
  180.         if (useQueueLabel)
  181.             fullLabel = @(logMessage->queueLabel);
  182.         else
  183.             fullLabel = logMessage->threadName;
  184.        
  185.         OSSpinLockLock(&lock);
  186.         {
  187.             abrvLabel = _replacements[fullLabel];
  188.         }
  189.         OSSpinLockUnlock(&lock);
  190.        
  191.         if (abrvLabel)
  192.             queueThreadLabel = abrvLabel;
  193.         else
  194.             queueThreadLabel = fullLabel;
  195.     }
  196.     else
  197.     {
  198.         queueThreadLabel = [NSString stringWithFormat:@"%x", logMessage->machThreadID];
  199.     }
  200.    
  201.     // Now use the thread label in the output
  202.    
  203.     NSUInteger labelLength = [queueThreadLabel length];
  204.    
  205.     // labelLength > maxQueueLength : truncate
  206.     // labelLength < minQueueLength : padding
  207.     //                              : exact
  208.    
  209.     if ((maxQueueLength > 0) && (labelLength > maxQueueLength))
  210.     {
  211.         // Truncate
  212.        
  213.         return [queueThreadLabel substringToIndex:maxQueueLength];
  214.     }
  215.     else if (labelLength < minQueueLength)
  216.     {
  217.         // Padding
  218.        
  219.         NSUInteger numSpaces = minQueueLength - labelLength;
  220.        
  221.         char spaces[numSpaces + 1];
  222.         memset(spaces, ' ', numSpaces);
  223.         spaces[numSpaces] = '\0';
  224.        
  225.         return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces];
  226.     }
  227.     else
  228.     {
  229.         // Exact
  230.        
  231.         return queueThreadLabel;
  232.     }
  233. }
  234.  
  235. - (NSString *)formatLogMessage:(DDLogMessage *)logMessage
  236. {
  237.     NSString *timestamp = [self stringFromDate:(logMessage->timestamp)];
  238.     NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage];
  239.    
  240.     return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->logMsg];
  241. }
  242.  
  243. - (void)didAddToLogger:(id <DDLogger>)logger
  244. {
  245.     OSAtomicIncrement32(&atomicLoggerCount);
  246. }
  247.  
  248. - (void)willRemoveFromLogger:(id <DDLogger>)logger
  249. {
  250.     OSAtomicDecrement32(&atomicLoggerCount);
  251. }
  252.  
  253. @end
  254.