iOS學(xué)習(xí)筆記系列 - CocoaLumberjack

今天幾乎花了一整天時間去看這個庫,也算是有些心得,總結(jié)一下。

目錄:

  1. 總綱
  2. CocoaLumberjack項目架構(gòu)
  3. 自定義日志分類
  4. 日志過濾及格式
  5. 文件日志

1. 總綱

CocoaLumberjack是個非常好用的開源日志庫,做iOS的應(yīng)該多多少少都有接觸??赡苡行┤藢@個名字不是很熟悉的,但代碼上用的最多的日志命令DDLogInfo總還是見過的吧,它就是CocoaLumberjack提供的一個宏。

這篇文章主要看一下這個庫的架構(gòu),和一些實際應(yīng)用上的概念。為什么要看這些呢?原因有三:

  • 了解除了平常的用DDLogInfo,DDLogError打一些日志之外,它還可以幫我們干什么;
  • 如何去實現(xiàn)這些高級功能,比如配置自定義的日志框架,如何精確控制什么時候打什么日志,如何配置文件日志等等;
  • 由于CocoaLumberjack是個開源項目,感興趣的讀者還可以在看完這篇文章之后去為開源社區(qū)貢獻(xiàn)自己的一份力量。

2. CocoaLumberjack架構(gòu)

總的來說,這個庫由四個部分組成:DDLog, DDLogger, DDLogMessage, DDLogFormatter。我們逐個分析一下。

2.1 DDLog與DDLogger

如上圖所示,DDLog是整個庫的入口,我們平時用的DDLogLevel等宏就是直接調(diào)用DDLog的接口。一個DDLog包含著一個或多個DDLogger,比如常用的DDTTYLogger,DDASLLogger等等。當(dāng)我們調(diào)用DDLogInfo的時候,DDLog會把已有的DDLogger全部遍歷一遍,對于每個DDLogger都會調(diào)用其logMessage接口。當(dāng)然細(xì)心的讀者會意識到,這些操作不可能同步(SYNC)進(jìn)行。而且如果要保證日志的相對順序,必然會給DDLogger分配一個專屬的線性隊列(SERIAL_QUEUE)。詳情可以參考筆者之前寫的關(guān)于GCD的介紹

2.2 DDLogger,DDLogFormatter與DDLogMessage

這三者之間的關(guān)系,用圖像解釋反而更加容易迷惑,還是用文字吧。

先闡述一下整個流程。DDLog調(diào)用DDLogger的時候,傳入的是一個DDLogMessage實例。這個實例除了日志內(nèi)容本身之外,還包含了關(guān)于這個日志的輔助信息,主要包括日志等級(level),環(huán)境(context),隊列(queueLabel),標(biāo)簽(tag)時間戳(timestamp)等等,他們的用法下面會有詳細(xì)介紹。接著,DDLogger里面如果有DDLogFormatter的話,會先調(diào)用DDLogFormatter處理日志格式,對日志進(jìn)行過濾等等操作,然后把日志打到Logger對應(yīng)的位置。

這里要注意,每個DDLogger最多只能有一個DDLogFormatter實例,可以通過setLogFormatter:設(shè)置。但是,如果有需要同時應(yīng)用多個DDLogFormatter的話,可以使用框架內(nèi)置的一個DDMultiFormatter把需要用的整合到一起。這樣就使得用戶自定義formatter非常的方便。這里要注意兩點:

  • DDMultiFormatter應(yīng)用formatter時,是按照其添加的順序逐個依次線性地進(jìn)行的,所以往DDMultiFormatter上添加formatter時一定要注意添加的順序;
  • 雖然DDLogFormatter名字上叫做Formatter,它的功能并不局限于改變?nèi)罩镜母袷?。你還可以用它來過濾日志等等。
2.3 DDLogMessage相關(guān)屬性

DDLogMessage屬性的作用是給DDLogFormatter足夠的信息去修改日志格式以及進(jìn)行過濾篩選等操作。這里貼一下DDLogMessage的屬性列表:

@interface DDLogMessage : NSObject <NSCopying>
{
    // Direct accessors to be used only for performance
    @public
    NSString *_message;
    DDLogLevel _level;
    DDLogFlag _flag;
    NSInteger _context;
    NSString *_file;
    NSString *_fileName;
    NSString *_function;
    NSUInteger _line;
    id _tag;
    DDLogMessageOptions _options;
    NSDate *_timestamp;
    NSString *_threadID;
    NSString *_threadName;
    NSString *_queueLabel;
}

大部分屬性都相對比較容易理解,這里想著重梳理一下contextlevel。截止至寫作日期,Github上的文檔還沒有更新,所以如果你去讀文檔的話,會感到非常混亂。CocoaLumberjack自從v2.x.x以來,社區(qū)大幅度地改變了對這兩個屬性的定義。

按照文檔所說,用戶可以通過在自己的頭文件里#define自定義日志等級。但是如果你去試試就會發(fā)現(xiàn)根本行不通。原因是自從2.x版本以后,日志等級的定義方式由原來的宏改成了枚舉(NS_ENUM)。這幾乎杜絕了用戶自定義日志等級。

3. 自定義日志分類

那么用戶想在原有的幾個等級上添加更詳細(xì)的分類怎么辦呢?沒錯,用 context。CocoaLumberjack默認(rèn)context的值都是0. 如果你想添加新的分類,比如說DDLogNetwork,你需要做的就是定義自己的context 值。

#define LOG_CONTEXT_NETWORK 1

然后定義自己的宏:

#define DDLogNetworkInfo(frmt, ...)    LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo,   LOG_CONTEXT_NETWORK, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)

這樣的好處在于對日志等級和日志環(huán)境有了一個比較清晰的界定,也給了用戶更多的自主權(quán)。比如說用戶可以很方便地定義DDLogNetworkWarningDDLogNetworkError, 等等。而不用像文檔里面所說的先定義LOG_FLAG然后再用它來定義LOG_LEVEL之類復(fù)雜的操作。

4. 日志過濾及改變?nèi)罩靖袷?/h3>

按照上面所說的流程,日志過濾應(yīng)該是DDLogFormatter的職責(zé)。沒錯,CocoaLumberjack自帶了幾個DDLogFormatter,包括DDContextWhitelistFilterLogFormatter, DDDispatchQueueLogFormatter等。前者可以通過設(shè)置context白名單過濾日志,適用于比如只想讓當(dāng)前Logger打某個環(huán)境值的日志。最常用的情況就是希望自定義一個新的分類,然后只把該分類的日志都打到一個文件里面。用法如下:

DDContextWhitelistFilterLogFormatter *contextFilter = [[DDContextWhitelistFilterLogFormatter alloc] init];
[contextFilter addToWhitelist: LOG_LEVEL_NETWORK];
[[DDTTYLogger sharedInstance] setLogFormatter:contextFilter];
[[DDLog addLogger:[DDTTYLogger sharedInstance] withLevel:DDLogLevelInfo];

這兩個formatter只是個用法示例,用戶完全可以根據(jù)自己的需要依樣畫葫蘆,自定義格式化工具和過濾,然后加進(jìn)指定的DDLogger。

5. 文件日志

CocoaLumberjack自帶了一個文件日志類:DDFileLogger。如果不需要自定義日志路徑的話,用法比較簡單:

DDFileLogger *fileLogger = [[DDFileLogger alloc] init];
[DDLog addLogger:fileLogger withLevel:DDLogLevelInfo];

默認(rèn)日志路徑在:
/app/path/Library/Cached/。
如果需要自定義日志路徑的話,需要稍微多幾行代碼:

NSString *path = "/Some/Path";
id<DDLogFileManager> logFileManager = [[DDLogFileManagerDefault alloc] initWithLogsDirectory:path];
logFileManager.maximumNumberOfLogFiles = 5; //可自行調(diào)整

DDFileLogger *fileLogger = [[DDFileLogger alloc] init];
fileLogger.rollingFrequency = 24*60*60; // 一天,可自行調(diào)整
[DDLog addLogger:fileLogger withLevel:DDLogLevelInfo];

寫在最后

今天大概就先寫到這里,希望能幫到有需要的人。如果有什么疑問歡迎在下面回復(fù)提出,筆者將盡量及時作出回復(fù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,047評論 4 61
  • 老大,可能一開始就是我錯了,把關(guān)系搞得那么復(fù)雜,sorry??! 是挺尷尬的,第一次喲!鼓起多大的勇氣就呼出多少的嘆...
    做人吶閱讀 262評論 0 0
  • 因工作需要被派到中心icu學(xué)習(xí)半個月。 從急診來到重癥才發(fā)現(xiàn),原來這里的同仁們比我們更辛苦,更專業(yè)。 因重癥監(jiān)護(hù)室...
    翌驍媽媽閱讀 411評論 0 1

友情鏈接更多精彩內(nèi)容