关于App日志与奔溃信息的简单记录与上传

  1. Log日志的写入本地。
///----------------------------------
///  @name 调试输出
///----------------------------------

#import "_pragma_push.h"

#import 

#define DLogOut( ... ) if([DLFrameDebug sharedInstance].enabled)\
[[DLFrameDebug sharedInstance] file:@(__FILE__) line:__LINE__ func:@(__PRETTY_FUNCTION__) format:__VA_ARGS__];

@interface DLFrameDebug : NSObject

@singleton(DLFrameDebug)

/*!
 *  是否打开log
 */
@prop_assign(BOOL, enabled)

/// LogLevel, without in this framework

- (void)file:(NSString *)file line:(NSUInteger)line func:(NSString *)func format:(NSString *)format, ...;

@end

#import "_pragma_pop.h"
#import "DLFrameDebug.h"

@implementation DLFrameDebug

@def_singleton(DLFrameDebug)

- (void)file:(NSString *)file line:(NSUInteger)line func:(NSString *)func format:(NSString *)format, ... {
    
    if ( nil == format || NO == [format isKindOfClass:[NSString class]] )
        return;
    
    va_list args;
    va_start( args, format );
    
    [self file:file line:line func:func format:format args:args];
    
    va_end( args );
}

- (void)file:(NSString *)file line:(NSUInteger)line func:(NSString *)func format:(NSString *)format args:(va_list)params {
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    
    @autoreleasepool {
        
        NSMutableString * content = [[NSMutableString alloc] initWithFormat:(NSString *)format arguments:params];
        
        if ( content && content.length )
        {
            NSMutableString * text = [[NSMutableString alloc] init];
            if ( text ) {
                
                [text appendString:content];
                
                if ( [text rangeOfString:@"%"].length )
                {
                    [text replaceOccurrencesOfString:@"%"
                                          withString:@"%%"
                                             options:NSLiteralSearch
                                               range:NSMakeRange(0, text.length)];
                }
                
                if (![[NSFileManager defaultManager] fileExistsAtPath:DL_LOG_PATH]) {
                    
                    [[NSFileManager defaultManager] createFileAtPath:DL_LOG_PATH contents:nil attributes:nil];
                }
                
                NSString * logStr = [NSString stringWithContentsOfFile:DL_LOG_PATH encoding:NSUTF8StringEncoding error:nil];
                
                if (logStr) {
                    
                    logStr = [logStr stringByAppendingFormat:@"\n\n[TIME]:%@\n[FILE]:%@\n[FUNC]:%@\n[LINE]:%ld\n----->\n[INFO]:\n%@\n<-----\n", [NSDate date], file, func, (unsigned long)line, text];
                } else {
                    
                    logStr = text;
                }
                
                [logStr writeToFile:DL_LOG_PATH atomically:YES encoding:NSUTF8StringEncoding error:nil];
                
                fprintf( stderr, "\n\n--->\n[TIME]:%s\n[FUNC]:%s\n[LINE]:%d\n[INFO]:\n%s\n<---\n\n", [NSString stringWithFormat:@"%@", [NSDate date]].UTF8String, func.UTF8String, line, [text UTF8String]);
            }
        }
    }
}

@end

这样, 我们完成了Log日志的本地写入, 上边这种方法只是最普通的办法, 原本打算使用FILE然后重指向stderr的, 嘿嘿想想还是算了。 俗气的才是高大上的。 直接writetofile。

  1. Exception的捕获。

在ApplicationDidFinishLaunch中, 设置异常捕获的方法


    if ([DLFrameDebug sharedInstance].enabled) {
        
        // Add Exception Handler
        NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
    }

并实现这个方法, 使用Log把异常Log到日志中

void UncaughtExceptionHandler(NSException *exception) {
    
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *content = [NSString stringWithFormat:@"\n异常错误报告\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[callStack componentsJoinedByString:@"\n"]];
    
    DLogOut(@"%@", content);
}
  1. 是否正常退出

我专门写了一个Manager的单例类, 用来管理这个,要注册响应的应用程序状态的通知.

    // Add Notification For Default Manager
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(UIApplicationDidFinishLaunchingNotification)
                                                 name:UIApplicationDidFinishLaunchingNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(UIApplicationDidEndBackgroundNotification)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(UIApplicationDidBecameActive)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil];

在程序退到后台的时候, 设置一下正确退出了、 进入前台的时候设置不正确退出。 这样的话, 程序非正常退出的时候判断一下bool值就可以了。 在上次正常的情况下清理Log文件, 如果没有正常退出那就发送信息到服务器, 并清空。

- (void)UIApplicationDidFinishLaunchingNotification {
    
    // start some application operations
    [self startUp];
}

- (void)UIApplicationDidEndBackgroundNotification {
    
    // Change the Application Exit Status
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:ApplicationExited];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)UIApplicationDidBecameActive {
    
    // check application exit normal
    [self checkApplicationExitedNormal];
 
    // set first launch
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:ApplicationFirstLaunch];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)checkApplicationExitedNormal {
    NSLog(@"%d", [NSUserDefaults boolForKey:ApplicationExited]);
    if (![NSUserDefaults boolForKey:ApplicationExited] && ![NSUserDefaults boolForKey:ApplicationFirstLaunch]) {
        
        // Application first launch
    } else if ([NSUserDefaults boolForKey:ApplicationFirstLaunch] && ![NSUserDefaults boolForKey:ApplicationExited]) {
        
        NSString * logStr = [NSString stringWithContentsOfFile:DL_LOG_PATH encoding:NSUTF8StringEncoding error:nil];
        
        if (logStr) {
            
            [DLServer POST:@"logs.api" param:[@{
                                                @"data" : logStr
                                                } mutableCopy] complete:^(BOOL requestSuccess, id responseObject) {
                
            } error:^(NSError *error) {
                
            }];
        }
        
        [self clearLogFile];
    } else {
        
        // Exited Normal
        [self clearLogFile];
    }
}

- (void)clearLogFile {
    
    NSString * logStr = [NSString stringWithContentsOfFile:DL_LOG_PATH encoding:NSUTF8StringEncoding error:nil];
    if (logStr) {
        
        logStr = @"";
        [logStr writeToFile:DL_LOG_PATH atomically:YES encoding:NSUTF8StringEncoding error:nil];
    }
    
    DLogOut(@"%@, %@", DL_VERSION, DL_APP);
    
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:ApplicationExited];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)startUp {
    
    if ([DLFrameDebug sharedInstance].enabled) {
        
        // Add Exception Handler
        NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
    }
    
    [[DLFrame_ClassLoader classLoader] loadClasses:@[
                                                     
                                                     @"DLOperation"
                                                     
                                                     ]];
}

CopyRight@Dylan 2015-9-24.

你可能感兴趣的:(关于App日志与奔溃信息的简单记录与上传)