深入CocoaLumberjack日志系統(tǒng)

引入

在iOS開發(fā)中咆课,日志系統(tǒng)是很重要的一個(gè)部分唤崭,尤其是在修復(fù)代碼中的bug棕孙,通常會(huì)用NSLog來將這些信息打印到XCode控制臺(tái)中顯示舔亭,但在日志信息較多的時(shí)候,會(huì)出現(xiàn)一些性能上的問題蟀俊。因?yàn)镹SLog在使用的時(shí)候占用資源較多钦铺,其設(shè)計(jì)也是基于ASL(Apple System Log)的高層封裝,針對(duì)error log肢预。所以在對(duì)性能要求較高的地方矛洞,不能用NSLog進(jìn)行調(diào)試。

作為NSLog的替代烫映,CocoaLumberjack是一款優(yōu)秀的第三方日志系統(tǒng)沼本。官方的介紹如下:

CocoaLumberjack is a fast & simple, yet powerful & flexible logging framework for Mac and iOS.

It is similar in concept to other popular logging frameworks such as log4j, yet is designed specifically
for Objective-C, and takes advantage of features such as multi-threading, grand central dispatch (if available),
lockless atomic operations, and the dynamic nature of the Objective-C runtime.

支持用CocoaPods和Carthage部署到項(xiàng)目中,當(dāng)前的系統(tǒng)要求如下:

在設(shè)計(jì)中锭沟,CocoaLumberjack使用了大量的GCD語法抽兆,使性能更好;宏定義的使用族淮,讓API接口語法更加簡便辫红;加上整體架構(gòu)的設(shè)計(jì)獨(dú)特,使這套第三方日志系統(tǒng)更利于根據(jù)一些特殊需求來定制功能祝辣。

代碼分析

使用CocoaLumberjack的時(shí)候贴妻,會(huì)引用其頭文件,Oc的項(xiàng)目引用CocoaLumberjack.h蝙斜,swift項(xiàng)目CocoaLumberjack.swift名惩。

這里,我們從CocoaLumberjack.h展開孕荠,文件開頭給出了大段的注釋信息绢片,詳細(xì)介紹了關(guān)于該日志系統(tǒng)的使用(在該源碼的其他頭文件中,同樣可以看到消息的注釋信息岛琼,對(duì)該接口甚至類的設(shè)計(jì)進(jìn)行解說,可見一套優(yōu)秀的開源項(xiàng)目在細(xì)節(jié)上是做的多么細(xì)致巢株,值得學(xué)習(xí)槐瑞!),隨后阁苞,引入了一系列的頭文件:

  1. DDLog是該日志系統(tǒng)中核心的部分困檩,接口調(diào)用都通過該類進(jìn)行調(diào)用祠挫,在該類中封裝了許多的協(xié)議和基礎(chǔ)類,也算是作為整個(gè)日志系統(tǒng)的執(zhí)行中樞悼沿,給整套架構(gòu)打下基礎(chǔ)等舔。

  2. DDLogMacros.hDDAssertMacros.h這兩個(gè)文件中定義了大量的宏,都是對(duì)DDLog的接口進(jìn)行的封裝糟趾,封裝后慌植,對(duì)DDLog的使用變得更加簡單。

  3. DDASLLogCapture是用來捕獲ASL消息的工具類义郑。

  4. DDTTYLogger蝶柿、DDASLLoggerDDFileLoggerDDOSLogger是提供具體日志功能的類非驮,分別對(duì)應(yīng)著控制臺(tái)日志功能交汤、ASL日志功能、文件日志功能和oslog日志功能劫笙。如果需要增加新的日志功能芙扎,可以模仿這幾個(gè)類,實(shí)現(xiàn)新功能填大。

DDLog類

是單例戒洼,其內(nèi)部維持了一個(gè)dispatch_queue_tdispatch_group_t和信號(hào)鎖dispatch_semaphore_t(最大為1000個(gè)線程同時(shí)訪問),通過這類GCD屬性可以很好地發(fā)揮出多線程的優(yōu)勢(shì)栋盹。此外在該類中還維持著一個(gè)loggers數(shù)組施逾,數(shù)組里面的每個(gè)元素為DDLoggerNode類型的元素。DDLogDDLoggerNode來保存被添加的logger(同之前介紹的logger)例获,并將添加logger時(shí)的level和logger中維持的線程也一并添加到DDLoggerNode里汉额。這樣當(dāng)DDLog需要log一條message的時(shí)候,就會(huì)去遍歷這個(gè)數(shù)組榨汤,然后根據(jù)level在相應(yīng)的dispatch_queue_t中執(zhí)行蠕搜。

DDLog中,定義了創(chuàng)建logger需要的一些接口和基礎(chǔ)類收壕,DDLoggerDDLogFormatter是兩個(gè)協(xié)議妓灌,DDLogger是創(chuàng)建的logger必須遵循的協(xié)議,內(nèi)部的定義如下:

- (void)logMessage:(DDLogMessage *)logMessage NS_SWIFT_NAME(log(message:));

@property (nonatomic, strong) id <DDLogFormatter> logFormatter;

@optional

- (void)didAddLogger;

- (void)didAddLoggerInQueue:(dispatch_queue_t)queue;

- (void)willRemoveLogger;

- (void)flush;

@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggerQueue;

@property (nonatomic, readonly) NSString *loggerName;

其中logMessage是用來被調(diào)用執(zhí)行l(wèi)og的接口蜜宪,在DDLog中被調(diào)用;logFormatter是一個(gè)遵循DDLogFormatter協(xié)議的類虫埂,主要用來控制log的格式(控制臺(tái)輸出或者存入文件);接下來的did和will開頭的接口為事件響應(yīng),可以選擇去實(shí)現(xiàn)在相應(yīng)事件發(fā)生時(shí)候的處理圃验;flush是在一些關(guān)系內(nèi)存和io操作需要實(shí)現(xiàn)的類掉伏,它可以控制在內(nèi)存不足的時(shí)候?qū)uffer存入磁盤或者相關(guān)的數(shù)據(jù)庫;最后loggerQueueloggerName用來獲取在logger中維持的線程隊(duì)列,loggerName是用來創(chuàng)建隊(duì)列用的名字斧散,在DDAbstractLogger中可以看到logger線程隊(duì)列是如何維持的供常。

在創(chuàng)建logger的時(shí)候,只需繼承于DDAbstractLogger鸡捐,其內(nèi)部會(huì)維持一個(gè)CDG隊(duì)列栈暇,然后遵循DDLogger協(xié)議,接口都在協(xié)議里面定義好了箍镜。在logger里面只需專注于功能的實(shí)現(xiàn)源祈,這樣可以省去很多接口定義和屬性維持方面的事。

同樣在DDLog里面會(huì)出現(xiàn)很多類似 id<DDLogger> 的屬性鹿寨,通過協(xié)議新博,即使不知道其具體實(shí)現(xiàn),也可以調(diào)用接口脚草。通過DDAbstractLogger基類和DDLogger協(xié)議赫悄,為拓展做了很好的基礎(chǔ)。

CocoaLumberjack的架構(gòu)關(guān)系如下圖:

對(duì)比實(shí)驗(yàn)

蘋果官方在2016年的WWDC上放出了新的日志系統(tǒng)(The unified logging system)馏慨,提供了日志信息分類統(tǒng)計(jì)和關(guān)鍵信息捕捉等功能埂淮,而且在速度上會(huì)更快、使用更方便写隶、提供給開發(fā)者的可控性也更多倔撞。

最后對(duì)命令行輸出效率進(jìn)行實(shí)驗(yàn),這里對(duì)NSLog慕趴、printf痪蝇、os_logwritev在命令行的輸出性能進(jìn)行了對(duì)比:

    CFAbsoluteTime startNSLog = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < 10000; i++) {
        NSLog(@"%d", i);
    }
    CFAbsoluteTime endNSLog = CFAbsoluteTimeGetCurrent();
    
    CFAbsoluteTime startPrintf = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < 10000; i++) {
        printf("%d\n", i);
    }
    CFAbsoluteTime endPrintf = CFAbsoluteTimeGetCurrent();
    
    CFAbsoluteTime startOsLog = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < 10000; i++) {
        os_log(OS_LOG_DEFAULT, "%d\n", i);
    }
    CFAbsoluteTime endOsLog = CFAbsoluteTimeGetCurrent();
    
    CFAbsoluteTime startWritev = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < 10000; i++) {
        struct iovec v[1];
        v[0].iov_base = "a\n";
        v[0].iov_len = 2;
        writev(STDERR_FILENO, v, 1);
    }
    CFAbsoluteTime endWritev = CFAbsoluteTimeGetCurrent();
    
    NSLog(@"NSLog time: %lf, printf time: %lf", endNSLog - startNSLog, endPrintf - startPrintf);
    NSLog(@"OsLog time: %lf, writev time: %lf", endOsLog - startOsLog, endWritev - startWritev);

Mac電腦上的運(yùn)行時(shí)間:


虛擬機(jī)運(yùn)行時(shí)間:


真機(jī)運(yùn)行時(shí)間:


通過對(duì)比可知,采用writev和printf這種底層的命令行輸出效率最高冕房。

總結(jié):

  1. CocoaLumberjack架構(gòu)設(shè)計(jì)精妙躏啰,接口易于拓展定制功能。
  2. 蘋果提供了新的日志系統(tǒng)API耙册,但在命令行的輸出上底層接口的效率更高给僵。

參考:
NSLog效率低下的原因及嘗試lldb斷點(diǎn)打印Log
WWDC2016 session721
Logging

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市详拙,隨后出現(xiàn)的幾起案子帝际,更是在濱河造成了極大的恐慌,老刑警劉巖饶辙,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹲诀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弃揽,警方通過查閱死者的電腦和手機(jī)侧甫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門珊佣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人披粟,你說我怎么就攤上這事±淙撸” “怎么了守屉?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蒿辙。 經(jīng)常有香客問我拇泛,道長,這世上最難降的妖魔是什么思灌? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任俺叭,我火速辦了婚禮,結(jié)果婚禮上泰偿,老公的妹妹穿的比我還像新娘熄守。我一直安慰自己,他們只是感情好耗跛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布裕照。 她就那樣靜靜地躺著,像睡著了一般调塌。 火紅的嫁衣襯著肌膚如雪晋南。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天羔砾,我揣著相機(jī)與錄音负间,去河邊找鬼。 笑死姜凄,一個(gè)胖子當(dāng)著我的面吹牛政溃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播檀葛,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼玩祟,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了屿聋?” 一聲冷哼從身側(cè)響起空扎,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎润讥,沒想到半個(gè)月后转锈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楚殿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年撮慨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砌溺,死狀恐怖影涉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情规伐,我是刑警寧澤蟹倾,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站猖闪,受9級(jí)特大地震影響鲜棠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜培慌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一豁陆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吵护,春花似錦盒音、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至用爪,卻和暖如春原押,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偎血。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工诸衔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颇玷。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓笨农,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帖渠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子琼锋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容