日志,Crash,埋点

20 9月
  • 日志(CocoaLumberjack)
  • Crash
  • 埋点

日志(CocoaLumberjack)

日志系统很重要,需要上报包括但不限于Crash,Error,使用时长,用户在关键路径的行为日志等。通常上报系统是个Framework被集成进工程中,因为上报系统除了网络传输完,通常还会有可视化数据展示界面等,比较通用,独立出来可以多项目复用。

代码中要记录日志可以用NSLog,除了能在xcode的控制台显示外,还会额外记录到Apple System Log(ASL)中,这就注定了NSLog的执行效率比较低。而且NSLog设计出来本意是记录error的,没有日志level分级,所以记录一些辅助信息,或用户行为时,不便于日志中分级查找数据。所以大APP都使用开源的日志系统,例如CocoaLumberjack

CocoaLumberjack解决了NSLog的不足,提供了日志level分级,支持存储到本地日志文件中,支持自定义logger格式等。

照着github官网的安装流程,用pods集成进工程后,在pods目录下可以观察一下CocoaLumberjack.h,主文件已经给你合理的规划了整个开源项目的组织结构。

项目中可以不用NSLog了,替换为DDLogMessage先给日志level分级,还可以用DDLogFormatter自定义格式化日志。

日志存储CocoaLumberjack.h里提供了:

#import <CocoaLumberjack/DDTTYLogger.h>    // xcode控制台输出(调用系统标准输入/输出)
#import <CocoaLumberjack/DDASLLogger.h>    // 存储到Apple System Log(ASL)中,可以在Console.app中查看
#import <CocoaLumberjack/DDFileLogger.h>   // 存储到APP本地文件内
#import <CocoaLumberjack/DDOSLogger.h>     // IOS10+版本后,用这个替代上面的DDTTYLogger和DDASLLogger

最常用的当然是DDFileLogger,将日志存储到APP本地的沙盒文件夹内。这都需要程序员根据需求自己设计:

  • IO存储是主线程和非主线程间的安全
  • 文件存储的位置
  • 文件命名
  • 文件大小的阀值
  • 文件过期的阀值 & 过期自动清理
  • Kill APP的保存
  • applicationWillTerminate flush和mmap

关于开源库就不多赘述,用法直接看github官网。

Crash

APP的Crash率是必须要收集的指标,当Crash发生时,我们要收集当时的堆栈并上报,以便排查问题。

Crash分系统级应用级

系统级的是Signal信号,每当Mach内核发生异常时(例如野指针)都会发送Unix信号,APP接收到这个信号会进行APP应用的中断,并发送SIGKILL,SIGSEGV等信号。

应用级的的是NSException,例如当程序员不规范使用系统函数(如参数类型错误)会抛出NSException。

开发者需要捕捉不同类型的Crash,收集现场堆栈信息,保存到日志里并上报。例如:、

#include <execinfo.h>

[self _caughtException];    // 启用异常捕获

- (void)_caughtException{
    // NSexception
    NSSetUncaughtExceptionHandler(HandleNSException);
    
    // signal
    signal(SIGABRT, SignalExceptionHandler);
    signal(SIGILL, SignalExceptionHandler);
    signal(SIGSEGV, SignalExceptionHandler);
    signal(SIGFPE, SignalExceptionHandler);
    signal(SIGBUS, SignalExceptionHandler);
    signal(SIGPIPE, SignalExceptionHandler);
}

void HandleNSException(NSException *exception){
    __unused NSString *reason = [exception reason];
    __unused NSString *name = [exception name];
    // 存储 crash 信息并上报
}

void SignalExceptionHandler(int signal){
    void* callstack[128];
    int frames = backtrace(callstack, 128);
    char **strs = backtrace_symbols(callstack, frames);
    NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
    for (int i = 0; i < frames; i++) {
        [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
    }
    free(strs);
    // 存储 crash 信息并上报
}

可以用开源项目KSCrashPLCrashReporter,它们会尽可能多的收集不同类型的Crash并存储。但上传和分析日志里Crash原因还是需要开发者自己完成。

当然也有第三方SDK如友盟Bugly,集成进工程后提供收集Crash,存储,上报,分析,报表展示等一条龙服务。

埋点

埋点分手动埋点自动埋点

手动埋点非常直观,程序员在需要埋点的地方手动写发送网络请求的代码。缺点是对代码侵入性强,而且跟版,一旦埋点参数传错,只能下个版本修复。

自动埋点原理是基于IOS的Runtime / 消息转发的机制,来hook住通用方法,如hook住点击事件,hook住所有View的生命周期的方法来统计时长,hook主NSURLSession的网络接口,全自动实现埋点上报。这样对业务代码没有侵入性。

可以使用开源框架如Aspects实现自动埋点。

发表评论

电子邮件地址不会被公开。 必填项已用*标注