使用KSCrash進行崩潰日志的采集

  1. KSCrash的功能特性
  2. KSCrash的日志處理
  3. KSCrash的集成擴展

1.KSCrash的功能特性

我挑選了幾個重要的功能

a.支持在設備上進行離線符號化的工作

和PLCrashReporter中的PLCrashReporterSymbolicationStrategyAll枚舉值類似,提供了一種本地符號化的功能。大多數(shù)平臺的日志解析都需要我們上傳對應的符號表文件,用于日志的符號化。但是后臺無法提供Mac機或者個人開發(fā)者的條件受限,其實可以暫時使用這種方式直接得到解析過后的日志。

在后面也有提到此種方式會是

On-device symbolication requires basic symbols to be present in the final build. To enable this, go to your app's build settings and set Strip Style to Debugging Symbols. Doing so increases your final binary size by about 5%, but you get on-device symbolication.

開啟設備符號化需要在最終版本中包含基本符號,所以要在build settings 中設置 Strip StyleDebugging Symbols。也會造成最終的二進制文件大小增加5%左右,這也是之前PLCrashReporter中提到的,不過當時查到的數(shù)據(jù)是30-50%,確實測試后沒有如此大的差距,也算是解了疑惑,由于打包包含了基本符號表導致的二進制大小增加。

但是得到的行號還是可能有誤的,如果需要具體的行號,還是需要dsym的解析

b.支持所有Apple設備,包括Apple Watch。

c.跟蹤未被捕獲的C ++異常的真實原因。

通常,如果你的應用程序由于未被捕獲的C ++異常而終止,那么得到的只是

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib          0x9750ea6a 0x974fa000 + 84586 (__pthread_kill + 10)
1   libsystem_sim_c.dylib           0x04d56578 0x4d0f000 + 292216 (abort + 137)
2   libc++abi.dylib                 0x04ed6f78 0x4ed4000 + 12152 (abort_message + 102)
3   libc++abi.dylib                 0x04ed4a20 0x4ed4000 + 2592 (_ZL17default_terminatev + 29)
4   libobjc.A.dylib                 0x013110d0 0x130b000 + 24784 (_ZL15_objc_terminatev + 109)
5   libc++abi.dylib                 0x04ed4a60 0x4ed4000 + 2656 (_ZL19safe_handler_callerPFvvE + 8)
6   libc++abi.dylib                 0x04ed4ac8 0x4ed4000 + 2760 (_ZSt9terminatev + 18)
7   libc++abi.dylib                 0x04ed5c48 0x4ed4000 + 7240 (__cxa_rethrow + 77)
8   libobjc.A.dylib                 0x01310fb8 0x130b000 + 24504 (objc_exception_rethrow + 42)
9   CoreFoundation                  0x01f2af98 0x1ef9000 + 204696 (CFRunLoopRunSpecific + 360)
...

無法追蹤異常情況到底從何處拋出
使用KSCrash,可以獲得未捕獲的異常類型,描述以及從何處引發(fā):

Application Specific Information:
*** Terminating app due to uncaught exception 'MyException', reason: 'Something bad happened...'

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   Crash-Tester                    0x0000ad80 0x1000 + 40320 (-[Crasher throwUncaughtCPPException] + 0)
1   Crash-Tester                    0x0000842e 0x1000 + 29742 (__32-[AppDelegate(UI) crashCommands]_block_invoke343 + 78)
2   Crash-Tester                    0x00009523 0x1000 + 34083 (-[CommandEntry executeWithViewController:] + 67)
3   Crash-Tester                    0x00009c0a 0x1000 + 35850 (-[CommandTVC tableView:didSelectRowAtIndexPath:] + 154)
4   UIKit                           0x0016f285 0xb4000 + 766597 (-[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1194)
5   UIKit                           0x0016f4ed 0xb4000 + 767213 (-[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 201)
6   Foundation                      0x00b795b3 0xb6e000 + 46515 (__NSFireDelayedPerform + 380)
7   CoreFoundation                  0x01f45376 0x1efa000 + 308086 (__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22)
8   CoreFoundation                  0x01f44e06 0x1efa000 + 306694 (__CFRunLoopDoTimer + 534)
9   CoreFoundation                  0x01f2ca82 0x1efa000 + 207490 (__CFRunLoopRun + 1810)
10  CoreFoundation                  0x01f2bf44 0x1efa000 + 204612 (CFRunLoopRunSpecific + 276)
...

d.可插拔的后臺報告架構(gòu)

支持Hockey、QuincyKit、Victory、Email四種日志發(fā)送方式,也可以增加自己的發(fā)送接口。前三者可能大家?guī)缀醪挥玫剑]件方式或者發(fā)送到自己后臺才是大多數(shù)人選擇的方案。

e.支持的崩潰類型

  • Mach內(nèi)核異常
  • signals異常
  • C ++異常
  • Objective-C異常
  • 主線程死鎖(實驗)
  • 自定義崩潰

f.死鎖檢測

這是一個不穩(wěn)定的功能。
如果你的主線程死鎖,你的用戶界面將無響應,用戶將不得不手動關閉該應用程序(為此,不會有崩潰報告)。啟用死鎖檢測后,會建立一個看門狗定時器。如果任何東西的主線程持續(xù)時間超過了看門狗定時器的持續(xù)時間,KSCrash將關閉該應用程序,并給出堆棧跟蹤,顯示當前主線程正在執(zhí)行的操作。

這很好,但你必須小心:應用初始化通常發(fā)生在主線程上。如果你的初始化代碼比看門狗定時器花費的時間更長,您的應用程序?qū)⒃趩舆^程中被強制關閉!

g.自定義崩潰處理代碼(KSCrash.h中的onCrash)

如果你想在發(fā)生崩潰后執(zhí)行一些額外的處理(可能會向報告中添加更多上下文數(shù)據(jù)),則可以這樣做。

但是,您必須確保只使用異步安全的代碼,并且最重要的是永遠不要從該方法調(diào)用Objective-C代碼!但是某些類別的崩潰會忽略這種警告的處理程序代碼會導致崩潰處理程序崩潰!

h.KSCrash日志重定向

通過一個kRedirectConsoleLogToDefaultFile宏定義控制,調(diào)用redirectConsoleLogsToDefaultFile接口,可以將打印到控制臺的日志信息寫入文件。 默認會寫到/Library/Caches/KSCrashReports/目錄。

2.KSCrash的日志處理

crash堆棧臨時信息

同PLCrashReporter一樣,KSCrash在崩潰產(chǎn)生的時候并沒有直接生成可讀的crash日志,而是會在/Library/Caches/KSCrashReports/Simple-Example目錄下生成一個帶有reporterID的json文件,保存的當前crash的堆棧信息。

crash日志生成

根據(jù)reporterID得到json文件,使用- (NSString*) toAppleFormat:(NSDictionary*) JSONReport;進行日志的解析和拼接成string格式。

crash日志發(fā)送

根據(jù)可插拔式的發(fā)送服務來進行日志的發(fā)送,不同的插件發(fā)往不同的服務端。調(diào)用kscrash_i_callCompletion(self.onCompletion, self.reports, success, nil);這個block,將string格式的日志文件轉(zhuǎn)為NSData后進行發(fā)送,并且會回調(diào)到調(diào)用層

    [installation sendAllReportsWithCompletion:^(NSArray* reports, BOOL completed, NSError* error)
     {
         if(completed)
         {
             NSLog(@"Sent %d reports", (int)[reports count]);
         }
         else
         {
             NSLog(@"Failed to send reports: %@", error);
         }
     }];

發(fā)送策略

內(nèi)部默認根據(jù)本地保存的所有crash.json文件進行發(fā)送。所有刪除策略決定每次發(fā)送的日志。提供了三種模式,

// 從不刪除
KSCDeleteNever,
// 成功后刪除
KSCDeleteOnSucess,
// 每次刪除
KSCDeleteAlways

一般情況下 我們可以選擇KSCDeleteOnSucess。

3.KSCrash的集成擴展

  1. 基本的集成步驟demo中寫的很明白,主要是創(chuàng)建一個installation對象,根據(jù)不同的發(fā)送渠道,然后執(zhí)行install方法。
  2. addConditionalAlertWithTitle會顯示一個提示窗,在點擊sure后,KSCrash會讀取本地的日志文件,再進行發(fā)送?!杆?如果我們需要隱式的,偷偷地發(fā)送日志,需要去源碼中刪除這個提示,自己進行發(fā)送的處理。不過后來,找到了更合適的方法?!?/li>
KSCrashInstallationHockey* installation = [KSCrashInstallationHockey sharedInstance];
installation.appIdentifier = @"PUT_YOUR_HOCKEY_APP_ID_HERE";
[installation setReportStyle:KSCrashEmailReportStyleApple useDefaultFilenameFormat:YES]; 

// Optional: Add an alert confirmation (recommended for email installation)
[installation addConditionalAlertWithTitle:@"Crash Detected"
                                 message:@"The app crashed last time it was launched. Send a crash report?"
                               yesAnswer:@"Sure!"
                                noAnswer:@"No thanks"];

[installation install];

常規(guī)的日志發(fā)送

1.除了email形式也許可以給個人開發(fā)者使用,其余的都不滿足我們的日志發(fā)送需求。那可以使用提供的KSCrashInstallationStandard對象。

他擁有一個url屬性,KSCrash會自動向這個url發(fā)送日志的json格式文件。

@property(nonatomic,readwrite,retain) NSURL* url;

關于request的創(chuàng)建和發(fā)送的內(nèi)容都在KSCrashReportSinkStandard中。

2.此外如果需要增加發(fā)送完成的回調(diào)設置,可以在sendAllReportsWithCompletion接口中設置。

  
    KSCrashInstallation* installation = [self makeStandardInstallation];
    
    [installation install];
    // 設置發(fā)送成功后刪除
    [KSCrash sharedInstance].deleteBehaviorAfterSendAll = KSCDeleteOnSucess;
    
    [installation sendAllReportsWithCompletion:^(NSArray* reports, BOOL completed, NSError* error)
     {

     }];

3.如果這樣還是滿足不了你的需求,報文格式、加解密這些步驟需要增加,那就要去request的創(chuàng)建環(huán)節(jié)進行修改了。

- (void) filterReports:(NSArray*) reports
          onCompletion:(KSCrashReportFilterCompletion) onCompletion
{
    self.reports = reports;
    self.onCompletion = onCompletion;

    self.reachableOperation = [KSReachableOperationKSCrash operationWithHost:[self.url host]
                                                                   allowWWAN:YES
                                                                       block:^
    {
      
    }];
}

這樣整個KSCrash的日志存放、日志讀取、日志發(fā)送和自定義擴展都能大概有個了解了。感興趣的可以查看源碼,了解各個發(fā)送渠道、日志讀取處理的完整操作,進一步關于crash日志的生成和解析。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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