iOS日志系統(tǒng)

將log信息記錄到控制臺(tái),文件或遠(yuǎn)程服務(wù)器被廣泛用于幾乎任何類型的軟件開發(fā)。它是調(diào)試的最簡單的形式之一。當(dāng)調(diào)試或試圖理解一個(gè)復(fù)雜的邏輯,不管語言,日志系統(tǒng)都能夠很容易,且快速為開發(fā)和維護(hù)帶來便利。在iOS中,在正常的debug情況下當(dāng)然可以通過NSLog來打印,但是當(dāng)程序正式上線,程序閃退等意外發(fā)生的時(shí)候,這時(shí)候要是有記錄用戶行為的日志被記錄下來,那么能夠更容易分析錯(cuò)誤。這里介紹一個(gè)iOS上一個(gè)第三方日志庫CocoaLumberjack。正如它在Github 上介紹的那樣

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

為什么不用NSLog

你可能不知道NSLog會(huì)使你的程序變慢。NSLog首先就不是設(shè)計(jì)作為普通的debug log的,而是error log。并且每一次NSLog的打印都需要和蘋果系統(tǒng)日志(ASL)進(jìn)行一次連接,然后在打印結(jié)束后,斷開這次連接。總結(jié)下NSLog有如下幾個(gè)缺點(diǎn)

  1. NSLog太不靈活
  2. NSLog太慢
  3. NSLog沒有等級(jí)制度log
    其中最為重要一點(diǎn)就是NSLog缺少成為日志系統(tǒng)所必須的log級(jí)別。這就是本文所要介紹的CocoaLumberjack的優(yōu)點(diǎn),并且CocoaLumberjack能夠很容易的自定義自己的log等級(jí)

CocoaLumberjack

CocoaLumberjack能夠快速的給你提供如下的的功能:

  1. 跟蹤在程序中不斷出現(xiàn)的不可復(fù)制的bug
  2. 為你的應(yīng)用程序?qū)ふ移髽I(yè)級(jí)的日志解決方案。
    CocoaLumberjack的使用很簡單,只需要簡單將Lumberjack文件添加到你的項(xiàng)目中,配置完后使用所定義的宏就好了。

配置CocoaLumberjack

整個(gè)配置很簡單,只需在applicationDidFinishLaunching后添加如下兩句代碼,這樣就使CocoaLumberjack定義的宏DDLog具有NSLog的功能(ASL和控制臺(tái))

[DDLog addLogger:[DDASLLogger sharedInstance]];  // 向ASL 發(fā)送log
[DDLog addLogger:[DDTTYLogger sharedInstance]];  // 向控制臺(tái)發(fā)送

對(duì)于調(diào)試代碼來說,只需要打開向控制臺(tái)發(fā)送輸出結(jié)果就好,即打開下面那個(gè)logger。CocoaLumberjack我覺得最酷的就是可以異步輸出到文件,并且能定期的發(fā)送到遠(yuǎn)程服務(wù)器,或者緩存到達(dá)一定的size發(fā)送到制定的服務(wù)器,而且使用也很簡單,只需要單獨(dú)的設(shè)置。

fileLogger = [[DDFileLogger new]; 
fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling 
fileLogger.logFileManager.maximumNumberOfLogFiles = 7; 
[DDLog addLogger:fileLogger];

上面的代碼告訴應(yīng)用程序要在系統(tǒng)上保持一周的日志文件,是不是簡單而又功能強(qiáng)大。

DDLog四種級(jí)別

DDLog默認(rèn)有四種級(jí)別,分別為:

  1. DDlogError
  2. DDlogWarn
  3. DDlogInfo
  4. DDlogVerbose

DDLogLevel定義了全局的logger等級(jí),DDLogFlag 是打log時(shí)設(shè)定的log等級(jí),CocoaLumberjack會(huì)比較兩者,如果flag低于level,則不會(huì)打log.針對(duì)不同的flag。這兩個(gè)在后面自定義自己的日志系統(tǒng)中,有很大的作用。

DDlogVerbose

這個(gè)級(jí)別最低的東東,一般的來說,在系統(tǒng)實(shí)際運(yùn)行過程中,一般都是不輸出的。因此這個(gè)級(jí)別的信息,可以隨意的使用,任何覺得有利于在調(diào)試時(shí)更詳細(xì)的了解系統(tǒng)運(yùn)行狀態(tài)的東東,比如變量的值等等,都輸出來看看也無妨。當(dāng)然,在每一個(gè) Debug 調(diào)用之前,一定要加上 If 判斷。

DDlogInfo

這個(gè)應(yīng)該用來反饋系統(tǒng)的當(dāng)前狀態(tài)給最終用戶的,所以,在這里輸出的信息,應(yīng)該對(duì)最終用戶具有實(shí)際意義,也就是最終用戶要能夠看得明白是什么意思才行。從某種角度上說,Info 輸出的信息可以看作是軟件產(chǎn)品的一部分(就像那些交互界面上的文字一樣),所以需要謹(jǐn)慎對(duì)待,不可隨便。

DDlogError DDlogWarn

警告、錯(cuò)誤應(yīng)該都在系統(tǒng)運(yùn)行時(shí)檢測(cè)到了一個(gè)不正常的狀態(tài).

自定義log系統(tǒng)

對(duì)于構(gòu)建自己的log系統(tǒng),一般需要以下實(shí)現(xiàn)幾個(gè)方面

  1. 可以設(shè)定 Log 等級(jí)
  2. 可以積攢到一定量的 log 后,一次性發(fā)送給服務(wù)器,絕對(duì)不能打一個(gè) Log 就發(fā)一次
  3. 可以一定時(shí)間后,將未發(fā)送的 log 發(fā)送到服務(wù)器
  4. 可以在 App 切入后臺(tái)時(shí)將未發(fā)送的 log 發(fā)送到服務(wù)器

下面基于Lumberjack,實(shí)現(xiàn)自己的log系統(tǒng)。

自定義Log等級(jí)

如果覺得Lumberjack默認(rèn)的等級(jí)分的不夠細(xì),Lumberjack支持自定義log等級(jí),只需要自定義我們自己的頭文件,然后替代DDlog.h來引入到項(xiàng)目中去。等級(jí)的詳細(xì)程度可以根據(jù)自己的需求,首先需要undefine Lumberjack自帶的log,然后自定義自己的等級(jí)和flag。最后定義自己格式的宏,來替代DDLogNSLog

#import "DDLog.h"
// First undefine the default stuff we don't want to use.
#undef LOG_FLAG_ERROR
#undef LOG_FLAG_WARN 
#undef LOG_FLAG_INFO
#undef LOG_FLAG_DEBUG
#undef LOG_FLAG_VERBOSE

#undef LOG_LEVEL_ERROR
#undef LOG_LEVEL_WARN
#undef LOG_LEVEL_INFO
#undef LOG_LEVEL_DEBUG
#undef LOG_LEVEL_VERBOSE

#undef LOG_ERROR
#undef LOG_WARN
#undef LOG_INFO
#undef LOG_DEBUG
#undef LOG_VERBOSE

#undef DDLogError
#undef DDLogWarn
#undef DDLogInfo
#undef DDLogDebug
#undef DDLogVerbose

#undef DDLogCError
#undef DDLogCWarn
#undef DDLogCInfo
#undef DDLogCDebug
#undef DDLogCVerbose

// Now define everything how we want it

#define LOG_FLAG_FATAL   (1 << 0)  // 0...000001
#define LOG_FLAG_ERROR   (1 << 1)  // 0...000010
#define LOG_FLAG_WARN    (1 << 2)  // 0...000100
#define LOG_FLAG_NOTICE  (1 << 3)  // 0...001000
#define LOG_FLAG_INFO    (1 << 4)  // 0...010000
#define LOG_FLAG_DEBUG   (1 << 5)  // 0...100000

#define LOG_LEVEL_FATAL   (LOG_FLAG_FATAL)                     // 0...000001
#define LOG_LEVEL_ERROR   (LOG_FLAG_ERROR  | LOG_LEVEL_FATAL ) // 0...000011
#define LOG_LEVEL_WARN    (LOG_FLAG_WARN   | LOG_LEVEL_ERROR ) // 0...000111
#define LOG_LEVEL_NOTICE  (LOG_FLAG_NOTICE | LOG_LEVEL_WARN  ) // 0...001111
#define LOG_LEVEL_INFO    (LOG_FLAG_INFO   | LOG_LEVEL_NOTICE) // 0...011111
#define LOG_LEVEL_DEBUG   (LOG_FLAG_DEBUG  | LOG_LEVEL_INFO  ) // 0...111111

#define LOG_FATAL   (ddLogLevel & LOG_FLAG_FATAL )
#define LOG_ERROR   (ddLogLevel & LOG_FLAG_ERROR )
#define LOG_WARN    (ddLogLevel & LOG_FLAG_WARN  )
#define LOG_NOTICE  (ddLogLevel & LOG_FLAG_NOTICE)
#define LOG_INFO    (ddLogLevel & LOG_FLAG_INFO  )
#define LOG_DEBUG   (ddLogLevel & LOG_FLAG_DEBUG )

// third define Formmater
#define DDLogFatal(frmt, ...)    SYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_FATAL,  0, frmt, ##__VA_ARGS__)
#define DDLogError(frmt, ...)    SYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_ERROR,  0, frmt, ##__VA_ARGS__)
#define DDLogWarn(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_WARN,   0, frmt, ##__VA_ARGS__)
#define DDLogNotice(frmt, ...)  ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_NOTICE, 0, frmt, ##__VA_ARGS__)
#define DDLogInfo(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_INFO,   0, frmt, ##__VA_ARGS__)
#define DDLogDebug(frmt, ...)   ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_DEBUG,  0, frmt, ##__VA_ARGS__)

#define DDLogCFatal(frmt, ...)   SYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_FATAL,  0, frmt, ##__VA_ARGS__)
#define DDLogCError(frmt, ...)   SYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_ERROR,  0, frmt, ##__VA_ARGS__)
#define DDLogCWarn(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_WARN,   0, frmt, ##__VA_ARGS__)
#define DDLogCNotice(frmt, ...) ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_NOTICE, 0, frmt, ##__VA_ARGS__)
#define DDLogCInfo(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_INFO,   0, frmt, ##__VA_ARGS__)
#define DDLogCDebug(frmt, ...)  ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_DEBUG,  0, frmt, ##__VA_ARGS__)

自定義log格式

CocoaLumberjack 允許自定義log的消息結(jié)構(gòu)。自定義一個(gè) LogFormatter的類, 遵從DDLogFormatter 協(xié)議,重寫 formatLogMessage 方法,這個(gè)方法返回值是NSString,就是最終 log 的消息體字符串。而輸入?yún)?shù) logMessage 是由 logger 發(fā)的一個(gè) DDLogMessage對(duì)象,包含了一些必要的信息。以下是一個(gè)簡單的實(shí)現(xiàn),輸出時(shí)間和flag格式,和log消息

- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
    NSString *flag = stringByLogFlag(logMessage->_flag);
    NSString *dateAndTime = [_dataFormatter stringFromDate:logMessage->_timestamp];
    return [NSString stringWithFormat:@"%@ %@ %@", dateAndTime, flag, logMessage->_message];
}

總結(jié)

CocoaLumberjack 使構(gòu)建自己的log系統(tǒng)變得十分簡單,只需要定義level和log消息格式就好了。

參考文獻(xiàn)

NSLog效率低下的原因及嘗試lldb斷點(diǎn)打印Log

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

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

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