Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pmbaty | 1 | #import <Foundation/Foundation.h> |
2 | #import "DDLog.h" |
||
3 | |||
4 | @class DDLogFileInfo; |
||
5 | |||
6 | /** |
||
7 | * Welcome to Cocoa Lumberjack! |
||
8 | * |
||
9 | * The project page has a wealth of documentation if you have any questions. |
||
10 | * https://github.com/CocoaLumberjack/CocoaLumberjack |
||
11 | * |
||
12 | * If you're new to the project you may wish to read the "Getting Started" wiki. |
||
13 | * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted |
||
14 | * |
||
15 | * |
||
16 | * This class provides a logger to write log statements to a file. |
||
17 | **/ |
||
18 | |||
19 | |||
20 | // Default configuration and safety/sanity values. |
||
21 | // |
||
22 | // maximumFileSize -> DEFAULT_LOG_MAX_FILE_SIZE |
||
23 | // rollingFrequency -> DEFAULT_LOG_ROLLING_FREQUENCY |
||
24 | // maximumNumberOfLogFiles -> DEFAULT_LOG_MAX_NUM_LOG_FILES |
||
25 | // |
||
26 | // You should carefully consider the proper configuration values for your application. |
||
27 | |||
28 | #define DEFAULT_LOG_MAX_FILE_SIZE (1024 * 1024) // 1 MB |
||
29 | #define DEFAULT_LOG_ROLLING_FREQUENCY (60 * 60 * 24) // 24 Hours |
||
30 | #define DEFAULT_LOG_MAX_NUM_LOG_FILES (5) // 5 Files |
||
31 | |||
32 | |||
33 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
34 | #pragma mark - |
||
35 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
36 | |||
37 | // The LogFileManager protocol is designed to allow you to control all aspects of your log files. |
||
38 | // |
||
39 | // The primary purpose of this is to allow you to do something with the log files after they have been rolled. |
||
40 | // Perhaps you want to compress them to save disk space. |
||
41 | // Perhaps you want to upload them to an FTP server. |
||
42 | // Perhaps you want to run some analytics on the file. |
||
43 | // |
||
44 | // A default LogFileManager is, of course, provided. |
||
45 | // The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property. |
||
46 | // |
||
47 | // This protocol provides various methods to fetch the list of log files. |
||
48 | // |
||
49 | // There are two variants: sorted and unsorted. |
||
50 | // If sorting is not necessary, the unsorted variant is obviously faster. |
||
51 | // The sorted variant will return an array sorted by when the log files were created, |
||
52 | // with the most recently created log file at index 0, and the oldest log file at the end of the array. |
||
53 | // |
||
54 | // You can fetch only the log file paths (full path including name), log file names (name only), |
||
55 | // or an array of DDLogFileInfo objects. |
||
56 | // The DDLogFileInfo class is documented below, and provides a handy wrapper that |
||
57 | // gives you easy access to various file attributes such as the creation date or the file size. |
||
58 | |||
59 | @protocol DDLogFileManager <NSObject> |
||
60 | @required |
||
61 | |||
62 | // Public properties |
||
63 | |||
64 | /** |
||
65 | * The maximum number of archived log files to keep on disk. |
||
66 | * For example, if this property is set to 3, |
||
67 | * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk. |
||
68 | * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted. |
||
69 | * |
||
70 | * You may optionally disable deleting old/rolled/archived log files by setting this property to zero. |
||
71 | **/ |
||
72 | @property (readwrite, assign) NSUInteger maximumNumberOfLogFiles; |
||
73 | |||
74 | // Public methods |
||
75 | |||
76 | - (NSString *)logsDirectory; |
||
77 | |||
78 | - (NSArray *)unsortedLogFilePaths; |
||
79 | - (NSArray *)unsortedLogFileNames; |
||
80 | - (NSArray *)unsortedLogFileInfos; |
||
81 | |||
82 | - (NSArray *)sortedLogFilePaths; |
||
83 | - (NSArray *)sortedLogFileNames; |
||
84 | - (NSArray *)sortedLogFileInfos; |
||
85 | |||
86 | // Private methods (only to be used by DDFileLogger) |
||
87 | |||
88 | - (NSString *)createNewLogFile; |
||
89 | |||
90 | @optional |
||
91 | |||
92 | // Notifications from DDFileLogger |
||
93 | |||
94 | - (void)didArchiveLogFile:(NSString *)logFilePath; |
||
95 | - (void)didRollAndArchiveLogFile:(NSString *)logFilePath; |
||
96 | |||
97 | @end |
||
98 | |||
99 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
100 | #pragma mark - |
||
101 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
102 | |||
103 | /** |
||
104 | * Default log file manager. |
||
105 | * |
||
106 | * All log files are placed inside the logsDirectory. |
||
107 | * If a specific logsDirectory isn't specified, the default directory is used. |
||
108 | * On Mac, this is in ~/Library/Logs/<Application Name>. |
||
109 | * On iPhone, this is in ~/Library/Caches/Logs. |
||
110 | * |
||
111 | * Log files are named "<app name> <date> <time>.log" |
||
112 | * Example: MobileSafari 2013-12-03 17-14.log |
||
113 | * |
||
114 | * Archived log files are automatically deleted according to the maximumNumberOfLogFiles property. |
||
115 | **/ |
||
116 | @interface DDLogFileManagerDefault : NSObject <DDLogFileManager> |
||
117 | { |
||
118 | NSUInteger maximumNumberOfLogFiles; |
||
119 | NSString *_logsDirectory; |
||
120 | } |
||
121 | |||
122 | - (id)init; |
||
123 | - (instancetype)initWithLogsDirectory:(NSString *)logsDirectory; |
||
124 | |||
125 | /* Inherited from DDLogFileManager protocol: |
||
126 | |||
127 | @property (readwrite, assign) NSUInteger maximumNumberOfLogFiles; |
||
128 | |||
129 | - (NSString *)logsDirectory; |
||
130 | |||
131 | - (NSArray *)unsortedLogFilePaths; |
||
132 | - (NSArray *)unsortedLogFileNames; |
||
133 | - (NSArray *)unsortedLogFileInfos; |
||
134 | |||
135 | - (NSArray *)sortedLogFilePaths; |
||
136 | - (NSArray *)sortedLogFileNames; |
||
137 | - (NSArray *)sortedLogFileInfos; |
||
138 | |||
139 | */ |
||
140 | |||
141 | @end |
||
142 | |||
143 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
144 | #pragma mark - |
||
145 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
146 | |||
147 | /** |
||
148 | * Most users will want file log messages to be prepended with the date and time. |
||
149 | * Rather than forcing the majority of users to write their own formatter, |
||
150 | * we will supply a logical default formatter. |
||
151 | * Users can easily replace this formatter with their own by invoking the setLogFormatter method. |
||
152 | * It can also be removed by calling setLogFormatter, and passing a nil parameter. |
||
153 | * |
||
154 | * In addition to the convenience of having a logical default formatter, |
||
155 | * it will also provide a template that makes it easy for developers to copy and change. |
||
156 | **/ |
||
157 | @interface DDLogFileFormatterDefault : NSObject <DDLogFormatter> |
||
158 | { |
||
159 | NSDateFormatter *dateFormatter; |
||
160 | } |
||
161 | |||
162 | - (id)init; |
||
163 | - (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter; |
||
164 | |||
165 | @end |
||
166 | |||
167 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
168 | #pragma mark - |
||
169 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
170 | |||
171 | @interface DDFileLogger : DDAbstractLogger <DDLogger> |
||
172 | { |
||
173 | __strong id <DDLogFileManager> logFileManager; |
||
174 | |||
175 | DDLogFileInfo *currentLogFileInfo; |
||
176 | NSFileHandle *currentLogFileHandle; |
||
177 | |||
178 | dispatch_source_t currentLogFileVnode; |
||
179 | dispatch_source_t rollingTimer; |
||
180 | |||
181 | unsigned long long maximumFileSize; |
||
182 | NSTimeInterval rollingFrequency; |
||
183 | } |
||
184 | |||
185 | - (id)init; |
||
186 | - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager; |
||
187 | |||
188 | /** |
||
189 | * Log File Rolling: |
||
190 | * |
||
191 | * maximumFileSize: |
||
192 | * The approximate maximum size to allow log files to grow. |
||
193 | * If a log file is larger than this value after a log statement is appended, |
||
194 | * then the log file is rolled. |
||
195 | * |
||
196 | * rollingFrequency |
||
197 | * How often to roll the log file. |
||
198 | * The frequency is given as an NSTimeInterval, which is a double that specifies the interval in seconds. |
||
199 | * Once the log file gets to be this old, it is rolled. |
||
200 | * |
||
201 | * Both the maximumFileSize and the rollingFrequency are used to manage rolling. |
||
202 | * Whichever occurs first will cause the log file to be rolled. |
||
203 | * |
||
204 | * For example: |
||
205 | * The rollingFrequency is 24 hours, |
||
206 | * but the log file surpasses the maximumFileSize after only 20 hours. |
||
207 | * The log file will be rolled at that 20 hour mark. |
||
208 | * A new log file will be created, and the 24 hour timer will be restarted. |
||
209 | * |
||
210 | * You may optionally disable rolling due to filesize by setting maximumFileSize to zero. |
||
211 | * If you do so, rolling is based solely on rollingFrequency. |
||
212 | * |
||
213 | * You may optionally disable rolling due to time by setting rollingFrequency to zero (or any non-positive number). |
||
214 | * If you do so, rolling is based solely on maximumFileSize. |
||
215 | * |
||
216 | * If you disable both maximumFileSize and rollingFrequency, then the log file won't ever be rolled. |
||
217 | * This is strongly discouraged. |
||
218 | **/ |
||
219 | @property (readwrite, assign) unsigned long long maximumFileSize; |
||
220 | @property (readwrite, assign) NSTimeInterval rollingFrequency; |
||
221 | |||
222 | /** |
||
223 | * The DDLogFileManager instance can be used to retrieve the list of log files, |
||
224 | * and configure the maximum number of archived log files to keep. |
||
225 | * |
||
226 | * @see DDLogFileManager.maximumNumberOfLogFiles |
||
227 | **/ |
||
228 | @property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager; |
||
229 | |||
230 | |||
231 | // You can optionally force the current log file to be rolled with this method. |
||
232 | // CompletionBlock will be called on main queue. |
||
233 | |||
234 | - (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock; |
||
235 | |||
236 | // Method is deprecated. Use rollLogFileWithCompletionBlock: method instead. |
||
237 | |||
238 | - (void)rollLogFile __attribute((deprecated)); |
||
239 | |||
240 | // Inherited from DDAbstractLogger |
||
241 | |||
242 | // - (id <DDLogFormatter>)logFormatter; |
||
243 | // - (void)setLogFormatter:(id <DDLogFormatter>)formatter; |
||
244 | |||
245 | @end |
||
246 | |||
247 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
248 | #pragma mark - |
||
249 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
250 | |||
251 | /** |
||
252 | * DDLogFileInfo is a simple class that provides access to various file attributes. |
||
253 | * It provides good performance as it only fetches the information if requested, |
||
254 | * and it caches the information to prevent duplicate fetches. |
||
255 | * |
||
256 | * It was designed to provide quick snapshots of the current state of log files, |
||
257 | * and to help sort log files in an array. |
||
258 | * |
||
259 | * This class does not monitor the files, or update it's cached attribute values if the file changes on disk. |
||
260 | * This is not what the class was designed for. |
||
261 | * |
||
262 | * If you absolutely must get updated values, |
||
263 | * you can invoke the reset method which will clear the cache. |
||
264 | **/ |
||
265 | @interface DDLogFileInfo : NSObject |
||
266 | { |
||
267 | __strong NSString *filePath; |
||
268 | __strong NSString *fileName; |
||
269 | |||
270 | __strong NSDictionary *fileAttributes; |
||
271 | |||
272 | __strong NSDate *creationDate; |
||
273 | __strong NSDate *modificationDate; |
||
274 | |||
275 | unsigned long long fileSize; |
||
276 | } |
||
277 | |||
278 | @property (strong, nonatomic, readonly) NSString *filePath; |
||
279 | @property (strong, nonatomic, readonly) NSString *fileName; |
||
280 | |||
281 | @property (strong, nonatomic, readonly) NSDictionary *fileAttributes; |
||
282 | |||
283 | @property (strong, nonatomic, readonly) NSDate *creationDate; |
||
284 | @property (strong, nonatomic, readonly) NSDate *modificationDate; |
||
285 | |||
286 | @property (nonatomic, readonly) unsigned long long fileSize; |
||
287 | |||
288 | @property (nonatomic, readonly) NSTimeInterval age; |
||
289 | |||
290 | @property (nonatomic, readwrite) BOOL isArchived; |
||
291 | |||
292 | + (instancetype)logFileWithPath:(NSString *)filePath; |
||
293 | |||
294 | - (instancetype)initWithFilePath:(NSString *)filePath; |
||
295 | |||
296 | - (void)reset; |
||
297 | - (void)renameFile:(NSString *)newFileName; |
||
298 | |||
299 | #if TARGET_IPHONE_SIMULATOR |
||
300 | |||
301 | // So here's the situation. |
||
302 | // Extended attributes are perfect for what we're trying to do here (marking files as archived). |
||
303 | // This is exactly what extended attributes were designed for. |
||
304 | // |
||
305 | // But Apple screws us over on the simulator. |
||
306 | // Everytime you build-and-go, they copy the application into a new folder on the hard drive, |
||
307 | // and as part of the process they strip extended attributes from our log files. |
||
308 | // Normally, a copy of a file preserves extended attributes. |
||
309 | // So obviously Apple has gone to great lengths to piss us off. |
||
310 | // |
||
311 | // Thus we use a slightly different tactic for marking log files as archived in the simulator. |
||
312 | // That way it "just works" and there's no confusion when testing. |
||
313 | // |
||
314 | // The difference in method names is indicative of the difference in functionality. |
||
315 | // On the simulator we add an attribute by appending a filename extension. |
||
316 | // |
||
317 | // For example: |
||
318 | // log-ABC123.txt -> log-ABC123.archived.txt |
||
319 | |||
320 | - (BOOL)hasExtensionAttributeWithName:(NSString *)attrName; |
||
321 | |||
322 | - (void)addExtensionAttributeWithName:(NSString *)attrName; |
||
323 | - (void)removeExtensionAttributeWithName:(NSString *)attrName; |
||
324 | |||
325 | #else |
||
326 | |||
327 | // Normal use of extended attributes used everywhere else, |
||
328 | // such as on Macs and on iPhone devices. |
||
329 | |||
330 | - (BOOL)hasExtendedAttributeWithName:(NSString *)attrName; |
||
331 | |||
332 | - (void)addExtendedAttributeWithName:(NSString *)attrName; |
||
333 | - (void)removeExtendedAttributeWithName:(NSString *)attrName; |
||
334 | |||
335 | #endif |
||
336 | |||
337 | - (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another; |
||
338 | - (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another; |
||
339 | |||
340 | @end |