你的位置:首页 > 操作系统

[操作系统]IOS异常日志记录与展现


在平常的APP开发过程中经常碰到程序遇到异常闪退的问题,通过日志可以把相关的详细错误信息进行记录,本实例要记录不管在哪个页面出错都要进行记录,这边使用到的日志记录插件CocoaLumberjack,以文本的形式记录错误信息,然后再去读取各个文本的内容进行展示;当然现在有很多第三方的插件比如友盟也已经集成错误记录的功能;

效果图如下:

1:封装DDLogger的类

MyFileLogger.h文件#import <Foundation/Foundation.h>#import <CocoaLumberjack.h>@interface MyFileLogger : NSObject@property (nonatomic, strong, readwrite) DDFileLogger *fileLogger;+(MyFileLogger *)sharedManager;@end

MyFileLogger.m文件#import "MyFileLogger.h"@implementation MyFileLogger#pragma mark - Inititlization- (instancetype)init{  self = [super init];    if (self) {    [self configureLogging];  }  return self;}#pragma mark 单例模式static MyFileLogger *sharedManager=nil;+(MyFileLogger *)sharedManager{  static dispatch_once_t once;  dispatch_once(&once, ^{    sharedManager=[[self alloc]init];  });  return sharedManager;}#pragma mark - 配记日志类型- (void)configureLogging{#ifdef DEBUG  [DDLog addLogger:[DDASLLogger sharedInstance]];  [DDLog addLogger:[DDTTYLogger sharedInstance]];#endif  [DDLog addLogger:self.fileLogger];}#pragma mark - 初始化文件记录类型- (DDFileLogger *)fileLogger{  if (!_fileLogger) {    DDFileLogger *fileLogger = [[DDFileLogger alloc] init];    fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling    fileLogger.logFileManager.maximumNumberOfLogFiles = 7;        _fileLogger = fileLogger;  }    return _fileLogger;}@end

这边是设置24小时进行记录一个文件

2:出进异常进行记录

MyExceptionHandler.h文件#import <Foundation/Foundation.h>#import <CocoaLumberjack.h>@interface MyExceptionHandler : NSObject+ (void)setDefaultHandler;+ (NSUncaughtExceptionHandler *)getHandler;+ (void)TakeException:(NSException *) exception;@end

#import "MyExceptionHandler.h"void UncaughtExceptionHandler(NSException * exception){  NSArray * arr = [exception callStackSymbols];  NSString * reason = [exception reason];  NSString * name = [exception name];  NSString * url = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arr componentsJoinedByString:@"\n"]];  DDLogError(@"%@\n\n",url);}@implementation MyExceptionHandler+ (void)setDefaultHandler{  NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);}+ (NSUncaughtExceptionHandler *)getHandler{  return NSGetUncaughtExceptionHandler();}+ (void)TakeException:(NSException *)exception{  NSArray * arr = [exception callStackSymbols];  NSString * reason = [exception reason];  NSString * name = [exception name];  NSString * url = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arr componentsJoinedByString:@"\n"]];  DDLogError(@"%@",url);}@end

这个文件也是当出现异常会执行

3:AppDelegate配置的内容

AppDelegate.h文件内容#import <UIKit/UIKit.h>#import <DDLog.h>#import <CocoaLumberjack.h>#import "MyExceptionHandler.h"#import "MyFileLogger.h"@interface AppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (nonatomic, strong) MyFileLogger *logger;@end

AppDelegate.m文件:#import "AppDelegate.h"@interface AppDelegate ()@end@implementation AppDelegatestatic const int ddLogLevel = LOG_LEVEL_VERBOSE;- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  //初始化  [MyExceptionHandler setDefaultHandler];  self.logger=[[MyFileLogger alloc]init];    NSString *path = NSHomeDirectory();//主目录  NSLog(@"当前项目的路径:%@",path);    return YES;}- (void)applicationWillResignActive:(UIApplication *)application {}- (void)applicationDidEnterBackground:(UIApplication *)application {}- (void)applicationWillEnterForeground:(UIApplication *)application {}- (void)applicationDidBecomeActive:(UIApplication *)application {}- (void)applicationWillTerminate:(UIApplication *)application {}@end

这边重点是设置DDLOG的记录等级ddLogLevel,以及上面两个文件的初始化[MyExceptionHandler setDefaultHandler];self.logger=[[MyFileLogger alloc]init];

实现上面的代码已经能够记录异常的内容;

4:创建一个错误的异常代码

- (void)viewDidLoad {  [super viewDidLoad];    NSArray *test=@[@"123",@"444"];  id testID=test[5];}

执行到这段代码便记录异常的内容,接着进行内容的展示,是以一个列表展示每个日志文件,然后一个详细页面进行展示;

5:日志列表

loggerTableViewController.h文件#import <UIKit/UIKit.h>#import <CocoaLumberjack.h>#import "AppDelegate.h"#import "LoggerDetailViewController.h"@interface loggerTableViewController : UIViewController@end

#import "loggerTableViewController.h"#define BLSRecyclingRecordViewController_CellIdentifier @"MyTablecell"@interface loggerTableViewController ()<UITableViewDataSource, UITableViewDelegate>@property (strong, nonatomic) UITableView *myTableView;@property (nonatomic, strong) NSDateFormatter *dateFormatter;@property (nonatomic, weak) DDFileLogger *fileLogger;@property (nonatomic, strong) NSArray *logFiles;@end@implementation loggerTableViewController- (void)viewDidLoad {  [super viewDidLoad];    //加载日志文件  AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];  _fileLogger = delegate.logger.fileLogger;    [self loadLogFiles];    if (!_myTableView) {    _myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) style:UITableViewStyleGrouped];    _myTableView.showsVerticalScrollIndicator = NO;    _myTableView.showsHorizontalScrollIndicator=NO;    _myTableView.dataSource = self;    _myTableView.delegate = self;    [_myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:BLSRecyclingRecordViewController_CellIdentifier];    [self.view addSubview:_myTableView];  }}//读取日志的文件个数- (void)loadLogFiles{  self.logFiles = self.fileLogger.logFileManager.sortedLogFileInfos;}//时间格式- (NSDateFormatter *)dateFormatter{  if (_dateFormatter) {    return _dateFormatter;  }  _dateFormatter = [[NSDateFormatter alloc] init];  [_dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];  return _dateFormatter;}- (void)didReceiveMemoryWarning {  [super didReceiveMemoryWarning];}#pragma mark - Table view data source- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{  if (section==0) {    return 40;  }  return 10;}- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{  return 1;}- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{  return 2;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{  if (section == 0) {    return self.logFiles.count;  }    return 1;}- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{  UIView *headView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 30)];  if (section==0) {    UILabel *myLabel=[[UILabel alloc]initWithFrame:CGRectMake(10, 10, [[UIScreen mainScreen] bounds].size.width, 30)];    myLabel.text=@"日记列表";    [headView addSubview:myLabel];  }    return headView;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:BLSRecyclingRecordViewController_CellIdentifier];  if (indexPath.section == 0) {    DDLogFileInfo *logFileInfo = (DDLogFileInfo *)self.logFiles[indexPath.row];    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;    cell.textLabel.text = indexPath.row == 0 ? NSLocalizedString(@"当前", @"") : [self.dateFormatter stringFromDate:logFileInfo.creationDate];    cell.textLabel.textAlignment = NSTextAlignmentLeft;  } else {    cell.accessoryType = UITableViewCellAccessoryNone;    cell.textLabel.textAlignment = NSTextAlignmentCenter;    cell.textLabel.text = NSLocalizedString(@"清理旧的记录", @"");  }  return cell;}#pragma mark - Table view delegate- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{  [tableView deselectRowAtIndexPath:indexPath animated:YES];    if (indexPath.section == 0) {    DDLogFileInfo *logFileInfo = (DDLogFileInfo *)self.logFiles[indexPath.row];    NSData *logData = [NSData dataWithContentsOfFile:logFileInfo.filePath];    NSString *logText = [[NSString alloc] initWithData:logData encoding:NSUTF8StringEncoding];        LoggerDetailViewController *detailViewController = [[LoggerDetailViewController alloc] initWithLog:logText                                                    forDateString:[self.dateFormatter stringFromDate:logFileInfo.creationDate]];    [self.navigationController pushViewController:detailViewController animated:YES];  } else {    for (DDLogFileInfo *logFileInfo in self.logFiles) {      //除了当前 其它进行清除      if (logFileInfo.isArchived) {        [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];      }    }    [self loadLogFiles];    [self.myTableView reloadData];  }}@end

这边把表格分成两部分,一部分是日志文件的列表,以及一个清除功能,清除功能主要是对先前的文件进行删除的操作,读取日志的个数及日志时间,日志详细内容

DDLogFileInfo

6:异常的详细信息页面

LoggerDetailViewController.h代码#import <UIKit/UIKit.h>@interface LoggerDetailViewController : UIViewController- (id)initWithLog:(NSString *)logText forDateString:(NSString *)logDate;@end

LoggerDetailViewController.m文件#import "LoggerDetailViewController.h"@interface LoggerDetailViewController ()@property (nonatomic, strong) NSString *logText;@property (nonatomic, strong) NSString *logDate;@property (nonatomic, strong) UITextView *textView;@end@implementation LoggerDetailViewController- (void)viewDidLoad {  [super viewDidLoad];    self.textView = [[UITextView alloc] initWithFrame:self.view.bounds];  self.textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;  self.textView.editable = NO;  self.textView.text = self.logText;  [self.view addSubview:self.textView];}- (void)didReceiveMemoryWarning {  [super didReceiveMemoryWarning];  // Dispose of any resources that can be recreated.}- (id)initWithLog:(NSString *)logText forDateString:(NSString *)logDate{  self = [super initWithNibName:nil bundle:nil];  if (self) {    _logText = logText;    _logDate = logDate;    self.title = logDate;  }  return self;}@end

 这样便可以实现不管在哪个页面出出异常都可以进行记录,因为实例比较小,如果要源代码可以留下邮箱统一进行发送;