1.调用ios提供的NSSetUncaughtExceptionHandler方法捕捉崩溃信息,如:NSSetUncaughtExceptionHandler (&chUncaughtExceptionHandler);,其中参数“&chUncaughtExceptionHandler”为方法的地址。
2.上述方法并不能catch所有崩溃情况,如内存访问错误。它会抛出signal信号,所以还需做signal处理
3.在程序路入口处设置崩溃信息捕捉[CHLoggersetDefaultUncaughtExceptionHandler];
4.输出其他异常,如:[[CHLoggershareInstance]error:@"%s timeOut:%@ exp:%@",__func__,_timeOutStr, [exreason]];
具体实现如下:
首先定义一个CHLogger类,文件代码如下
CHLogger.h
#import
@interface CHLogger : NSObject
+(CHLogger *)shareInstance;
+ (void)setDefaultUncaughtExceptionHandler;
-(void)error:(NSString *)format,...;
-(void)info:(NSString *)format,...;
-(void)debug:(NSString *)format,...;
#pragma mark -捕捉崩溃日志
void chUncaughtExceptionHandler(NSException *exception);
#pragma mark -signal处理
void SignalHandler(int signal);
#pragma mark -上传日志文件
-(void)uploadLogFile:(NSString *)taskId logDate:(NSString *)logDate logType:(NSString *)logType;
@end
#import "CHLogger.h"
#define LOG_TIME_FORMAT @"yyyy-MM-dd HH:mm:ss.SSS"
#define LOG_QUEUE_ID "log_queue"
static CHLogger *_instance=nil;
static dispatch_queue_t queue_log;
static NSUncaughtExceptionHandler *_handler;
@implementation CHLogger
@synthesize _logLevel;
+(CHLogger *)shareInstance
{
@synchronized(self)
{
if(_instance==nil)
{
_instance=[[self alloc]init];
queue_log = dispatch_queue_create(LOG_QUEUE_ID, DISPATCH_QUEUE_SERIAL);
}
}
return _instance;
}
#pragma mark -设置crash
+ (void)setDefaultUncaughtExceptionHandler
{
NSSetUncaughtExceptionHandler (&chUncaughtExceptionHandler);
signal(SIGABRT, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGFPE, SignalHandler);
signal(SIGBUS, SignalHandler);
signal(SIGPIPE, SignalHandler);
}
#pragma mark -获取崩溃日志
void chUncaughtExceptionHandler(NSException *exception)
{
// 异常的堆栈信息
NSArray *stackArray = [exception callStackSymbols];
// 出现异常的原因
NSString *reason = [exception reason];
// 异常名称
NSString *name = [exception name];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:LOG_TIME_FORMAT];
NSString *time = [formatter stringFromDate:[NSDate date]];
NSString *exceptionInfo = [NSString stringWithFormat:@"%@Exception reason:%@\nException name:%@\nException stack:%@", time, name, reason, stackArray];
[self writeLogfile:exceptionInfo fileName:LOG_CRASH];
}
void SignalHandler(int signal)
{
//拦截signal
}
-(void)debug:(NSString *)format,...
{
if(self._logLevel < LOG_LEVEL_DEBUG)
{
return ;
}
if (format != NULL)
{
@try {
CFStringRef param = (__bridge CFStringRef)format;
va_list args;
va_start(args, format);
CFStringRef s = CFStringCreateWithFormatAndArguments(NULL, NULL, param, args);
va_end(args);
if (s != NULL)
{
NSString *msg = [NSString stringWithFormat:@"%@\n", (__bridge NSString *)s];
[self printMsg:[self formatLogMsg:msg]];
}
} @catch (NSException *exception) {
}
}
}
-(NSString *)formatLogMsg:(NSString *)formatText
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:LOG_TIME_FORMAT];
NSString *time = [formatter stringFromDate:[NSDate date]];
NSMutableString *msg = [NSMutableString stringWithFormat:@"%@ ", time];
[msg appendString:formatText];
return msg;
}
-(void)info:(NSString *)format,...
{
if(self._logLevel < LOG_LEVEL_INFO)
{
return ;
}
if (format != NULL)
{
@try {
CFStringRef param = (__bridge CFStringRef)format;
va_list args;
va_start(args, format);
CFStringRef s = CFStringCreateWithFormatAndArguments(NULL, NULL, param, args);
va_end(args);
if (s != NULL)
{
NSString *msg = [NSString stringWithFormat:@"%@\n", (__bridge NSString *)s];
[self printMsg:[self formatLogMsg:msg]];
}
} @catch (NSException *exception) {
}
}
}
-(void)error:(NSString *)format,...
{
if(self._logLevel < LOG_LEVEL_ERROR)
{
return ;
}
if (format != NULL)
{
@try {
CFStringRef param = (__bridge CFStringRef)format;
va_list args;
va_start(args, format);
CFStringRef s = CFStringCreateWithFormatAndArguments(NULL, NULL, param, args);
va_end(args);
if (s != NULL)
{
NSString *msg = [NSString stringWithFormat:@"%@\n", (__bridge NSString *)s];
[self printMsg:[self formatLogMsg:msg]];
}
} @catch (NSException *exception) {
}
}
}
-(NSString *)createLogFileName
{
NSString *date = [PubMethod getFormatStrFromDate:[NSDate date] formatStr:TIME_FORMAT_TEXT_D];
NSString *fileName = [NSString stringWithFormat:@"%@.log", date];
return fileName;
}
-(void)printMsg:(NSString *)msg
{
dispatch_async(queue_log, ^{
[self writeLogfile:msg fileName:[self createLogFileName]];
});
}
#pragma mark -输出日志
+ (void)writeLogfile:(NSString *)msg fileName:(NSString *)fileName
{
@try
{
NSString *homePath = [_instance getLogFileDir];
if (![[NSFileManager defaultManager] fileExistsAtPath:homePath])//判断createPath路径文件夹是否已存在,此处createPath为需要新建的文件夹的绝对路径
{
//创建文件夹
[[NSFileManager defaultManager] createDirectoryAtPath:homePath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *filePath = [homePath stringByAppendingPathComponent:fileName];
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:filePath]) //如果不存在
{
[msg writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
[fileHandle seekToEndOfFile]; //将节点跳到文件的末尾
NSData* stringData = [msg dataUsingEncoding:NSUTF8StringEncoding];
[fileHandle writeData:stringData]; //追加写入数据
[fileHandle closeFile];
}
@catch(NSException *e)
{
}
}
}