照例先上github地址
做這個的原因
程序測試時并不是總是連著Xcode的,這就導致如果測試過程中程序出現崩潰時,可能是由于數據異常引起的,而我們有無法看到數據,連接Xcode重測時,有時候問題并不能重現,導致很多問題無法確認,所以想把所有NSLog輸出的數據,保存到文件中。這樣,當程序出問題時,我們只需導出log文件,查看,便可很容易的復現問題。
用法
- 如果想要NSLog輸出的內容和崩潰信息都放入日志文件中,就在application:didFinishLaunchingWithOptions:方法中實現方法redirectNSLogToDocumentFolder
- 如果只是想要保存崩潰信息到日志文件中,只需在application:didFinishLaunchingWithOptions:方法中實現NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);就可以了。
保持淡定, 人生從此不再寂寞。(其實,這只是個分割線,哈哈)
文筆不好,還是直接上代碼
- (void)redirectNSLogToDocumentFolder
{
//如果已經連接Xcode調試則不輸出到文件
if (isatty(STDOUT_FILENO)) {
return;
}
//判定如果是模擬器就不輸出
UIDevice *device = [UIDevice currentDevice];
if ([[device model]hasSuffix:@"Simulator"]) {
return;
}
//將NSLog打印信息保存到Document目錄下的Log文件夾下
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *logDirectory = [[paths objectAtIndex:0]stringByAppendingPathComponent:@"Log"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL fileExists = [fileManager fileExistsAtPath:logDirectory];
if (!fileExists) {
NSError *error = nil;
[fileManager createDirectoryAtPath:logDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
NSLog(@"error = %@",[error localizedDescription]);
}
}
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setLocale:[[NSLocale alloc]initWithLocaleIdentifier:@"zh_CN"]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
//每次啟動都保存一個新的日志文件中
NSString *dateStr = [formatter stringFromDate:[NSDate date]];
NSString *logFilePath = [logDirectory stringByAppendingFormat:@"/%@.log",dateStr];
//將log文件輸出到文件
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a++", stdout);
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a++", stderr);
//捕獲Object-C異常日志
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
void UncaughtExceptionHandler(NSException* exception)
{
NSString *name = [exception name];
NSString *reason = [exception reason];
NSArray *symbols = [exception callStackSymbols];
//異常發生時的調用棧
NSMutableString *strSymbols = [[NSMutableString alloc]init];
//將調用棧平成輸出日志的字符串
for (NSString *str in symbols) {
[strSymbols appendString:str];
[strSymbols appendString:@"\r\n"];
}
//將crash日志保存到Document目錄下的Log文件夾下
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *logDirectory = [[paths objectAtIndex:0]stringByAppendingPathComponent:@"Log"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:logDirectory]) {
NSError *error = nil;
[fileManager createDirectoryAtPath:logDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
NSLog(@"error = %@",[error localizedDescription]);
}
}
NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"UncaughtException.log"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setLocale:[[NSLocale alloc]initWithLocaleIdentifier:@"zh_CN"]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *dateStr = [formatter stringFromDate:[NSDate date]];
NSString *crashString = [NSString stringWithFormat:@",- %@ ->[Uncaught Exception]\r\nName:%@,Reason:%@\r\n[Fe Symbols Start]\r\n%@[Fe Symbols End]\r\n\r\n",dateStr,name,reason,strSymbols];
//把錯誤日志寫到文件中
if (![fileManager fileExistsAtPath:logFilePath]) {
[crashString writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}else{
NSFileHandle *outFile = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[outFile seekToEndOfFile];
[outFile writeData:[crashString dataUsingEncoding:NSUTF8StringEncoding]];
[outFile closeFile];
}
//把錯誤日志發送到郵箱
NSString *urlStr = [NSString stringWithFormat:@"mailto://(此處為郵箱地址)?subject=bug&body=感謝您的配合錯誤詳情:%@",crashString];
NSURL *url = [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication]openURL:url];
}
注:這段代碼寫的挺早了,參考鏈接已找不到,不能貼出來,但仍要感謝。