zoukankan      html  css  js  c++  java
  • 崩溃日志收集

    主要思路:
    一.捕获两种崩溃的方法:
    1.通过 NSSetUncaughtExceptionHandler 设置全局的异常处理器, 能够捕获的异常有: 数组越界/字典赋值 nil/ 调用方法不存在..
    2.通过 Signal 处理,因为像内存访问错误/重复释放等错误, 会抛出 Signal 信号,所以需要专门处理
    二.异常回调
    1.发生异常之后,进入回调函数,此时获取堆栈中的信息
    2.收到异常处理消息时, 开启 runloop,防止程序死亡
    3.本机记录异常 or 上传服务器
     

    .h

    #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.
    
    "
    //                @"Debug details follow:
    %@
    %@", 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 的介绍

    https://www.cnblogs.com/daxiaxiaohao/p/4466097.html

  • 相关阅读:
    select在各个浏览器中的兼容性问题
    pc打开手机站提示切换为手机屏幕
    图片预加载
    div盒子水平垂直居中的方法
    如何检测该浏览器为微信浏览器
    小箭头的写法,z-index在ie7显示混乱问题
    微信a标签不跳转
    css font简写规则
    windows环境cmd下执行jar
    docker制作镜像步骤
  • 原文地址:https://www.cnblogs.com/daxueshan/p/8512439.html
Copyright © 2011-2022 走看看