崩潰日誌收集

主要思路:
一.捕獲兩種崩潰的方法:
1.經過 NSSetUncaughtExceptionHandler 設置全局的異常處理器, 可以捕獲的異常有: 數組越界/字典賦值 nil/ 調用方法不存在..
2.經過 Signal 處理,由於像內存訪問錯誤/重複釋放等錯誤, 會拋出 Signal 信號,因此須要專門處理
二.異常回調
1.發生異常以後,進入回調函數,此時獲取堆棧中的信息
2.收到異常處理消息時, 開啓 runloop,防止程序死亡
3.本機記錄異常 or 上傳服務器
 

.hhtml

#import <UIKit/UIKit.h>

@interface UncaughtExceptionHandler : NSObject{
    BOOL dismissed;
}

@end
void HandleException(NSException *exception);
void SignalHandler(int signal);


void YunInstallUncaughtExceptionHandler(void);

 

.m 數組

#import "YunUncaughtExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>



NSString * const YunUncaughtExceptionHandlerSignalExceptionName = @"YunUncaughtExceptionHandlerSignalExceptionName";
NSString * const YunUncaughtExceptionHandlerSignalKey = @"YunUncaughtExceptionHandlerSignalKey";
NSString * const YunUncaughtExceptionHandlerAddressesKey = @"YunUncaughtExceptionHandlerAddressesKey";
//volatile的做用是做爲指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。
//當前處理的異常個數
volatile int32_t YunUncaughtExceptionCount = 0;
//最大可以處理的異常個數
const int32_t YunUncaughtExceptionMaximum = 10;

const NSInteger YunUncaughtExceptionHandlerSkipAddressCount = 4;
const NSInteger YunUncaughtExceptionHandlerReportAddressCount = 5;

@implementation UncaughtExceptionHandler

//回溯, 追蹤
+ (NSArray *)backtrace
{
//    backtrace函數用於獲取堆棧的地址信息,
//    backtrace_symbols函數把堆棧地址翻譯成咱們易識別的字符串,
//    backtrace_symbols_fd函數則把字符串堆棧信息輸出到文件中
     void* callstack[128];
     int frames = backtrace(callstack, 128);
     char **strs = backtrace_symbols(callstack, frames);
     
     int i;
     NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
     for (
         i = YunUncaughtExceptionHandlerSkipAddressCount;
         i < YunUncaughtExceptionHandlerSkipAddressCount +
            YunUncaughtExceptionHandlerReportAddressCount;
        i++)
     {
         [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
     }
     free(strs);
     
     return backtrace;
}

- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
    
    if (anIndex == 0)
    {
        dismissed = YES;
    }
}

- (void)validateAndSaveCriticalApplicationData
{
    
}

//錯誤日誌開始發送到服務器
- (void)handleException:(NSException *)exception
{
    [self validateAndSaveCriticalApplicationData];
    
//    UIAlertView *alert =
//        [[UIAlertView alloc]
//            initWithTitle:NSLocalizedString(@"Unhandled exception", nil)
//            message:[NSString stringWithFormat:NSLocalizedString(
//                @"You can try to continue but the application may be unstable.\n\n"
//                @"Debug details follow:\n%@\n%@", nil),
//                [exception reason],
//                [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]]
//            delegate:self
//            cancelButtonTitle:NSLocalizedString(@"Quit", nil)
//            otherButtonTitles:NSLocalizedString(@"Continue", nil), nil];
//    [alert show];
    
    NSString *errorStr = [NSString stringWithFormat:NSLocalizedString(
                                                                      @"error info details follow:%@%@", nil),
                          [exception reason],
                          [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]]
    ;
    
   
    if(errorStr)
    {
        [self sendErrorMsg];
    }
    NSLog(@"捕獲的異常:error:%@",errorStr);

    //當接收到異常處理消息時,讓程序開始runloop,防止程序死亡
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    
    while (!dismissed)
    {
        for (NSString *mode in (__bridge  NSArray *)allModes)
        {
            CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false);
        }
    }
    
    CFRelease(allModes);

    NSSetUncaughtExceptionHandler(NULL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGILL, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
    
    if ([[exception name] isEqual:YunUncaughtExceptionHandlerSignalExceptionName])
    {
//若是我想程序發一個SIGINT函數,能夠使用kill函數 kill(getpid(),SIGINT)。getpid()得到了當前運行的程序id,此時就發送了SIGINT信號給該進程 kill(getpid(), [[[exception userInfo] objectForKey:YunUncaughtExceptionHandlerSignalKey] intValue]); }
else{
    //拋出異常,並致使崩潰 [exception raise]; } }
-(void)sendErrorMsg { // [fetchQueue setGLDelegate:self.gldelegate]; } @end /** 異常回調函數 */ void HandleException(NSException *exception){ //OSAtomicIncrement32:一個自增函數,在庫<libkern/OSAtomic.h>中,是線程安全的; int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount); if (exceptionCount > YunUncaughtExceptionMaximum) { return; } NSArray *callStack = [UncaughtExceptionHandler backtrace]; NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; [userInfo setObject:callStack forKey:YunUncaughtExceptionHandlerAddressesKey]; [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject: [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo] waitUntilDone:YES]; } /** 捕獲信號後的回調函數 */ void SignalHandler(int signal) { int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount); if (exceptionCount > YunUncaughtExceptionMaximum) { return; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:YunUncaughtExceptionHandlerSignalKey]; NSArray *callStack = [UncaughtExceptionHandler backtrace]; [userInfo setObject:callStack forKey:YunUncaughtExceptionHandlerAddressesKey]; [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject: [NSException exceptionWithName:YunUncaughtExceptionHandlerSignalExceptionName reason: [NSString stringWithFormat: NSLocalizedString(@"Signal %d was raised.", nil), signal] userInfo: [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:YunUncaughtExceptionHandlerSignalKey]] waitUntilDone:YES]; } //begain void YunInstallUncaughtExceptionHandler(void) { //崩潰報告系統會用NSSetUncaughtExceptionHandler方法設置全局的 異常處理器。 NSSetUncaughtExceptionHandler(&HandleException); signal(SIGABRT, SignalHandler); signal(SIGILL, SignalHandler); signal(SIGSEGV, SignalHandler); signal(SIGFPE, SignalHandler); signal(SIGBUS, SignalHandler); signal(SIGPIPE, SignalHandler); } /* SIGABRT--程序停止命令停止信號 SIGALRM--程序超時信號 SIGFPE--程序浮點異常信號 SIGILL--程序非法指令信號 SIGHUP--程序終端停止信號 SIGINT--程序鍵盤中斷信號 SIGKILL--程序結束接收停止信號 SIGTERM--程序kill停止信號 SIGSTOP--程序鍵盤停止信號 SIGSEGV--程序無效內存停止信號 SIGBUS--程序內存字節未對齊停止信號 SIGPIPE--程序Socket發送失敗停止信號 */

 

 

關於 Signal 的介紹安全

http://www.javashuo.com/article/p-ezpeeesh-do.html服務器

相關文章
相關標籤/搜索