Created by Shuimu
日志分級
分級定義:
Fatal 嚴(yán)重級別讲逛。
表明程序遇到了非常嚴(yán)重的錯誤悉尾,已經(jīng)不能繼續(xù)運行下去檐晕。
Error 出錯級別。
程序可能正處于非正常狀態(tài)下县恕,無法正常完成既定功能,但程序依然能運行剂桥。
Warning 警告級別忠烛。
程序處理中遇到非法數(shù)據(jù)或者某種可能的錯誤,程序無法處理权逗,但是依然能正常運行美尸。
Info 重要信息級別。
一般用于打印模塊中一些重要的點斟薇,以證明程序運行正常师坎。
Debug 調(diào)試級別。
表明當(dāng)前正在臨時打印一些log堪滨,以便調(diào)試程序胯陋。
輸出格式
[
level
]file
function
[linenum
]message
[
level
]file
function
[linenum
]message
[
level
]file
function
[linenum
]message
基本使用方法
像極了
NSLog
#define XXLogFatal(fmt, ...) // 省略具體實現(xiàn)
#define XXLogError(fmt, ...) // 省略具體實現(xiàn)
#define XXLogWarn(fmt, ...) // 省略具體實現(xiàn)
#define XXLogInfo(fmt, ...) // 省略具體實現(xiàn)
#define XXLogDebug(fmt, ...) // 省略具體實現(xiàn)
#define XXLog XXLogDebug // 等價于 Debug 級別(只是為了少打幾個字母)
日志讀取
簡介
日常開發(fā)中,經(jīng)常會用到NSLog進(jìn)行調(diào)試,NSLog本質(zhì)上是一個C函數(shù)惶岭,它的函數(shù)聲明如下:
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL;
系統(tǒng)的說明是:Logs an error message to the Apple System Log facility.
寿弱。
它是用來輸出信息到標(biāo)準(zhǔn)Error控制臺的,內(nèi)部使用的是Apple System Log
的API(相關(guān)API可以查看<asl.h>
)按灶。調(diào)試階段症革,日志會輸出到Xcode控制臺中,真機調(diào)試時鸯旁,則會輸出到系統(tǒng)的/var/log/syslog
這個文件中噪矛。
日志輸出到文件中的句柄定義在unistd.h
文件中
#define STDIN_FILENO 0 /* standard input file descriptor */
#define STDOUT_FILENO 1 /* standard output file descriptor */
#define STDERR_FILENO 2 /* standard error file descriptor */
NSLog
的日志是通過STDERR_FILENO
輸出到文件的。另外铺罢,fprintf
并不會調(diào)用ASL接口艇挨,只是簡單的輸出信息(相對NSLog,少了日期韭赘、進(jìn)程名缩滨、進(jìn)程id等信息),其日志是通過STDOUT_FILENO
輸出到文件中泉瞻。
ASL讀取日志
鑒于以上信息脉漏,既然日志是寫入到系統(tǒng)的syslog中,那么就可以直接讀取這些日志袖牙。通過ASL的相關(guān)API侧巨,我們可以讀取到這些日志內(nèi)容。
不過鞭达,查看<asl.h>
相關(guān)API可以發(fā)現(xiàn)司忱,
__API_DEPRECATED("os_log(3) has replaced asl(3)", macosx(10.4,10.12), ios(2.0,10.0), watchos(2.0,3.0), tvos(9.0,10.0))
asl
從iOS 10開始被棄用了,并提供了新的APIos_log
進(jìn)行替代的(詳見<os/log.h>
)
??畴蹭,系統(tǒng)版本限制坦仍,放棄。
NSLog重定向
通過前面的介紹可以了解到叨襟,NSLog
輸出的日志內(nèi)容繁扎,最終都通過STDERR
句柄來記錄的,所以可以考慮對其進(jìn)行重定向(當(dāng)然芹啥,重定向之后锻离,就無法在控制臺看到log打印了)。
文件重定向
利用c語言的freopen
函數(shù)進(jìn)行重定向墓怀,將寫往stderr的內(nèi)容重定向到我們指定的文件中去汽纠。
函數(shù)聲明:
FILE *freopen(const char * __restrict, const char * __restrict, FILE * __restrict)
- 第一個參數(shù):需要重定向到文件路徑
- 第二個參數(shù):文件的打開模式,r/w/a/+等
- 第三個參數(shù):被打開的文件名傀履,通常使用標(biāo)準(zhǔn)流文件(stdin/stdout/stderr)
核心代碼:
NSString *newLogFilePath = @"xxxxxx"; // 指定的寫入文件路徑
freopen([newLogFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr); // stderr 標(biāo)準(zhǔn)錯誤輸出流
由于iOS的沙盒機制虱朵,無法得知stderr
原來的文件路徑莉炉,導(dǎo)致freopen無法重定向回去。這里利用dup
和 dup2
來實現(xiàn)碴犬。
大致實現(xiàn)思路如下:
// 記錄原來的輸出流
int origin = dup(STDERR_FILENO);
// 利用freopen進(jìn)行重定向
FILE *myFile = freopen([newLogFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
// 恢復(fù)重定向
dup2(origin, STDERR_FILENO)
dup2重定向
上面提到的dup2
函數(shù)是專門進(jìn)行文件重定向的絮宁。同樣也可以直接通過dup2
函數(shù)直接重定向STDERR
句柄,將內(nèi)容指向指定的位置服协。
- 思路:
首先通過NSPipe
創(chuàng)建一個管道绍昂,pipe有讀端和寫端,通過dup2
將標(biāo)準(zhǔn)輸入重定向到pipe的寫端偿荷,在通過NSFileHandle
監(jiān)聽pipe的讀端窘游,再處理讀出的信息。
- 核心代碼如下:
- (void)redirectStandardOutput {
// 記錄標(biāo)準(zhǔn)輸出及錯誤流原始文件描述符
self.errFd = dup(STDERR_FILENO);
stderr->_flags = 10;
NSPipe *errPipe = [NSPipe pipe];
NSFileHandle *pipeErrHandle = [errPipe fileHandleForReading];
dup2([[errPipe fileHandleForWriting] fileDescriptor], STDERR_FILENO);
[pipeErrHandle readInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(redirectErrNotificationHandle:) name:NSFileHandleReadCompletionNotification object:pipeErrHandle];
}
- (void)recoverStandardOutput {
dup2(self.errFd, STDERR_FILENO);
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
// 重定向之后的錯誤輸出
- (void)redirectErrNotificationHandle:(NSNotification *)nf {
NSData *data = [[nf userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// write your code. 保存日志跳纳、上傳或展示等等
[[nf object] readInBackgroundAndNotify];
}