在平常的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 AppDelegate

static 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

7:如果有第三方其它记录异常的使用,最好用DEBUG模式本地记录异常日志,不然日志只会被记录在一个地方

    //友盟统计加载
[HYBUMAnalyticsHelper UMAnalyticStart]; #ifdef DEBUG
//日志框架(放在其它SDK下面 MyExceptionHandler)
[MyExceptionHandler setDefaultHandler];
#else #endif [MyFileLogger sharedManager];

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

IOS异常日志记录与展现功能的更多相关文章

  1. Log4Net异常日志记录在asp.net mvc3.0的应用

    前言 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是简单的介绍如何在Visual ...

  2. Log4Net异常日志记录在asp.net mvc3.0的应用(转载)

    这篇博客写的很好:http://www.cnblogs.com/qianlifeng/archive/2011/04/22/2024856.html 前言 log4net是.Net下一个非常优秀的开源 ...

  3. IOS本地日志记录方案

    我们在项目中日志记录这块也算是比较重要的,有时候用户程序出什么问题,光靠服务器的日志还不能准确的找到问题. 现在一般记录日志有几种方式: 1.使用第三方工具来记录日志,如腾讯的Bugly,它是只把程序 ...

  4. 从壹开始前后端分离 [.netCore 不定期更新 ] 三十五║ 完美实现全局异常日志记录

    缘起 哈喽我是不定期更新的日常,昨天群里小伙伴问到了记录日志,当然,以前我也挖过这个坑,后来一直没有来得及填上,也想着 swagger 一直又有错误信息展示的功能,就迟迟没有添加这个功能,不过昨天夜里 ...

  5. IOS本地日志记录解决方案

    我们在项目中日志记录这块也算是比较重要的,有时候用户程序出什么问题,光靠服务器的日志还不能准确的找到问题 现在一般记录日志有几种方式: 1.使用第三方工具来记录日志,如腾讯的Bugly,它是只把程序的 ...

  6. ASP.NET全局错误处理和异常日志记录以及IIS配置自定义错误页面

    应用场景和使用目的 很多时候,我们在访问页面的时候,由于程序异常.系统崩溃会导致出现黄页.在通常的情况下,黄页对于我们来说,帮助是极大的,因为它可以帮助我们知道问题根源,甚至是哪一行代码出现了错误.但 ...

  7. OneAPM大讲堂 | Java 异常日志记录最佳实践

    [编者按]本文作者是 Casey Dunham.Casey 是一位具有 10 多年经验的专业软件开发人员,以其独特的方式应对应用安全问题而闻名.本文系国内 ITOM 管理平台 OneAPM 工程师编译 ...

  8. 转:使用log4net完成程序异常日志记录(使用SQLite数据库记录和普通文本记录)

    http://www.cnblogs.com/kyo-yo/archive/2010/06/11/use-log4net-to-log-exception.html 在前端时间开发的时候由于需要将异常 ...

  9. ASP.NET Web API 异常日志记录

    如果在 ASP.NET MVC 应用程序中记录异常信息,我们只需要在 Global.asax 的 Application_Error 中添加代码就可以了,比如: public class MvcApp ...

随机推荐

  1. linux ckconfig

    linux自定义开机启动服务和chkconfig使用方法 linux自定义开机启动服务和chkconfig使用方法 1. 服务概述在linux操作系统下,经常需要创建一些服务,这些服务被做成shell ...

  2. Angular开发Tips

    1.在使用$routeProvider的时候,需要让模块依赖ngRoute,否则会提示找不到服务,示例: angular.module('module1', ['ngRoute']) .config( ...

  3. [git]查看某一行代码是谁写的

    git blame filename,'blame'意思为责怪!哈哈哈. 就会列出来每行的修改纪录.你可以通过行数或者代码来查看,是谁的锅!

  4. ASP.NET跨服务器上传文件的相关解决方案

    第一种:通过FTP来上传文件 首先,在另外一台服务器上设置好FTP服务,并创建好允许上传的用户和密码,然后,在ASP.NET里就可以直接将文件上传到这台 FTP 服务器上了.代码如下: <%@ ...

  5. IOS中图片加载的一些注意点

    图片的加载: [UIImage imageNamed:@"home"] //加载 png图片 在ios中获取一张图片只需要写图片名即可 不需要写后缀 默认都是加载.png的图片 但 ...

  6. Http客户端识别的方法

      Http用户识别的机制方法分为如下几种: 1).承载用户身份的HTTP首部 2).客户端IP地址跟踪,根据客户端IP地址进行识别 3).用户登录,用认证方式设别用户 4).使用胖URL,一种在UR ...

  7. MySQL体系结构以及各种文件类型学习

    1,mysql体系结构 由数据库和数据库实例组成,是单进场多线程架构. 数据库:物理操作系统文件或者其它文件的集合,在mysql中,数据库文件可以是frm.myd.myi.ibd等结尾的文件,当使用n ...

  8. 点餐APP 冲刺一总结

    在冲刺一的过程中,我们小组每个人的任务相对来说都比较轻松,完成的进度也比较快, 主要的原因是每个人分配的任务都比较明确,大家也很积极地去完成.当然啦,我们在实现 项目的过程中也遇到了一些麻烦,主要是最 ...

  9. Sql Server来龙去脉系列之四 数据库和文件

        在讨论数据库之前我们先要明白一个问题:什么是数据库?     数据库是若干对象的集合,这些对象用来控制和维护数据.一个经典的数据库实例仅仅包含少量的数据库,但用户一般也不会在一个实例上创建太多 ...

  10. 利用DropDownList实现下拉

    在视图的Model<Vo>里面我们需要使用IEnumerable来将别的列表的数据全部的转化为下拉列表.下面是关于在项目中实际的写法. 一:实现下拉属性列表的写法   通过使用Select ...