美文网首页
iOS开启错误日志人生

iOS开启错误日志人生

作者: AlexCorleone | 来源:发表于2018-08-09 18:52 被阅读25次

        在开发中遇到Crash是很正常的现象,还记得刚入iOS开发这个坑的时候根本不懂什么、错误提示啊、函数调用栈啊、po命令调试啊等等..........。那个时候最长用的就是异常断点,还有就是N个断点一步一步往下走哈哈哈直到遇到异常。😁🤣🤣🤣

        可是最近对接SDK比较多有时候遇到偶现的Crash自己手贱又没有把输出Log Copy出来就很尴尬了,于是想着是否可以把APP运行时的Crash Log记录下来这样下次连上电脑就可以直接查看上次的Crash日志进行错误分析了。于是百度了下发现Apple已经为我们提供了一个API在异常抛出之前进行调用,而这个API函数参数就是一个回调函数。下面我们来使用这个API进行一个简单的日志记录上报的单例类实现。

ACCrashManager .h的实现


typedefvoid(^ACReportBlock)(BOOLshouldReport);

@interface ACCrashManager :NSObject

@property (nonatomic, strong, readonly) NSData *crashData;

+ (instancetype)shareManager;

- (void)startCacheCrashWith:(NSString*)APPId

            withReportBlock:(ACReportBlock)reportBlock;

@end


.m的实现


#define ACFileManager  [NSFileManager defaultManager]

#define ACFileHandleWith(filePath) [NSFileHandle fileHandleForWritingAtPath:filePath]

@interface ACCrashManager ()

@property (nonatomic, strong) NSData *crashData;

@property (nonatomic, copy) NSString *crashAPPId;

@property (nonatomic, copy) ACReportBlock reportBlock;

@end

@implementation ACCrashManager

#pragma mark - Create Manager

static ACCrashManager*crashManager =nil;

+ (instancetype)shareManager {

    staticdispatch_once_tonceToken;

    dispatch_once(&onceToken, ^{

        crashManager = [[ACCrashManager alloc] init];

    });

    return crashManager;

}

#pragma mark - Setter && getter

- (NSData*)crashData

{

    NSString*filePath =ACCrashFilePath();

    if([ACFileManagerfileExistsAtPath:filePath])

    {

        return [NSData dataWithContentsOfFile:filePath];

    }else

    {

        returnnil;

    }

}

#pragma mark - Public Method

- (void)startCacheCrashWith:(NSString*)APPId

            withReportBlock:(ACReportBlock)reportBlock

{

    self.reportBlock= reportBlock;

    NSSetUncaughtExceptionHandler(&ACUncaughtExceptionHandler);//Apple异常调用API

    NSLog(@"AC : Crach Start Cache");

    self.crashAPPId= APPId.length>0? APPId :@"AC.ErrorDir";

        if(self.reportBlock)

            {

                self.reportBlock(YES);

            }

}

#pragma mark - Private Method

/*捕获错误异常的回调函数*/

void ACUncaughtExceptionHandler(NSException*exception)//异常调用API的回调函数

{

    NSString*reportErrorStr =  [NSString stringWithFormat:@"\n\n\"ERROR\" :{\n\"AC Crash TIME\" : \"%@\",\n\"AC Crash Name\" : \"%@\", \n\"AC Crash Reason\" : \"%@\", \n\n\"AC Crash CallStackReturnAddresses\" : \n\"%@\", \n\"AC Crash CallStackSymbols\" : \n\"%@\" \n}", ACGetTomeNow(), exception.name, exception.reason, exception.callStackReturnAddresses, exception.callStackSymbols];

    NSData *reportData = [reportErrorStr dataUsingEncoding:NSUTF8StringEncoding];

    NSString*filePath =ACCrashFilePath();

    BOOLisWrite =NO;

    if([ACFileManagerfileExistsAtPath:filePath])

    {

        isWrite =YES;

        NSFileHandle*fileHandle =ACFileHandleWith(filePath);

        [fileHandleseekToEndOfFile];

        [fileHandlewriteData:reportData];

        [fileHandlesynchronizeFile];

        [fileHandlecloseFile];

    }else

    {

        isWrite = [ACFileManagercreateFileAtPath:filePathcontents:reportDataattributes:nil];

    }

    if(isWrite)

    {

        NSLog(@"文件写入成功");

    }else

    {

        NSLog(@"文件写入失败");

    }

}

/*创建错误日志文件夹*/

staticNSString*ACReportFileDirectories(void)

{

    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];

    NSString *reportPath = [documentPath stringByAppendingString:[NSString stringWithFormat:@"/%@", crashManager.crashAPPId]];

    BOOLisDir =YES;

    if(![ACFileManagerfileExistsAtPath:reportPathisDirectory:&isDir])

    {

        NSError*error =nil;

        BOOL isCreateDir = [[NSFileManager defaultManager] createDirectoryAtPath:reportPath withIntermediateDirectories:YES attributes:nil error:&error];

        if(isCreateDir)

        {

            NSLog(@"文件夹创建成功");

        }else

        {

            NSLog(@"文件夹创建失败 : %@", error);

        }

    }

    returnreportPath;

}

/* 获取错误文件存放的文件夹 */

staticNSString*ACCrashFilePath(void)

{

    NSString *filePath = ACReportFileDirectories();

    filePath = [filePathstringByAppendingString:@"/ACErrorReport"];

    returnfilePath;

}

/* 获取当前时间*/

staticNSString*ACGetTomeNow()

{

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

    [formattersetDateFormat:@"YYYY-MM-dd HH:mm:ss"];

    NSDate*datenow = [NSDatedate];

    NSString*currentTimeString = [formatterstringFromDate:datenow];

    returncurrentTimeString;

}


这样便可以实现一个简单的Crash日志记录的功能。如果需要上传日志只需要在回调reportBlock中判断是否有上传日志,如果有则将crashData上传服务器。这里日志格式可以根据服务器要求自定义。🤣🤣🤣🤣🤣🤣我这里写的JSON。不过callStackReturnAddresses、callStackSymbols没有json格式化所以好像报错、需要上传服务器的自己再修改下reportErrorStr格式就好。

当然这里只是简单的一个实现思路、我们还是可以使用更好的日志收集分析工具的,如Bugly官方地址这里不多介绍因为Bugly的使用相对来说很简单,而且日志分析也是可视化的、最最主要的他还提供了一些推荐的解决方案。是不是以后不用改BUG了🤣🤣🤣🤣🤣🤣好啦、到此结束。开启Bugly之旅啦!!!

相关文章

  • iOS开启错误日志人生

    在开发中遇到Crash是很正常的现象,还记得刚入iOS开发这个坑的时候根本不懂什么、错误提示啊、函数调用栈啊、po...

  • Day09-Binlog日志配置与备份恢复

    1. 日志管理 日志作用:排错、数据恢复、优化 1.1 排错 错误日志(默认开启) 默认错误日志查看 配置方式: ...

  • MySQL备份与恢复

    MySQL 日志 错误日志 编辑配置文件 查看方式 一般查询日志 慢日志 默认是否开启:关闭 如何开启: 模拟慢查...

  • MySQL日志管理

    一.MySQL日志简介 二.错误日志 作用:解决MySQL故障,排错 默认是否开启:开启 路径/名字:hostna...

  • MySQL-lesson06-日志管理

    1、错误日志 作用:记录启动\关闭\日常运行过程中,状态信息,警告,错误 错误日志配置 默认就是开启的: /数据...

  • 走向DBA之日志管理

    开局先放一张图 一、日志作用: 1.1错误日志:(默认就是开启状态) 1.1.1查看MySQL错误日志的路径 1....

  • MySQL日志

    说明 MySQL日志,是工具日志。需要时开启,不需要时关闭 日志列举 错误日志 排错 慢日志 优化 二进制日志 ...

  • 根据bugly调用堆栈信息定位错误代码位置

    方法一:atos 解析 iOS 的错误崩溃日志 错误堆栈信息示例:myapp 0x00000001002abc74...

  • iOS崩溃日志相关文章转载

    iOS之DYSM分析友盟错误信息 iOS 用dSYM工具分析友盟崩溃日志 —— 详细步骤 漫谈iOS Crash收...

  • 代理无法启动

    方法列表: 重启代理 开启 Window EventLog 查看作业日志 作业活动监视器 展开错误日志 查看SQL...

网友评论

      本文标题:iOS开启错误日志人生

      本文链接:https://www.haomeiwen.com/subject/jpvcbftx.html