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 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 *[email protected][@"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)];
        myLa[email protected]"日记列表";
        [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

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

时间: 2024-10-25 04:34:16

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

IOS异常日志记录与展现

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

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

前言 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是简单的介绍如何在Visual Studio2010(Asp.Net Mvc3.0)中使用log4net快速创建系统日志,如何扩展以输出自定义字段. 用户可以从http://logging.apache.org/log4net/下载log4net的源代码.解压软件包后,在解压的src目录下将log4net.sln载入Visual

Spring + Aop+注解 集成使用 Log4j,实现异常日志记录

A,首先说,如何配置: 1,在web.xml中添加代码: <!-- log4j的配置相关 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:config/log4j/log4j.properties</param-value> </context-param> <context-param&g

redis队列结合log4net实现异常日志记录

查看了一些关于mvc异常日志记录的文章,发现使用redis+log4net的最多,这里简单总结了使用这种方式实现日志记录的过程.直接上步骤: 第一步:配置redis服务器 参考redis的配置和在.net中的使用 第二步:添加自己的异常过滤器(Models文件夹添加一个MyExceptionAttribute类) 1 public class MyExceptionAttribute : HandleErrorAttribute 2 { 3 //----所有用户出现异常,向同一个静态队列添加数据

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

缘起 哈喽我是不定期更新的日常,昨天群里小伙伴问到了记录日志,当然,以前我也挖过这个坑,后来一直没有来得及填上,也想着 swagger 一直又有错误信息展示的功能,就迟迟没有添加这个功能,不过昨天夜里想了想,还是需要增加上,旨在提高框架的高效性.不定期日常就直接上代码了,我有一个小想法,就是希望大家有好的想法,可以给我说,我会整理下,添加到框架里,并在文章头里写上 投稿作者:这里重点说明下,是参考群里小伙伴 Hello World! 的相关内容,并在他的基础上更新,添加了注入和全局,大家可以看看

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

应用场景和使用目的 很多时候,我们在访问页面的时候,由于程序异常.系统崩溃会导致出现黄页.在通常的情况下,黄页对于我们来说,帮助是极大的,因为它可以帮助我们知道问题根源,甚至是哪一行代码出现了错误.但这对于用户是非常可怕的,因为用户不知道发生了什么,也无法了解黄页给出的内容.甚至,如果我们遇到一些不友好的人,他们会拿这些内容大做文章,对我们网站产生威胁. 那我们如何在程序异常.系统崩溃时,不会出现黄页,并且还可以给出一些更加友好的提示呢?甚至在我们需要的时候,可以收集这些异常信息,并加以分析,能

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

http://www.cnblogs.com/kyo-yo/archive/2010/06/11/use-log4net-to-log-exception.html 在前端时间开发的时候由于需要将异常保存到数据库中,所以就到网上搜了下专门的日志记录工具,一搜果然很多,比如:log4net,NLog,EntLib Logging等等,但是还是log4net名气最大,所以就下载下来试用了一番,果然很方便,其涵盖了所有常用的日志记录方式具体的可以看下表: AdoNetAppender 将日志记录到数据

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

[编者按]本文作者是 Casey Dunham.Casey 是一位具有 10 多年经验的专业软件开发人员,以其独特的方式应对应用安全问题而闻名.本文系国内 ITOM 管理平台 OneAPM 工程师编译整理. 作为安全顾问,我对各种应用程序进行评估. 在我测试过的所有应用程序中,我发现它们通常会遇到一些对异常问题的处理和日志记录不足.日志记录和监控往往是被忽视的领域,并且由于对 Web 应用程序的威胁日益增加,它们已被添加到 OWASP Top 10 的十大问题之一,名为"Insufficient

C#错误异常日志记录到文件

当我们将网站布署到线上之后,为了实时了解网站的运行情况,如是否有错误页面.网站运行速度.是否有攻击等.那么我们就很有必要为网站加上错误与异常记录到日志文件,这样就可以随时查看网站的线上运行情况,另有一个好处是当网站有运行错误页面时,根据错误日志我们可以快速到定位到错误行进行排查原因.解决问题,这个是对于运行在线上而不能调试的网站的一个非常有必要的功能. 具体实现方法: 在全局文件Global.asax.cs中添加Application_Error的方法.只要当程序有错误时程序就会自动执行该方法,