CocoaLumberJack是一个用于mac或者iOS的日志库,简单易用, 可扩展。
可以通过设置Logger,分别把日志写入文件、终端、系统日志中。
DDLogLevel 7个等级
库不大,代码结构比较清晰。
使用 我用的cocopods、oc。
修改podfile
1 2 3 4 // podfile pod 'CocoaLumberjack'
代码
1 2 3 4 5 6 7 8 9 #import <CocoaLumberjack/CocoaLumberjack.h> // 引用头文件 static DDLogLevel ddLogLevel = DDLogLevelAll; // 定义全局变量 ... DDLogInfo(@"message"); ...
代码解读 主要代码类可以参考GitHub给出的图。
DDLog 这个是对外的接口, 所有API都是直接调用这个接口的类方法进行写日志的。
有一个单例和一个队列。 所有写日志操作,最终都是在同一个队列进行操作的。
日志可以写到不同的输出终端, 通过DDLogger协议来控制, DDLog可以添加多个DDLogger协议的对象(具体的都是抽象类DDAbstractLogger的子类)。
1 2 3 4 5 6 7 8 9 10 11 12 // _loggingQueue // _loggingGroup // _queueSemaphore // _numProcessors _loggingGroup 用于并发输出 UIApplicationWillTerminateNotification 执行 flushLog applicationWillTerminate
DDLogMessage 日志信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { // Direct accessors to be used only for performance @public NSString *_message; // 内容 DDLogLevel _level; // 等级 DDLogFlag _flag; // 用于过滤等级的信息, 只有 _level & _flag == 1 才会输出 NSInteger _context; // 可以用来过滤, 参考 DDContextWhitelistFilterLogFormatter NSString *_file; // 输出文件路径 NSString *_fileName; // 输出文件名 NSString *_function; // ?? NSUInteger _line; id _tag; // ?? DDLogMessageOptions _options; NSDate *_timestamp; NSString *_threadID; NSString *_threadName; NSString *_queueLabel; }
_loggerQueue
DDAbstractLogger 抽象的logger,
可以设置logFormatter、loggerQueue
logFormatter可以对输出的日志再格式化。
DDLoggerNode 用于记录logger的信息 1 2 3 4 5 6 7 8 9 10 11 12 @interface DDLoggerNode : NSObject { // Direct accessors to be used only for performance @public id <DDLogger> _logger; DDLogLevel _level; dispatch_queue_t _loggerQueue; } @property (nonatomic, readonly) id <DDLogger> logger; @property (nonatomic, readonly) DDLogLevel level; @property (nonatomic, readonly) dispatch_queue_t loggerQueue;
不同的logger输出, 又在各自的queue中操作。
DDLogger protocol 1 2 3 - (void)logMessage:(DDLogMessage *)logMessage NS_SWIFT_NAME(log(message:)); @property (nonatomic, strong) id <DDLogFormatter> logFormatter;
DDTTYLogger 写到tty的logger
DDOSLogger usr/include/os/log.h
os_log_create os_log_error os_log_info
DDASLLogger asl.h // 废弃了, 使用 usr/include/os/log.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 _client = asl_open(NULL, "com.apple.console", 0); { const char *msg = [message UTF8String]; size_t aslLogLevel; switch (logMessage->_flag) { // Note: By default ASL will filter anything above level 5 (Notice). // So our mappings shouldn't go above that level. case DDLogFlagError : aslLogLevel = ASL_LEVEL_CRIT; break; case DDLogFlagWarning : aslLogLevel = ASL_LEVEL_ERR; break; case DDLogFlagInfo : aslLogLevel = ASL_LEVEL_WARNING; break; // Regular NSLog's level case DDLogFlagDebug : case DDLogFlagVerbose : default : aslLogLevel = ASL_LEVEL_NOTICE; break; } static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; // NSLog uses the current euid to set the ASL_KEY_READ_UID. uid_t const readUID = geteuid(); char readUIDString[16]; #ifndef NS_BLOCK_ASSERTIONS size_t l = (size_t)snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); #else snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); #endif NSAssert(l < sizeof(readUIDString), @"Formatted euid is too long."); NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])), @"Unhandled ASL log level."); aslmsg m = asl_new(ASL_TYPE_MSG); if (m != NULL) { if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 && asl_set(m, ASL_KEY_MSG, msg) == 0 && asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 && asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) { asl_send(_client, m); } asl_free(m); } //TODO handle asl_* failures non-silently? }
OS_OBJECT_USE_OBJC 用于判断系统是否是6.0以前的? 6.0之后才定义了这个宏。
dispatch_group_async
1 2 3 4 5 6 { // Direct accessors to be used only for performance @public id <DDLogger> _logger; DDLogLevel _level; }
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。