0%

CocoaLumberJack源码学习

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给出的图。

CocoaLumberjackClassDiagram.png

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

DDLoggerInformation

1
2
3
4
5
6
{
// Direct accessors to be used only for performance
@public
id <DDLogger> _logger;
DDLogLevel _level;
}

DDExtractFileNameWithoutExtension 提取文件名

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。