• 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:@"========异常错误报告========
    name:%@
    reason:
    %@
    callStackSymbols:
    %@",name,reason,[arr componentsJoinedByString:@"
    "]];
        DDLogError(@"%@
    
    ",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:@"========异常错误报告========
    name:%@
    reason:
    %@
    callStackSymbols:
    %@",name,reason,[arr componentsJoinedByString:@"
    "]];
        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];

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

  • 相关阅读:
    CentOS 7拨号上网(ADSL & PPPoE)
    linux使用nmcli重新生成网卡配置文件
    Linux 内存缓存占用过大,Centos7设置定时清除buff/cache的脚本
    部署redis6.0 常见问题
    ssh 升级导致的hadoop 主备切换失败
    配置zookeeper的 ACL权限
    sqoop 创建跟mysql相同表结构的hive表报错
    vim中显示不可见字符
    supervisor 使用
    使用hive streaming 统计Wordcount
  • 原文地址:https://www.cnblogs.com/wujy/p/4862143.html
Copyright © 2020-2023  润新知