1.使用
- 自定义custom context,自定义flag
- 自定义日志的格式
- 自定义日志级别,取消DDLog实现自定义。
- 动态更改日志级别、使用userDefault保持上次更改记录、动态注册,为每个类添加日志的级别。
- 仅过滤出想要的日志级别,如LOG_ERROR;将同类型的日志归为一组。
2.文件结构
这份代码看到了面向接口编程的影子,与敏捷开发案例中的代码结构类似。
2.1 DDLogger
- DDAbstractLogger实现了DDLogger协议,子类: DDASLLogger、DDFileLogger、DDOSLogger、DDTTYLogger
- DDASLLogger:此类为终端输出或Xcode控制台输出提供了记录器,logMessage是C的,没看懂。
- DDFileLogger:管理文件。
- DDOSLogger:mac系统日志,暂时不用。
- DDTTYLogger:此类为终端输出或Xcode控制台输出提供了记录器,与DDASLLogger处理控制台颜色,暂时不用。
DDLoggerNode:model,DDLogger、loggerQueue、level的一个封装
DDLog单例:_loggers管理多个对象
DDLogMessage:消息对象
DDLogger:logMessage:DDLogMessage 添加消息时,带入消息对象到各个管理文件进行不同操作。在此之前会对数据按自定义或默认格式进行格式化
_logFormatter:提前配置好的。
2.2DDLogFormatter
DDContextFilterLogFormatter:过滤消息,白名单输出日志,黑名单不输出日志
DDDispatchQueueLogFormatter:打印队列日志
DDMultiFormatter:可添加多个日志格式消息;再次验证,栅栏函数使用自定义并发队列,在添加、移除时使用栅栏函数,获取消息时使用同步访问。
3.宏定义直接调用方法:DDlog
3.1宏的调用流程
__ PRETTY_FUNCTION __ 宏产生整个函数签名 - 返回类型,类名和所有参数,可能很长
## __VA_ARGS__ 是一个可变参数的宏,实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)
#undef 取消宏定义
#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
[DDLog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : (frmt), ## __VA_ARGS__]
#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \
do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0)
#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \
LOG_MAYBE(async, lvl, flg, ctx, __PRETTY_FUNCTION__, frmt, ## __VA_ARGS__)
//if(lvl & flg) 定义了lvl才能打印,调用了DDLog log
3.2 分析DDLogDebug
#define DDLogDebug(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG, LOG_LEVEL_DEF, LOG_FLAG_DEBUG, 0, frmt, ##VA_ARGS)
第一个参数LOG_ASYNC_DEBUG
#define LOG_ASYNC_ENABLED YES
#define LOG_ASYNC_ERROR ( NO && LOG_ASYNC_ENABLED)
#define LOG_ASYNC_DEBUG (YES && LOG_ASYNC_ENABLED)
该字段表示是否异步,除了DDLogError是同步,其余都是异步日志。第二个参数
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF ddLogLevel
#endif
#ifndef 如果没有定义LOG_LEVEL_DEF,定义一个默认的ddLogLevel,用户自定义的第三个参数
LOG_FLAG_DEBUG:与DDLogFlag宏对应,采用的是位偏移量
lvl & flg可以产生想要的结果其他参数
定义可变参数
4.OC代码流程
4.1流程
- 调用宏->+log(DDLog)->消息封装成DDLogMessage->queueLogMessage(DDLog)->lt_log(DDLog)
- 遍历数组_loggers调用logMessage进行消息分发
4.2 思路
DDLog 管理一个队列,队列中存放的是id
+logFormatter:DDLogFormatter 获取日志时,通过DDLogFormatter获取不同格式的日志,包括黑白名单、队列、多日志等。
5.文件管理
分为两部分:一部分是写入文件、另一部分是管理文件
滚动
maximumFileSize:最大文件个数
rollingFrequency:按时间进行滚动
日志压缩上传
您可能已经猜到了DDFileLogger
实现,它分为两个部分。 DDFileLogger是将日志消息写入文件的组件。 DDLogFileManager是一种协议,用于管理日志文件,并决定在滚动日志文件后如何处理。
6. 感想
- 初看时,作者的架构非常清晰,面向接口编程。有UML图给出类关系,document详细的日志,每个类的头部都带有简介说明此类作用,重要方法都有详细注释。
- 再看,发现作者对宏的使用出神入化。可变参数,打印函数的返回值、方法名、参数等,#ifndef定义ddLogLevel,取消作者定义的宏实现用户自定义
- 再看,发现框架扩展性非常强。日志级别、日志格式、Context、flag、动态修改LogLevel、每个用户等都是可以自定义。这才是可扩展的框架。