motion-logger 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/README.md +3 -1
  4. data/Rakefile +2 -4
  5. data/lib/logger/version.rb +1 -1
  6. data/motion-logger.gemspec +3 -3
  7. metadata +28 -51
  8. data/vendor/Podfile.lock +0 -5
  9. data/vendor/Pods/CocoaLumberjack/.gitignore +0 -24
  10. data/vendor/Pods/CocoaLumberjack/.hgignore +0 -6
  11. data/vendor/Pods/CocoaLumberjack/CocoaLumberjack.podspec +0 -18
  12. data/vendor/Pods/CocoaLumberjack/LICENSE.txt +0 -18
  13. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +0 -41
  14. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +0 -99
  15. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +0 -102
  16. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +0 -618
  17. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +0 -334
  18. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +0 -1346
  19. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +0 -498
  20. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +0 -979
  21. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +0 -49
  22. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +0 -186
  23. data/vendor/Pods/CocoaLumberjack/README.markdown +0 -37
  24. data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +0 -41
  25. data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +0 -102
  26. data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +0 -334
  27. data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +0 -498
  28. data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +0 -49
  29. data/vendor/Pods/Pods-Acknowledgements.markdown +0 -24
  30. data/vendor/Pods/Pods-Acknowledgements.plist +0 -54
  31. data/vendor/Pods/Pods-prefix.pch +0 -3
  32. data/vendor/Pods/Pods-resources.sh +0 -19
  33. data/vendor/Pods/Pods.bridgesupport +0 -462
  34. data/vendor/Pods/Pods.xcconfig +0 -4
  35. data/vendor/Pods/PodsDummy_Pods.m +0 -4
@@ -1,979 +0,0 @@
1
- #import "DDLog.h"
2
-
3
- #import <pthread.h>
4
- #import <objc/runtime.h>
5
- #import <mach/mach_host.h>
6
- #import <mach/host_info.h>
7
- #import <libkern/OSAtomic.h>
8
-
9
-
10
- /**
11
- * Welcome to Cocoa Lumberjack!
12
- *
13
- * The project page has a wealth of documentation if you have any questions.
14
- * https://github.com/robbiehanson/CocoaLumberjack
15
- *
16
- * If you're new to the project you may wish to read the "Getting Started" wiki.
17
- * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
18
- *
19
- **/
20
-
21
- #if ! __has_feature(objc_arc)
22
- #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
23
- #endif
24
-
25
- // We probably shouldn't be using DDLog() statements within the DDLog implementation.
26
- // But we still want to leave our log statements for any future debugging,
27
- // and to allow other developers to trace the implementation (which is a great learning tool).
28
- //
29
- // So we use a primitive logging macro around NSLog.
30
- // We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
31
-
32
- #define DD_DEBUG NO
33
-
34
- #define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0)
35
-
36
- // Specifies the maximum queue size of the logging thread.
37
- //
38
- // Since most logging is asynchronous, its possible for rogue threads to flood the logging queue.
39
- // That is, to issue an abundance of log statements faster than the logging thread can keepup.
40
- // Typically such a scenario occurs when log statements are added haphazardly within large loops,
41
- // but may also be possible if relatively slow loggers are being used.
42
- //
43
- // This property caps the queue size at a given number of outstanding log statements.
44
- // If a thread attempts to issue a log statement when the queue is already maxed out,
45
- // the issuing thread will block until the queue size drops below the max again.
46
-
47
- #define LOG_MAX_QUEUE_SIZE 1000 // Should not exceed INT32_MAX
48
-
49
-
50
- @interface DDLoggerNode : NSObject {
51
- @public
52
- id <DDLogger> logger;
53
- dispatch_queue_t loggerQueue;
54
- }
55
-
56
- + (DDLoggerNode *)nodeWithLogger:(id <DDLogger>)logger loggerQueue:(dispatch_queue_t)loggerQueue;
57
-
58
- @end
59
-
60
-
61
- @interface DDLog (PrivateAPI)
62
-
63
- + (void)lt_addLogger:(id <DDLogger>)logger;
64
- + (void)lt_removeLogger:(id <DDLogger>)logger;
65
- + (void)lt_removeAllLoggers;
66
- + (void)lt_log:(DDLogMessage *)logMessage;
67
- + (void)lt_flush;
68
-
69
- @end
70
-
71
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
72
- #pragma mark -
73
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
74
-
75
- @implementation DDLog
76
-
77
- // An array used to manage all the individual loggers.
78
- // The array is only modified on the loggingQueue/loggingThread.
79
- static NSMutableArray *loggers;
80
-
81
- // All logging statements are added to the same queue to ensure FIFO operation.
82
- static dispatch_queue_t loggingQueue;
83
-
84
- // Individual loggers are executed concurrently per log statement.
85
- // Each logger has it's own associated queue, and a dispatch group is used for synchrnoization.
86
- static dispatch_group_t loggingGroup;
87
-
88
- // In order to prevent to queue from growing infinitely large,
89
- // a maximum size is enforced (LOG_MAX_QUEUE_SIZE).
90
- static dispatch_semaphore_t queueSemaphore;
91
-
92
- // Minor optimization for uniprocessor machines
93
- static unsigned int numProcessors;
94
-
95
- /**
96
- * The runtime sends initialize to each class in a program exactly one time just before the class,
97
- * or any class that inherits from it, is sent its first message from within the program. (Thus the
98
- * method may never be invoked if the class is not used.) The runtime sends the initialize message to
99
- * classes in a thread-safe manner. Superclasses receive this message before their subclasses.
100
- *
101
- * This method may also be called directly (assumably by accident), hence the safety mechanism.
102
- **/
103
- + (void)initialize
104
- {
105
- static BOOL initialized = NO;
106
- if (!initialized)
107
- {
108
- initialized = YES;
109
-
110
- loggers = [[NSMutableArray alloc] initWithCapacity:4];
111
-
112
- NSLogDebug(@"DDLog: Using grand central dispatch");
113
-
114
- loggingQueue = dispatch_queue_create("cocoa.lumberjack", NULL);
115
- loggingGroup = dispatch_group_create();
116
-
117
- queueSemaphore = dispatch_semaphore_create(LOG_MAX_QUEUE_SIZE);
118
-
119
- // Figure out how many processors are available.
120
- // This may be used later for an optimization on uniprocessor machines.
121
-
122
- host_basic_info_data_t hostInfo;
123
- mach_msg_type_number_t infoCount;
124
-
125
- infoCount = HOST_BASIC_INFO_COUNT;
126
- host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
127
-
128
- unsigned int result = (unsigned int)(hostInfo.max_cpus);
129
- unsigned int one = (unsigned int)(1);
130
-
131
- numProcessors = MAX(result, one);
132
-
133
- NSLogDebug(@"DDLog: numProcessors = %u", numProcessors);
134
-
135
-
136
- #if TARGET_OS_IPHONE
137
- NSString *notificationName = @"UIApplicationWillTerminateNotification";
138
- #else
139
- NSString *notificationName = @"NSApplicationWillTerminateNotification";
140
- #endif
141
-
142
- [[NSNotificationCenter defaultCenter] addObserver:self
143
- selector:@selector(applicationWillTerminate:)
144
- name:notificationName
145
- object:nil];
146
- }
147
- }
148
-
149
- /**
150
- * Provides access to the logging queue.
151
- **/
152
- + (dispatch_queue_t)loggingQueue
153
- {
154
- return loggingQueue;
155
- }
156
-
157
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158
- #pragma mark Notifications
159
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160
-
161
- + (void)applicationWillTerminate:(NSNotification *)notification
162
- {
163
- [self flushLog];
164
- }
165
-
166
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
167
- #pragma mark Logger Management
168
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169
-
170
- + (void)addLogger:(id <DDLogger>)logger
171
- {
172
- if (logger == nil) return;
173
-
174
- dispatch_async(loggingQueue, ^{ @autoreleasepool {
175
-
176
- [self lt_addLogger:logger];
177
- }});
178
- }
179
-
180
- + (void)removeLogger:(id <DDLogger>)logger
181
- {
182
- if (logger == nil) return;
183
-
184
- dispatch_async(loggingQueue, ^{ @autoreleasepool {
185
-
186
- [self lt_removeLogger:logger];
187
- }});
188
- }
189
-
190
- + (void)removeAllLoggers
191
- {
192
- dispatch_async(loggingQueue, ^{ @autoreleasepool {
193
-
194
- [self lt_removeAllLoggers];
195
- }});
196
- }
197
-
198
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199
- #pragma mark Master Logging
200
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201
-
202
- + (void)queueLogMessage:(DDLogMessage *)logMessage asynchronously:(BOOL)asyncFlag
203
- {
204
- // We have a tricky situation here...
205
- //
206
- // In the common case, when the queueSize is below the maximumQueueSize,
207
- // we want to simply enqueue the logMessage. And we want to do this as fast as possible,
208
- // which means we don't want to block and we don't want to use any locks.
209
- //
210
- // However, if the queueSize gets too big, we want to block.
211
- // But we have very strict requirements as to when we block, and how long we block.
212
- //
213
- // The following example should help illustrate our requirements:
214
- //
215
- // Imagine that the maximum queue size is configured to be 5,
216
- // and that there are already 5 log messages queued.
217
- // Let us call these 5 queued log messages A, B, C, D, and E. (A is next to be executed)
218
- //
219
- // Now if our thread issues a log statement (let us call the log message F),
220
- // it should block before the message is added to the queue.
221
- // Furthermore, it should be unblocked immediately after A has been unqueued.
222
- //
223
- // The requirements are strict in this manner so that we block only as long as necessary,
224
- // and so that blocked threads are unblocked in the order in which they were blocked.
225
- //
226
- // Returning to our previous example, let us assume that log messages A through E are still queued.
227
- // Our aforementioned thread is blocked attempting to queue log message F.
228
- // Now assume we have another separate thread that attempts to issue log message G.
229
- // It should block until log messages A and B have been unqueued.
230
-
231
-
232
- // We are using a counting semaphore provided by GCD.
233
- // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value.
234
- // Everytime we want to queue a log message we decrement this value.
235
- // If the resulting value is less than zero,
236
- // the semaphore function waits in FIFO order for a signal to occur before returning.
237
- //
238
- // A dispatch semaphore is an efficient implementation of a traditional counting semaphore.
239
- // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked.
240
- // If the calling semaphore does not need to block, no kernel call is made.
241
-
242
- dispatch_semaphore_wait(queueSemaphore, DISPATCH_TIME_FOREVER);
243
-
244
- // We've now sure we won't overflow the queue.
245
- // It is time to queue our log message.
246
-
247
- dispatch_block_t logBlock = ^{ @autoreleasepool {
248
-
249
- [self lt_log:logMessage];
250
- }};
251
-
252
- if (asyncFlag)
253
- dispatch_async(loggingQueue, logBlock);
254
- else
255
- dispatch_sync(loggingQueue, logBlock);
256
- }
257
-
258
- + (void)log:(BOOL)asynchronous
259
- level:(int)level
260
- flag:(int)flag
261
- context:(int)context
262
- file:(const char *)file
263
- function:(const char *)function
264
- line:(int)line
265
- tag:(id)tag
266
- format:(NSString *)format, ...
267
- {
268
- va_list args;
269
- if (format)
270
- {
271
- va_start(args, format);
272
-
273
- NSString *logMsg = [[NSString alloc] initWithFormat:format arguments:args];
274
- DDLogMessage *logMessage = [[DDLogMessage alloc] initWithLogMsg:logMsg
275
- level:level
276
- flag:flag
277
- context:context
278
- file:file
279
- function:function
280
- line:line
281
- tag:tag];
282
-
283
- [self queueLogMessage:logMessage asynchronously:asynchronous];
284
-
285
- va_end(args);
286
- }
287
- }
288
-
289
- + (void)flushLog
290
- {
291
- dispatch_sync(loggingQueue, ^{ @autoreleasepool {
292
-
293
- [self lt_flush];
294
- }});
295
- }
296
-
297
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
298
- #pragma mark Registered Dynamic Logging
299
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
300
-
301
- + (BOOL)isRegisteredClass:(Class)class
302
- {
303
- SEL getterSel = @selector(ddLogLevel);
304
- SEL setterSel = @selector(ddSetLogLevel:);
305
-
306
- #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
307
-
308
- // Issue #6 (GoogleCode) - Crashes on iOS 4.2.1 and iPhone 4
309
- //
310
- // Crash caused by class_getClassMethod(2).
311
- //
312
- // "It's a bug with UIAccessibilitySafeCategory__NSObject so it didn't pop up until
313
- // users had VoiceOver enabled [...]. I was able to work around it by searching the
314
- // result of class_copyMethodList() instead of calling class_getClassMethod()"
315
-
316
- BOOL result = NO;
317
-
318
- unsigned int methodCount, i;
319
- Method *methodList = class_copyMethodList(object_getClass(class), &methodCount);
320
-
321
- if (methodList != NULL)
322
- {
323
- BOOL getterFound = NO;
324
- BOOL setterFound = NO;
325
-
326
- for (i = 0; i < methodCount; ++i)
327
- {
328
- SEL currentSel = method_getName(methodList[i]);
329
-
330
- if (currentSel == getterSel)
331
- {
332
- getterFound = YES;
333
- }
334
- else if (currentSel == setterSel)
335
- {
336
- setterFound = YES;
337
- }
338
-
339
- if (getterFound && setterFound)
340
- {
341
- result = YES;
342
- break;
343
- }
344
- }
345
-
346
- free(methodList);
347
- }
348
-
349
- return result;
350
-
351
- #else
352
-
353
- // Issue #24 (GitHub) - Crashing in in ARC+Simulator
354
- //
355
- // The method +[DDLog isRegisteredClass] will crash a project when using it with ARC + Simulator.
356
- // For running in the Simulator, it needs to execute the non-iOS code.
357
-
358
- Method getter = class_getClassMethod(class, getterSel);
359
- Method setter = class_getClassMethod(class, setterSel);
360
-
361
- if ((getter != NULL) && (setter != NULL))
362
- {
363
- return YES;
364
- }
365
-
366
- return NO;
367
-
368
- #endif
369
- }
370
-
371
- + (NSArray *)registeredClasses
372
- {
373
- int numClasses, i;
374
-
375
- // We're going to get the list of all registered classes.
376
- // The Objective-C runtime library automatically registers all the classes defined in your source code.
377
- //
378
- // To do this we use the following method (documented in the Objective-C Runtime Reference):
379
- //
380
- // int objc_getClassList(Class *buffer, int bufferLen)
381
- //
382
- // We can pass (NULL, 0) to obtain the total number of
383
- // registered class definitions without actually retrieving any class definitions.
384
- // This allows us to allocate the minimum amount of memory needed for the application.
385
-
386
- numClasses = objc_getClassList(NULL, 0);
387
-
388
- // The numClasses method now tells us how many classes we have.
389
- // So we can allocate our buffer, and get pointers to all the class definitions.
390
-
391
- Class *classes = (Class *)malloc(sizeof(Class) * numClasses);
392
-
393
- numClasses = objc_getClassList(classes, numClasses);
394
-
395
- // We can now loop through the classes, and test each one to see if it is a DDLogging class.
396
-
397
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:numClasses];
398
-
399
- for (i = 0; i < numClasses; i++)
400
- {
401
- Class class = classes[i];
402
-
403
- if ([self isRegisteredClass:class])
404
- {
405
- [result addObject:class];
406
- }
407
- }
408
-
409
- free(classes);
410
-
411
- return result;
412
- }
413
-
414
- + (NSArray *)registeredClassNames
415
- {
416
- NSArray *registeredClasses = [self registeredClasses];
417
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:[registeredClasses count]];
418
-
419
- for (Class class in registeredClasses)
420
- {
421
- [result addObject:NSStringFromClass(class)];
422
- }
423
-
424
- return result;
425
- }
426
-
427
- + (int)logLevelForClass:(Class)aClass
428
- {
429
- if ([self isRegisteredClass:aClass])
430
- {
431
- return [aClass ddLogLevel];
432
- }
433
-
434
- return -1;
435
- }
436
-
437
- + (int)logLevelForClassWithName:(NSString *)aClassName
438
- {
439
- Class aClass = NSClassFromString(aClassName);
440
-
441
- return [self logLevelForClass:aClass];
442
- }
443
-
444
- + (void)setLogLevel:(int)logLevel forClass:(Class)aClass
445
- {
446
- if ([self isRegisteredClass:aClass])
447
- {
448
- [aClass ddSetLogLevel:logLevel];
449
- }
450
- }
451
-
452
- + (void)setLogLevel:(int)logLevel forClassWithName:(NSString *)aClassName
453
- {
454
- Class aClass = NSClassFromString(aClassName);
455
-
456
- [self setLogLevel:logLevel forClass:aClass];
457
- }
458
-
459
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
460
- #pragma mark Logging Thread
461
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
462
-
463
- /**
464
- * This method should only be run on the logging thread/queue.
465
- **/
466
- + (void)lt_addLogger:(id <DDLogger>)logger
467
- {
468
- // Add to loggers array.
469
- // Need to create loggerQueue if loggerNode doesn't provide one.
470
-
471
- dispatch_queue_t loggerQueue = NULL;
472
-
473
- if ([logger respondsToSelector:@selector(loggerQueue)])
474
- {
475
- // Logger may be providing its own queue
476
-
477
- loggerQueue = [logger loggerQueue];
478
- }
479
-
480
- if (loggerQueue == nil)
481
- {
482
- // Automatically create queue for the logger.
483
- // Use the logger name as the queue name if possible.
484
-
485
- const char *loggerQueueName = NULL;
486
- if ([logger respondsToSelector:@selector(loggerName)])
487
- {
488
- loggerQueueName = [[logger loggerName] UTF8String];
489
- }
490
-
491
- loggerQueue = dispatch_queue_create(loggerQueueName, NULL);
492
- }
493
-
494
- DDLoggerNode *loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue];
495
- [loggers addObject:loggerNode];
496
-
497
- if ([logger respondsToSelector:@selector(didAddLogger)])
498
- {
499
- dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool {
500
-
501
- [logger didAddLogger];
502
- }});
503
- }
504
- }
505
-
506
- /**
507
- * This method should only be run on the logging thread/queue.
508
- **/
509
- + (void)lt_removeLogger:(id <DDLogger>)logger
510
- {
511
- // Find associated loggerNode in list of added loggers
512
-
513
- DDLoggerNode *loggerNode = nil;
514
-
515
- for (DDLoggerNode *node in loggers)
516
- {
517
- if (node->logger == logger)
518
- {
519
- loggerNode = node;
520
- break;
521
- }
522
- }
523
-
524
- if (loggerNode == nil)
525
- {
526
- NSLogDebug(@"DDLog: Request to remove logger which wasn't added");
527
- return;
528
- }
529
-
530
- // Notify logger
531
-
532
- if ([logger respondsToSelector:@selector(willRemoveLogger)])
533
- {
534
- dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool {
535
-
536
- [logger willRemoveLogger];
537
- }});
538
- }
539
-
540
- // Remove from loggers array
541
-
542
- [loggers removeObject:loggerNode];
543
- }
544
-
545
- /**
546
- * This method should only be run on the logging thread/queue.
547
- **/
548
- + (void)lt_removeAllLoggers
549
- {
550
- // Notify all loggers
551
-
552
- for (DDLoggerNode *loggerNode in loggers)
553
- {
554
- if ([loggerNode->logger respondsToSelector:@selector(willRemoveLogger)])
555
- {
556
- dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool {
557
-
558
- [loggerNode->logger willRemoveLogger];
559
- }});
560
- }
561
- }
562
-
563
- // Remove all loggers from array
564
-
565
- [loggers removeAllObjects];
566
- }
567
-
568
- /**
569
- * This method should only be run on the logging thread/queue.
570
- **/
571
- + (void)lt_log:(DDLogMessage *)logMessage
572
- {
573
- // Execute the given log message on each of our loggers.
574
-
575
- if (numProcessors > 1)
576
- {
577
- // Execute each logger concurrently, each within its own queue.
578
- // All blocks are added to same group.
579
- // After each block has been queued, wait on group.
580
- //
581
- // The waiting ensures that a slow logger doesn't end up with a large queue of pending log messages.
582
- // This would defeat the purpose of the efforts we made earlier to restrict the max queue size.
583
-
584
- for (DDLoggerNode *loggerNode in loggers)
585
- {
586
- dispatch_group_async(loggingGroup, loggerNode->loggerQueue, ^{ @autoreleasepool {
587
-
588
- [loggerNode->logger logMessage:logMessage];
589
-
590
- }});
591
- }
592
-
593
- dispatch_group_wait(loggingGroup, DISPATCH_TIME_FOREVER);
594
- }
595
- else
596
- {
597
- // Execute each logger serialy, each within its own queue.
598
-
599
- for (DDLoggerNode *loggerNode in loggers)
600
- {
601
- dispatch_sync(loggerNode->loggerQueue, ^{ @autoreleasepool {
602
-
603
- [loggerNode->logger logMessage:logMessage];
604
-
605
- }});
606
- }
607
- }
608
-
609
- // If our queue got too big, there may be blocked threads waiting to add log messages to the queue.
610
- // Since we've now dequeued an item from the log, we may need to unblock the next thread.
611
-
612
- // We are using a counting semaphore provided by GCD.
613
- // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value.
614
- // When a log message is queued this value is decremented.
615
- // When a log message is dequeued this value is incremented.
616
- // If the value ever drops below zero,
617
- // the queueing thread blocks and waits in FIFO order for us to signal it.
618
- //
619
- // A dispatch semaphore is an efficient implementation of a traditional counting semaphore.
620
- // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked.
621
- // If the calling semaphore does not need to block, no kernel call is made.
622
-
623
- dispatch_semaphore_signal(queueSemaphore);
624
- }
625
-
626
- /**
627
- * This method should only be run on the background logging thread.
628
- **/
629
- + (void)lt_flush
630
- {
631
- // All log statements issued before the flush method was invoked have now been executed.
632
- //
633
- // Now we need to propogate the flush request to any loggers that implement the flush method.
634
- // This is designed for loggers that buffer IO.
635
-
636
- for (DDLoggerNode *loggerNode in loggers)
637
- {
638
- if ([loggerNode->logger respondsToSelector:@selector(flush)])
639
- {
640
- dispatch_group_async(loggingGroup, loggerNode->loggerQueue, ^{ @autoreleasepool {
641
-
642
- [loggerNode->logger flush];
643
-
644
- }});
645
- }
646
- }
647
-
648
- dispatch_group_wait(loggingGroup, DISPATCH_TIME_FOREVER);
649
- }
650
-
651
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
652
- #pragma mark Utilities
653
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
654
-
655
- NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy)
656
- {
657
- if (filePath == NULL) return nil;
658
-
659
- char *lastSlash = NULL;
660
- char *lastDot = NULL;
661
-
662
- char *p = (char *)filePath;
663
-
664
- while (*p != '\0')
665
- {
666
- if (*p == '/')
667
- lastSlash = p;
668
- else if (*p == '.')
669
- lastDot = p;
670
-
671
- p++;
672
- }
673
-
674
- char *subStr;
675
- NSUInteger subLen;
676
-
677
- if (lastSlash)
678
- {
679
- if (lastDot)
680
- {
681
- // lastSlash -> lastDot
682
- subStr = lastSlash + 1;
683
- subLen = lastDot - subStr;
684
- }
685
- else
686
- {
687
- // lastSlash -> endOfString
688
- subStr = lastSlash + 1;
689
- subLen = p - subStr;
690
- }
691
- }
692
- else
693
- {
694
- if (lastDot)
695
- {
696
- // startOfString -> lastDot
697
- subStr = (char *)filePath;
698
- subLen = lastDot - subStr;
699
- }
700
- else
701
- {
702
- // startOfString -> endOfString
703
- subStr = (char *)filePath;
704
- subLen = p - subStr;
705
- }
706
- }
707
-
708
- if (copy)
709
- {
710
- return [[NSString alloc] initWithBytes:subStr
711
- length:subLen
712
- encoding:NSUTF8StringEncoding];
713
- }
714
- else
715
- {
716
- // We can take advantage of the fact that __FILE__ is a string literal.
717
- // Specifically, we don't need to waste time copying the string.
718
- // We can just tell NSString to point to a range within the string literal.
719
-
720
- return [[NSString alloc] initWithBytesNoCopy:subStr
721
- length:subLen
722
- encoding:NSUTF8StringEncoding
723
- freeWhenDone:NO];
724
- }
725
- }
726
-
727
- @end
728
-
729
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
730
- #pragma mark -
731
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
732
-
733
- @implementation DDLoggerNode
734
-
735
- - (id)initWithLogger:(id <DDLogger>)aLogger loggerQueue:(dispatch_queue_t)aLoggerQueue
736
- {
737
- if ((self = [super init]))
738
- {
739
- logger = aLogger;
740
-
741
- if (aLoggerQueue) {
742
- loggerQueue = aLoggerQueue;
743
- dispatch_retain(loggerQueue);
744
- }
745
- }
746
- return self;
747
- }
748
-
749
- + (DDLoggerNode *)nodeWithLogger:(id <DDLogger>)logger loggerQueue:(dispatch_queue_t)loggerQueue
750
- {
751
- return [[DDLoggerNode alloc] initWithLogger:logger loggerQueue:loggerQueue];
752
- }
753
-
754
- - (void)dealloc
755
- {
756
- if (loggerQueue) {
757
- dispatch_release(loggerQueue);
758
- }
759
- }
760
-
761
- @end
762
-
763
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
764
- #pragma mark -
765
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
766
-
767
- @implementation DDLogMessage
768
-
769
- - (id)initWithLogMsg:(NSString *)msg
770
- level:(int)level
771
- flag:(int)flag
772
- context:(int)context
773
- file:(const char *)aFile
774
- function:(const char *)aFunction
775
- line:(int)line
776
- tag:(id)aTag
777
- {
778
- if ((self = [super init]))
779
- {
780
- logMsg = msg;
781
- logLevel = level;
782
- logFlag = flag;
783
- logContext = context;
784
- file = aFile;
785
- function = aFunction;
786
- lineNumber = line;
787
- tag = aTag;
788
-
789
- timestamp = [[NSDate alloc] init];
790
-
791
- machThreadID = pthread_mach_thread_np(pthread_self());
792
-
793
- const char *label = dispatch_queue_get_label(dispatch_get_current_queue());
794
- if (label)
795
- {
796
- size_t labelLength = strlen(label);
797
- queueLabel = malloc(labelLength+1);
798
- strncpy(queueLabel, label, labelLength);
799
- queueLabel[labelLength] = 0;
800
- }
801
-
802
- threadName = [[NSThread currentThread] name];
803
- }
804
- return self;
805
- }
806
-
807
- - (NSString *)threadID
808
- {
809
- return [[NSString alloc] initWithFormat:@"%x", machThreadID];
810
- }
811
-
812
- - (NSString *)fileName
813
- {
814
- return DDExtractFileNameWithoutExtension(file, NO);
815
- }
816
-
817
- - (NSString *)methodName
818
- {
819
- if (function == NULL)
820
- return nil;
821
- else
822
- return [[NSString alloc] initWithUTF8String:function];
823
- }
824
-
825
- - (void)dealloc
826
- {
827
- if (queueLabel != NULL) {
828
- free(queueLabel);
829
- }
830
- }
831
-
832
- @end
833
-
834
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
835
- #pragma mark -
836
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
837
-
838
- @implementation DDAbstractLogger
839
-
840
- - (id)init
841
- {
842
- if ((self = [super init]))
843
- {
844
- const char *loggerQueueName = NULL;
845
- if ([self respondsToSelector:@selector(loggerName)])
846
- {
847
- loggerQueueName = [[self loggerName] UTF8String];
848
- }
849
-
850
- loggerQueue = dispatch_queue_create(loggerQueueName, NULL);
851
- }
852
- return self;
853
- }
854
-
855
- - (void)dealloc
856
- {
857
- if (loggerQueue) dispatch_release(loggerQueue);
858
- }
859
-
860
- - (void)logMessage:(DDLogMessage *)logMessage
861
- {
862
- // Override me
863
- }
864
-
865
- - (id <DDLogFormatter>)logFormatter
866
- {
867
- // This method must be thread safe and intuitive.
868
- // Therefore if somebody executes the following code:
869
- //
870
- // [logger setLogFormatter:myFormatter];
871
- // formatter = [logger logFormatter];
872
- //
873
- // They would expect formatter to equal myFormatter.
874
- // This functionality must be ensured by the getter and setter method.
875
- //
876
- // The thread safety must not come at a cost to the performance of the logMessage method.
877
- // This method is likely called sporadically, while the logMessage method is called repeatedly.
878
- // This means, the implementation of this method:
879
- // - Must NOT require the logMessage method to acquire a lock.
880
- // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts).
881
- //
882
- // Thread safety is ensured by executing access to the formatter variable on the loggerQueue.
883
- // This is the same queue that the logMessage method operates on.
884
- //
885
- // Note: The last time I benchmarked the performance of direct access vs atomic property access,
886
- // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone.
887
- //
888
- //
889
- // loggerQueue : Our own private internal queue that the logMessage method runs on.
890
- // Operations are added to this queue from the global loggingQueue.
891
- //
892
- // loggingQueue : The queue that all log messages go through before they arrive in our loggerQueue.
893
- //
894
- // It is important to note that, while the loggerQueue is used to create thread-safety for our formatter,
895
- // changes to the formatter variable are queued through the loggingQueue.
896
- //
897
- // Since this will obviously confuse the hell out of me later, here is a better description.
898
- // Imagine the following code:
899
- //
900
- // DDLogVerbose(@"log msg 1");
901
- // DDLogVerbose(@"log msg 2");
902
- // [logger setFormatter:myFormatter];
903
- // DDLogVerbose(@"log msg 3");
904
- //
905
- // Our intuitive requirement means that the new formatter will only apply to the 3rd log message.
906
- // But notice what happens if we have asynchronous logging enabled for verbose mode.
907
- //
908
- // Log msg 1 starts executing asynchronously on the loggingQueue.
909
- // The loggingQueue executes the log statement on each logger concurrently.
910
- // That means it executes log msg 1 on our loggerQueue.
911
- // While log msg 1 is executing, log msg 2 gets added to the loggingQueue.
912
- // Then the user requests that we change our formatter.
913
- // So at this exact moment, our queues look like this:
914
- //
915
- // loggerQueue : executing log msg 1, nil
916
- // loggingQueue : executing log msg 1, log msg 2, nil
917
- //
918
- // So direct access to the formatter is only available if requested from the loggerQueue.
919
- // In all other circumstances we need to go through the loggingQueue to get the proper value.
920
-
921
- dispatch_queue_t currentQueue = dispatch_get_current_queue();
922
- if (currentQueue == loggerQueue)
923
- {
924
- return formatter;
925
- }
926
- else
927
- {
928
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
929
- NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
930
-
931
- __block id <DDLogFormatter> result;
932
-
933
- dispatch_sync(globalLoggingQueue, ^{
934
- dispatch_sync(loggerQueue, ^{
935
- result = formatter;
936
- });
937
- });
938
-
939
- return result;
940
- }
941
- }
942
-
943
- - (void)setLogFormatter:(id <DDLogFormatter>)logFormatter
944
- {
945
- // The design of this method is documented extensively in the logFormatter message (above in code).
946
-
947
- dispatch_block_t block = ^{
948
- if (formatter != logFormatter) {
949
- formatter = logFormatter;
950
- }
951
- };
952
-
953
- dispatch_queue_t currentQueue = dispatch_get_current_queue();
954
- if (currentQueue == loggerQueue)
955
- {
956
- block();
957
- }
958
- else
959
- {
960
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
961
- NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
962
-
963
- dispatch_async(globalLoggingQueue, ^{
964
- dispatch_async(loggerQueue, block);
965
- });
966
- }
967
- }
968
-
969
- - (dispatch_queue_t)loggerQueue
970
- {
971
- return loggerQueue;
972
- }
973
-
974
- - (NSString *)loggerName
975
- {
976
- return NSStringFromClass([self class]);
977
- }
978
-
979
- @end