Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pmbaty | 1 | #import <Foundation/Foundation.h> |
2 | |||
3 | /** |
||
4 | * Welcome to Cocoa Lumberjack! |
||
5 | * |
||
6 | * The project page has a wealth of documentation if you have any questions. |
||
7 | * https://github.com/CocoaLumberjack/CocoaLumberjack |
||
8 | * |
||
9 | * If you're new to the project you may wish to read the "Getting Started" wiki. |
||
10 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted |
||
11 | * |
||
12 | * Otherwise, here is a quick refresher. |
||
13 | * There are three steps to using the macros: |
||
14 | * |
||
15 | * Step 1: |
||
16 | * Import the header in your implementation file: |
||
17 | * |
||
18 | * #import "DDLog.h" |
||
19 | * |
||
20 | * Step 2: |
||
21 | * Define your logging level in your implementation file: |
||
22 | * |
||
23 | * // Log levels: off, error, warn, info, verbose |
||
24 | * static const int ddLogLevel = LOG_LEVEL_VERBOSE; |
||
25 | * |
||
26 | * Step 2 [3rd party frameworks]: |
||
27 | * |
||
28 | * Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel: |
||
29 | * |
||
30 | * // #undef LOG_LEVEL_DEF // Undefine first only if needed |
||
31 | * #define LOG_LEVEL_DEF myLibLogLevel |
||
32 | * |
||
33 | * Define your logging level in your implementation file: |
||
34 | * |
||
35 | * // Log levels: off, error, warn, info, verbose |
||
36 | * static const int myLibLogLevel = LOG_LEVEL_VERBOSE; |
||
37 | * |
||
38 | * Step 3: |
||
39 | * Replace your NSLog statements with DDLog statements according to the severity of the message. |
||
40 | * |
||
41 | * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!"); |
||
42 | * |
||
43 | * DDLog works exactly the same as NSLog. |
||
44 | * This means you can pass it multiple variables just like NSLog. |
||
45 | **/ |
||
46 | |||
47 | #ifndef LOG_LEVEL_DEF |
||
48 | #define LOG_LEVEL_DEF ddLogLevel |
||
49 | #endif |
||
50 | |||
51 | @class DDLogMessage; |
||
52 | |||
53 | @protocol DDLogger; |
||
54 | @protocol DDLogFormatter; |
||
55 | |||
56 | /** |
||
57 | * This is the single macro that all other macros below compile into. |
||
58 | * This big multiline macro makes all the other macros easier to read. |
||
59 | **/ |
||
60 | |||
61 | #define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \ |
||
62 | [DDLog log:isAsynchronous \ |
||
63 | level:lvl \ |
||
64 | flag:flg \ |
||
65 | context:ctx \ |
||
66 | file:__FILE__ \ |
||
67 | function:fnct \ |
||
68 | line:__LINE__ \ |
||
69 | tag:atag \ |
||
70 | format:(frmt), ##__VA_ARGS__] |
||
71 | |||
72 | /** |
||
73 | * Define the Objective-C and C versions of the macro. |
||
74 | * These automatically inject the proper function name for either an objective-c method or c function. |
||
75 | * |
||
76 | * We also define shorthand versions for asynchronous and synchronous logging. |
||
77 | **/ |
||
78 | |||
79 | #define LOG_OBJC_MACRO(async, lvl, flg, ctx, frmt, ...) \ |
||
80 | LOG_MACRO(async, lvl, flg, ctx, nil, sel_getName(_cmd), frmt, ##__VA_ARGS__) |
||
81 | |||
82 | #define LOG_C_MACRO(async, lvl, flg, ctx, frmt, ...) \ |
||
83 | LOG_MACRO(async, lvl, flg, ctx, nil, __FUNCTION__, frmt, ##__VA_ARGS__) |
||
84 | |||
85 | #define SYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \ |
||
86 | LOG_OBJC_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
87 | |||
88 | #define ASYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \ |
||
89 | LOG_OBJC_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
90 | |||
91 | #define SYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \ |
||
92 | LOG_C_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
93 | |||
94 | #define ASYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \ |
||
95 | LOG_C_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
96 | |||
97 | /** |
||
98 | * Define version of the macro that only execute if the logLevel is above the threshold. |
||
99 | * The compiled versions essentially look like this: |
||
100 | * |
||
101 | * if (logFlagForThisLogMsg & ddLogLevel) { execute log message } |
||
102 | * |
||
103 | * When LOG_LEVEL_DEF is defined as ddLogLevel. |
||
104 | * |
||
105 | * As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels. |
||
106 | * This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques. |
||
107 | * |
||
108 | * Note that when compiler optimizations are enabled (as they are for your release builds), |
||
109 | * the log messages above your logging threshold will automatically be compiled out. |
||
110 | * |
||
111 | * (If the compiler sees ddLogLevel declared as a constant, the compiler simply checks to see if the 'if' statement |
||
112 | * would execute, and if not it strips it from the binary.) |
||
113 | * |
||
114 | * We also define shorthand versions for asynchronous and synchronous logging. |
||
115 | **/ |
||
116 | |||
117 | #define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \ |
||
118 | do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0) |
||
119 | |||
120 | #define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \ |
||
121 | LOG_MAYBE(async, lvl, flg, ctx, sel_getName(_cmd), frmt, ##__VA_ARGS__) |
||
122 | |||
123 | #define LOG_C_MAYBE(async, lvl, flg, ctx, frmt, ...) \ |
||
124 | LOG_MAYBE(async, lvl, flg, ctx, __FUNCTION__, frmt, ##__VA_ARGS__) |
||
125 | |||
126 | #define SYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \ |
||
127 | LOG_OBJC_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
128 | |||
129 | #define ASYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \ |
||
130 | LOG_OBJC_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
131 | |||
132 | #define SYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \ |
||
133 | LOG_C_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
134 | |||
135 | #define ASYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \ |
||
136 | LOG_C_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) |
||
137 | |||
138 | /** |
||
139 | * Define versions of the macros that also accept tags. |
||
140 | * |
||
141 | * The DDLogMessage object includes a 'tag' ivar that may be used for a variety of purposes. |
||
142 | * It may be used to pass custom information to loggers or formatters. |
||
143 | * Or it may be used by 3rd party extensions to the framework. |
||
144 | * |
||
145 | * Thes macros just make it a little easier to extend logging functionality. |
||
146 | **/ |
||
147 | |||
148 | #define LOG_OBJC_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \ |
||
149 | LOG_MACRO(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__) |
||
150 | |||
151 | #define LOG_C_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \ |
||
152 | LOG_MACRO(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__) |
||
153 | |||
154 | #define LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \ |
||
155 | do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0) |
||
156 | |||
157 | #define LOG_OBJC_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \ |
||
158 | LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__) |
||
159 | |||
160 | #define LOG_C_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \ |
||
161 | LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__) |
||
162 | |||
163 | /** |
||
164 | * Define the standard options. |
||
165 | * |
||
166 | * We default to only 4 levels because it makes it easier for beginners |
||
167 | * to make the transition to a logging framework. |
||
168 | * |
||
169 | * More advanced users may choose to completely customize the levels (and level names) to suite their needs. |
||
170 | * For more information on this see the "Custom Log Levels" page: |
||
171 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/CustomLogLevels |
||
172 | * |
||
173 | * Advanced users may also notice that we're using a bitmask. |
||
174 | * This is to allow for custom fine grained logging: |
||
175 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/FineGrainedLogging |
||
176 | * |
||
177 | * -- Flags -- |
||
178 | * |
||
179 | * Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations. |
||
180 | * For example, say you have a lot of warning log messages, and you wanted to disable them. |
||
181 | * However, you still needed to see your error and info log messages. |
||
182 | * You could accomplish that with the following: |
||
183 | * |
||
184 | * static const int ddLogLevel = LOG_FLAG_ERROR | LOG_FLAG_INFO; |
||
185 | * |
||
186 | * When LOG_LEVEL_DEF is defined as ddLogLevel. |
||
187 | * |
||
188 | * Flags may also be consulted when writing custom log formatters, |
||
189 | * as the DDLogMessage class captures the individual flag that caused the log message to fire. |
||
190 | * |
||
191 | * -- Levels -- |
||
192 | * |
||
193 | * Log levels are simply the proper bitmask of the flags. |
||
194 | * |
||
195 | * -- Booleans -- |
||
196 | * |
||
197 | * The booleans may be used when your logging code involves more than one line. |
||
198 | * For example: |
||
199 | * |
||
200 | * if (LOG_VERBOSE) { |
||
201 | * for (id sprocket in sprockets) |
||
202 | * DDLogVerbose(@"sprocket: %@", [sprocket description]) |
||
203 | * } |
||
204 | * |
||
205 | * -- Async -- |
||
206 | * |
||
207 | * Defines the default asynchronous options. |
||
208 | * The default philosophy for asynchronous logging is very simple: |
||
209 | * |
||
210 | * Log messages with errors should be executed synchronously. |
||
211 | * After all, an error just occurred. The application could be unstable. |
||
212 | * |
||
213 | * All other log messages, such as debug output, are executed asynchronously. |
||
214 | * After all, if it wasn't an error, then it was just informational output, |
||
215 | * or something the application was easily able to recover from. |
||
216 | * |
||
217 | * -- Changes -- |
||
218 | * |
||
219 | * You are strongly discouraged from modifying this file. |
||
220 | * If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project. |
||
221 | * Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h |
||
222 | * |
||
223 | * For an example of customizing your logging experience, see the "Custom Log Levels" page: |
||
224 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/CustomLogLevels |
||
225 | **/ |
||
226 | |||
227 | #define LOG_FLAG_ERROR (1 << 0) // 0...00001 |
||
228 | #define LOG_FLAG_WARN (1 << 1) // 0...00010 |
||
229 | #define LOG_FLAG_INFO (1 << 2) // 0...00100 |
||
230 | #define LOG_FLAG_DEBUG (1 << 3) // 0...01000 |
||
231 | #define LOG_FLAG_VERBOSE (1 << 4) // 0...10000 |
||
232 | |||
233 | #define LOG_LEVEL_OFF 0 |
||
234 | #define LOG_LEVEL_ERROR (LOG_FLAG_ERROR) // 0...00001 |
||
235 | #define LOG_LEVEL_WARN (LOG_FLAG_ERROR | LOG_FLAG_WARN) // 0...00011 |
||
236 | #define LOG_LEVEL_INFO (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO) // 0...00111 |
||
237 | #define LOG_LEVEL_DEBUG (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO | LOG_FLAG_DEBUG) // 0...01111 |
||
238 | #define LOG_LEVEL_VERBOSE (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO | LOG_FLAG_DEBUG | LOG_FLAG_VERBOSE) // 0...11111 |
||
239 | |||
240 | #define LOG_ERROR (LOG_LEVEL_DEF & LOG_FLAG_ERROR) |
||
241 | #define LOG_WARN (LOG_LEVEL_DEF & LOG_FLAG_WARN) |
||
242 | #define LOG_INFO (LOG_LEVEL_DEF & LOG_FLAG_INFO) |
||
243 | #define LOG_DEBUG (LOG_LEVEL_DEF & LOG_FLAG_DEBUG) |
||
244 | #define LOG_VERBOSE (LOG_LEVEL_DEF & LOG_FLAG_VERBOSE) |
||
245 | |||
246 | #define LOG_ASYNC_ENABLED YES |
||
247 | |||
248 | #define LOG_ASYNC_ERROR ( NO && LOG_ASYNC_ENABLED) |
||
249 | #define LOG_ASYNC_WARN (YES && LOG_ASYNC_ENABLED) |
||
250 | #define LOG_ASYNC_INFO (YES && LOG_ASYNC_ENABLED) |
||
251 | #define LOG_ASYNC_DEBUG (YES && LOG_ASYNC_ENABLED) |
||
252 | #define LOG_ASYNC_VERBOSE (YES && LOG_ASYNC_ENABLED) |
||
253 | |||
254 | #define DDLogError(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_ERROR, LOG_LEVEL_DEF, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__) |
||
255 | #define DDLogWarn(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_WARN, LOG_LEVEL_DEF, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__) |
||
256 | #define DDLogInfo(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_INFO, LOG_LEVEL_DEF, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__) |
||
257 | #define DDLogDebug(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG, LOG_LEVEL_DEF, LOG_FLAG_DEBUG, 0, frmt, ##__VA_ARGS__) |
||
258 | #define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, LOG_LEVEL_DEF, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__) |
||
259 | |||
260 | #define DDLogCError(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_ERROR, LOG_LEVEL_DEF, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__) |
||
261 | #define DDLogCWarn(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_WARN, LOG_LEVEL_DEF, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__) |
||
262 | #define DDLogCInfo(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_INFO, LOG_LEVEL_DEF, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__) |
||
263 | #define DDLogCDebug(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_DEBUG, LOG_LEVEL_DEF, LOG_FLAG_DEBUG, 0, frmt, ##__VA_ARGS__) |
||
264 | #define DDLogCVerbose(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_VERBOSE, LOG_LEVEL_DEF, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__) |
||
265 | |||
266 | /** |
||
267 | * The THIS_FILE macro gives you an NSString of the file name. |
||
268 | * For simplicity and clarity, the file name does not include the full path or file extension. |
||
269 | * |
||
270 | * For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy" |
||
271 | **/ |
||
272 | |||
273 | NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy); |
||
274 | |||
275 | #define THIS_FILE (DDExtractFileNameWithoutExtension(__FILE__, NO)) |
||
276 | |||
277 | /** |
||
278 | * The THIS_METHOD macro gives you the name of the current objective-c method. |
||
279 | * |
||
280 | * For example: DDLogWarn(@"%@ - Requires non-nil strings", THIS_METHOD) -> @"setMake:model: requires non-nil strings" |
||
281 | * |
||
282 | * Note: This does NOT work in straight C functions (non objective-c). |
||
283 | * Instead you should use the predefined __FUNCTION__ macro. |
||
284 | **/ |
||
285 | |||
286 | #define THIS_METHOD NSStringFromSelector(_cmd) |
||
287 | |||
288 | |||
289 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
290 | #pragma mark - |
||
291 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
292 | |||
293 | @interface DDLog : NSObject |
||
294 | |||
295 | /** |
||
296 | * Provides access to the underlying logging queue. |
||
297 | * This may be helpful to Logger classes for things like thread synchronization. |
||
298 | **/ |
||
299 | |||
300 | + (dispatch_queue_t)loggingQueue; |
||
301 | |||
302 | /** |
||
303 | * Logging Primitive. |
||
304 | * |
||
305 | * This method is used by the macros above. |
||
306 | * It is suggested you stick with the macros as they're easier to use. |
||
307 | **/ |
||
308 | |||
309 | + (void)log:(BOOL)synchronous |
||
310 | level:(int)level |
||
311 | flag:(int)flag |
||
312 | context:(int)context |
||
313 | file:(const char *)file |
||
314 | function:(const char *)function |
||
315 | line:(int)line |
||
316 | tag:(id)tag |
||
317 | format:(NSString *)format, ... __attribute__ ((format (__NSString__, 9, 10))); |
||
318 | |||
319 | /** |
||
320 | * Logging Primitive. |
||
321 | * |
||
322 | * This method can be used if you have a prepared va_list. |
||
323 | **/ |
||
324 | |||
325 | + (void)log:(BOOL)asynchronous |
||
326 | level:(int)level |
||
327 | flag:(int)flag |
||
328 | context:(int)context |
||
329 | file:(const char *)file |
||
330 | function:(const char *)function |
||
331 | line:(int)line |
||
332 | tag:(id)tag |
||
333 | format:(NSString *)format |
||
334 | args:(va_list)argList; |
||
335 | |||
336 | |||
337 | /** |
||
338 | * Since logging can be asynchronous, there may be times when you want to flush the logs. |
||
339 | * The framework invokes this automatically when the application quits. |
||
340 | **/ |
||
341 | |||
342 | + (void)flushLog; |
||
343 | |||
344 | /** |
||
345 | * Loggers |
||
346 | * |
||
347 | * If you want your log statements to go somewhere, |
||
348 | * you should create and add a logger. |
||
349 | **/ |
||
350 | |||
351 | + (void)addLogger:(id <DDLogger>)logger; // adds the logger using maximum log level (LOG_LEVEL_VERBOSE) |
||
352 | |||
353 | /** |
||
354 | * Please use as logLevels the LOG_LEVEL_* macros |
||
355 | * |
||
356 | **/ |
||
357 | + (void)addLogger:(id <DDLogger>)logger withLogLevel:(int)logLevel; |
||
358 | |||
359 | + (void)removeLogger:(id <DDLogger>)logger; |
||
360 | + (void)removeAllLoggers; |
||
361 | |||
362 | /** |
||
363 | * Registered Dynamic Logging |
||
364 | * |
||
365 | * These methods allow you to obtain a list of classes that are using registered dynamic logging, |
||
366 | * and also provides methods to get and set their log level during run time. |
||
367 | **/ |
||
368 | |||
369 | + (NSArray *)registeredClasses; |
||
370 | + (NSArray *)registeredClassNames; |
||
371 | |||
372 | + (int)logLevelForClass:(Class)aClass; |
||
373 | + (int)logLevelForClassWithName:(NSString *)aClassName; |
||
374 | |||
375 | + (void)setLogLevel:(int)logLevel forClass:(Class)aClass; |
||
376 | + (void)setLogLevel:(int)logLevel forClassWithName:(NSString *)aClassName; |
||
377 | |||
378 | @end |
||
379 | |||
380 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
381 | #pragma mark - |
||
382 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
383 | |||
384 | @protocol DDLogger <NSObject> |
||
385 | @required |
||
386 | |||
387 | - (void)logMessage:(DDLogMessage *)logMessage; |
||
388 | |||
389 | /** |
||
390 | * Formatters may optionally be added to any logger. |
||
391 | * |
||
392 | * If no formatter is set, the logger simply logs the message as it is given in logMessage, |
||
393 | * or it may use its own built in formatting style. |
||
394 | **/ |
||
395 | - (id <DDLogFormatter>)logFormatter; |
||
396 | - (void)setLogFormatter:(id <DDLogFormatter>)formatter; |
||
397 | |||
398 | @optional |
||
399 | |||
400 | /** |
||
401 | * Since logging is asynchronous, adding and removing loggers is also asynchronous. |
||
402 | * In other words, the loggers are added and removed at appropriate times with regards to log messages. |
||
403 | * |
||
404 | * - Loggers will not receive log messages that were executed prior to when they were added. |
||
405 | * - Loggers will not receive log messages that were executed after they were removed. |
||
406 | * |
||
407 | * These methods are executed in the logging thread/queue. |
||
408 | * This is the same thread/queue that will execute every logMessage: invocation. |
||
409 | * Loggers may use these methods for thread synchronization or other setup/teardown tasks. |
||
410 | **/ |
||
411 | - (void)didAddLogger; |
||
412 | - (void)willRemoveLogger; |
||
413 | |||
414 | /** |
||
415 | * Some loggers may buffer IO for optimization purposes. |
||
416 | * For example, a database logger may only save occasionaly as the disk IO is slow. |
||
417 | * In such loggers, this method should be implemented to flush any pending IO. |
||
418 | * |
||
419 | * This allows invocations of DDLog's flushLog method to be propogated to loggers that need it. |
||
420 | * |
||
421 | * Note that DDLog's flushLog method is invoked automatically when the application quits, |
||
422 | * and it may be also invoked manually by the developer prior to application crashes, or other such reasons. |
||
423 | **/ |
||
424 | - (void)flush; |
||
425 | |||
426 | /** |
||
427 | * Each logger is executed concurrently with respect to the other loggers. |
||
428 | * Thus, a dedicated dispatch queue is used for each logger. |
||
429 | * Logger implementations may optionally choose to provide their own dispatch queue. |
||
430 | **/ |
||
431 | - (dispatch_queue_t)loggerQueue; |
||
432 | |||
433 | /** |
||
434 | * If the logger implementation does not choose to provide its own queue, |
||
435 | * one will automatically be created for it. |
||
436 | * The created queue will receive its name from this method. |
||
437 | * This may be helpful for debugging or profiling reasons. |
||
438 | **/ |
||
439 | - (NSString *)loggerName; |
||
440 | |||
441 | @end |
||
442 | |||
443 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
444 | #pragma mark - |
||
445 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
446 | |||
447 | @protocol DDLogFormatter <NSObject> |
||
448 | @required |
||
449 | |||
450 | /** |
||
451 | * Formatters may optionally be added to any logger. |
||
452 | * This allows for increased flexibility in the logging environment. |
||
453 | * For example, log messages for log files may be formatted differently than log messages for the console. |
||
454 | * |
||
455 | * For more information about formatters, see the "Custom Formatters" page: |
||
456 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/CustomFormatters |
||
457 | * |
||
458 | * The formatter may also optionally filter the log message by returning nil, |
||
459 | * in which case the logger will not log the message. |
||
460 | **/ |
||
461 | - (NSString *)formatLogMessage:(DDLogMessage *)logMessage; |
||
462 | |||
463 | @optional |
||
464 | |||
465 | /** |
||
466 | * A single formatter instance can be added to multiple loggers. |
||
467 | * These methods provides hooks to notify the formatter of when it's added/removed. |
||
468 | * |
||
469 | * This is primarily for thread-safety. |
||
470 | * If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers. |
||
471 | * Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter), |
||
472 | * it could possibly use these hooks to switch to thread-safe versions of the code. |
||
473 | **/ |
||
474 | - (void)didAddToLogger:(id <DDLogger>)logger; |
||
475 | - (void)willRemoveFromLogger:(id <DDLogger>)logger; |
||
476 | |||
477 | @end |
||
478 | |||
479 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
480 | #pragma mark - |
||
481 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
482 | |||
483 | @protocol DDRegisteredDynamicLogging |
||
484 | |||
485 | /** |
||
486 | * Implement these methods to allow a file's log level to be managed from a central location. |
||
487 | * |
||
488 | * This is useful if you'd like to be able to change log levels for various parts |
||
489 | * of your code from within the running application. |
||
490 | * |
||
491 | * Imagine pulling up the settings for your application, |
||
492 | * and being able to configure the logging level on a per file basis. |
||
493 | * |
||
494 | * The implementation can be very straight-forward: |
||
495 | * |
||
496 | * + (int)ddLogLevel |
||
497 | * { |
||
498 | * return ddLogLevel; |
||
499 | * } |
||
500 | * |
||
501 | * + (void)ddSetLogLevel:(int)logLevel |
||
502 | * { |
||
503 | * ddLogLevel = logLevel; |
||
504 | * } |
||
505 | **/ |
||
506 | |||
507 | + (int)ddLogLevel; |
||
508 | + (void)ddSetLogLevel:(int)logLevel; |
||
509 | |||
510 | @end |
||
511 | |||
512 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
513 | #pragma mark - |
||
514 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
515 | |||
516 | /** |
||
517 | * The DDLogMessage class encapsulates information about the log message. |
||
518 | * If you write custom loggers or formatters, you will be dealing with objects of this class. |
||
519 | **/ |
||
520 | |||
521 | enum { |
||
522 | DDLogMessageCopyFile = 1 << 0, |
||
523 | DDLogMessageCopyFunction = 1 << 1 |
||
524 | }; |
||
525 | typedef int DDLogMessageOptions; |
||
526 | |||
527 | @interface DDLogMessage : NSObject <NSCopying> |
||
528 | { |
||
529 | |||
530 | // The public variables below can be accessed directly (for speed). |
||
531 | // For example: logMessage->logLevel |
||
532 | |||
533 | @public |
||
534 | int logLevel; |
||
535 | int logFlag; |
||
536 | int logContext; |
||
537 | NSString *logMsg; |
||
538 | NSDate *timestamp; |
||
539 | char *file; |
||
540 | char *function; |
||
541 | int lineNumber; |
||
542 | mach_port_t machThreadID; |
||
543 | char *queueLabel; |
||
544 | NSString *threadName; |
||
545 | |||
546 | // For 3rd party extensions to the framework, where flags and contexts aren't enough. |
||
547 | id tag; |
||
548 | |||
549 | // For 3rd party extensions that manually create DDLogMessage instances. |
||
550 | DDLogMessageOptions options; |
||
551 | } |
||
552 | |||
553 | /** |
||
554 | * Standard init method for a log message object. |
||
555 | * Used by the logging primitives. (And the macros use the logging primitives.) |
||
556 | * |
||
557 | * If you find need to manually create logMessage objects, there is one thing you should be aware of: |
||
558 | * |
||
559 | * If no flags are passed, the method expects the file and function parameters to be string literals. |
||
560 | * That is, it expects the given strings to exist for the duration of the object's lifetime, |
||
561 | * and it expects the given strings to be immutable. |
||
562 | * In other words, it does not copy these strings, it simply points to them. |
||
563 | * This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters, |
||
564 | * so it makes sense to optimize and skip the unnecessary allocations. |
||
565 | * However, if you need them to be copied you may use the options parameter to specify this. |
||
566 | * Options is a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction. |
||
567 | **/ |
||
568 | - (instancetype)initWithLogMsg:(NSString *)logMsg |
||
569 | level:(int)logLevel |
||
570 | flag:(int)logFlag |
||
571 | context:(int)logContext |
||
572 | file:(const char *)file |
||
573 | function:(const char *)function |
||
574 | line:(int)line |
||
575 | tag:(id)tag |
||
576 | options:(DDLogMessageOptions)optionsMask; |
||
577 | |||
578 | /** |
||
579 | * Returns the threadID as it appears in NSLog. |
||
580 | * That is, it is a hexadecimal value which is calculated from the machThreadID. |
||
581 | **/ |
||
582 | - (NSString *)threadID; |
||
583 | |||
584 | /** |
||
585 | * Convenience property to get just the file name, as the file variable is generally the full file path. |
||
586 | * This method does not include the file extension, which is generally unwanted for logging purposes. |
||
587 | **/ |
||
588 | - (NSString *)fileName; |
||
589 | |||
590 | /** |
||
591 | * Returns the function variable in NSString form. |
||
592 | **/ |
||
593 | - (NSString *)methodName; |
||
594 | |||
595 | @end |
||
596 | |||
597 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
598 | #pragma mark - |
||
599 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
600 | |||
601 | /** |
||
602 | * The DDLogger protocol specifies that an optional formatter can be added to a logger. |
||
603 | * Most (but not all) loggers will want to support formatters. |
||
604 | * |
||
605 | * However, writting getters and setters in a thread safe manner, |
||
606 | * while still maintaining maximum speed for the logging process, is a difficult task. |
||
607 | * |
||
608 | * To do it right, the implementation of the getter/setter has strict requiremenets: |
||
609 | * - Must NOT require the logMessage method to acquire a lock. |
||
610 | * - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). |
||
611 | * |
||
612 | * To simplify things, an abstract logger is provided that implements the getter and setter. |
||
613 | * |
||
614 | * Logger implementations may simply extend this class, |
||
615 | * and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their logMessage method! |
||
616 | **/ |
||
617 | |||
618 | @interface DDAbstractLogger : NSObject <DDLogger> |
||
619 | { |
||
620 | id <DDLogFormatter> formatter; |
||
621 | |||
622 | dispatch_queue_t loggerQueue; |
||
623 | } |
||
624 | |||
625 | - (id <DDLogFormatter>)logFormatter; |
||
626 | - (void)setLogFormatter:(id <DDLogFormatter>)formatter; |
||
627 | |||
628 | // For thread-safety assertions |
||
629 | - (BOOL)isOnGlobalLoggingQueue; |
||
630 | - (BOOL)isOnInternalLoggerQueue; |
||
631 | |||
632 | @end |