iOS运用 Metrickit 搜集溃散日志

Metrickit 是什么

MetricKit 是 苹果在 iOS13体系开端引入的用来汇总和分析有关反常和溃散确诊以及电源和性能指标的每个设备的陈述。

为什么要用 MetricKit 搜集溃散日志

当时市面上的开源结构,如 KSCrash,PLCrashReport 等结构都有一些溃散不能抓取;比如PLCrashReport 不能抓取栈溢出的溃散,不能抓取SIGKILL, SIGQUIT等信号量的溃散。KSCrash 对SIGKILL的溃散抓取也只能抓取一部分

Metrickit 缺点

1.目前只支持 iOS14 以后的溃散日志搜集

2.溃散日志没有返回具体的溃散时刻和启动时刻,溃散场景信息除了仓库外没有其他信息

3.假如运用了段搬迁编译技术,主程序 macho 的地址和 uuid 无法匹配。

iOS14的溃散日志是24小时会回调通知一次,时效性低;iOS15 之后,溃散日志会在下次启动之后就返回,但经验证,有的会当即回调,有的则不然,规律不行揣摩

开端接入

1.增加 MetricKit

iOS使用 Metrickit 收集崩溃日志

2.增加 MetricKit 监听者


if (@available(iOS 14.0, *)) {
    MXMetricManager *manager = [MXMetricManager sharedManager];
    if (self && manager && [manager respondsToSelector:@selector(addSubscriber:)]) {
      [manager addSubscriber:self];
    }
  }  

3. 监听者完成 MXMetricManagerSubscriber 协议办法, payloadDic 里面包含着上次本应用产生的溃散日志仓库和信息


 // 苹果假如有数据数据,注册监听之后就会回调
- (void)didReceiveDiagnosticPayloads:(NSArray<MXDiagnosticPayload *> * _Nonnull)payloads API_AVAILABLE(ios(14.0)){
  if (@available(iOS 14.0, *)) {
    for (MXDiagnosticPayload *payload in payloads) {
        NSDictionary *payloadDic = [payload dictionaryRepresentation];
       
      });
    }
  }
}

4.日志拼装关键代码示例


NSArray *callStackRootFrames = [dicFrame ArrayValueForKey:kMetrkitCallStackRootFramesKey];
      if (callStackRootFrames.count <= 0) {
        continue;
      }
      NSDictionary *dicZero = [callStackRootFrames ObjectAtIndex:0];
      int rootIndex = 0;
      while (dicZero && dicZero.count > 0) {
        NSString *binaryUUID = [dicZero  stringValueForKey:kMetrkitBinaryUUIDKey];
        NSString *binaryName = [dicZero  stringValueForKey:kMetrkitBinaryNameKey];
        long long baseAdd = [[dicZero NumberValueForKey:kMetrkitOffsetIntoBinaryTextSegmentKey] longLongValue];
        long long address = [[dicZero numberValueForKey:kMetrkitAddressKey] longLongValue];
        NSArray *subFrames = [dicZero arrayValueForKey:kMetrkitSubFramesKey];
        [strStack appendFormat:@"%d %@ 0x%llx 0x%llx + %lld\n", rootIndex, binaryName, baseAdd, address, address - model.baseAddress];
        rootIndex++;
        if (subFrames && subFrames.count >= 0) {
          dicZero = [subFrames ObjectAtIndex:0];
        } else {
          dicZero = nil;
        }
    

MetricKit 返回字段意义及概况

JSON总格局

key 值类型 解说 demo值
crashDiagnostics Array 记载的溃散 见下面概况
hangDiagnostics Array 记载的卡顿信息 见下面概况
cpuExceptionDiagnostics Array 记载的cpu反常信息 见下面概况
diskWriteExceptionDiagnostics Array 记载的磁盘写入反常信息 见下面概况
timeStampBegin Date 记载事情开端间隔 2021-12-01 09:06:57 +0000
timeStampEnd Date 记载事情完毕间隔 2021-12-01 09:06:57 +0000

crashDiagnostics 概况

每一个溃散为一个字典,具体内容为下

key 值类型 解说 demo值
version String Metrkit 结构版别 1.0.0
diagnosticMetaData 字典 溃散的一些中心信息(含App信息) 见二级概况
callStackTree 字典 仓库相关信息 见二级概况

diagnosticMetaData 字典概况

key 值类型 解说 demo值
appBuildVersion String build 12.29.0.1
appVersion String app 版别 12.29.0
regionFormat String 区域代码 CN
exceptionType String 反常类型 1
osVersion String iOS 操作体系 iPhone OS 15.1 (19B74)
deviceType String Model iPhone13,1
bundleIdentifier String bundle com.xxx.xxxxx
exceptionCode String exception Code 1
signal String 信号量符号 11
platformArchitecture String cpu 架构 arm64e
virtualMemoryRegionInfo String 虚拟内存信息 0x10 is not in any region. Bytes before following region: 433969560 REGION TYPE START- END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START—> __**TEXT 102aa8000-11012c000 [214.5M] r-x/r-x SM=COW …p/xxxxx **

|terminationReason|String|溃散原因| RBSTerminateContext domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: application<com.xxx.xxxx> :6308 exhausted real (wall clock) time allowance of 10.00 seconds|

callStackTree 字典概况

key 值类型 解说 demo值
callStacks Array 每个线程具体仓库 见三级概况
callStackPerThread BOOL 是否只搜集单线程 见二级概况

callStacks 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
threadAttributed BOOL 是否是溃散线程 true
callStackRootFrames Array 单线程仓库具体信息 见下一级级概况

callStackRootFrames 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
binaryUUID String uuid DC6B1885-FB91-34C4-A9FC-A539C17A08A7
offsetIntoBinaryTextSegment int 根据二进制macho的偏移,十进制 4339695616
sampleCount int 不知道 1
binaryName String 二进制macho的称号 xxx
address int 二进制macho的基址 4446737180
subFrames Array 诱发此次溃散的上一级线程 有或许循环递归callStackRootFrames内容

diskWriteExceptionDiagnostics 概况

每一个溃散为一个字典,具体内容为下

key 值类型 解说 demo值
version String Metrkit 结构版别 1.0.0
diagnosticMetaData 字典 溃散的一些中心信息(含App信息) 见二级概况
callStackTree 字典 仓库相关信息 见二级概况

diagnosticMetaData 字典概况

key 值类型 解说 demo值
appBuildVersion String build 12.29.0.1
appVersion String app 版别 12.29.0
regionFormat String 区域代码 CN
osVersion String iOS 操作体系 iPhone OS 15.1 (19B74)
deviceType String Model iPhone13,1
bundleIdentifier String bundle com.xxx
writesCaused String 写原因 2,000字节
platformArchitecture String cpu 架构 arm64e

callStackTree 字典概况

key 值类型 解说 demo值
callStacks Array 每个线程具体仓库 见三级概况
callStackPerThread BOOL 是否只搜集单线程 见二级概况

callStacks 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
threadAttributed BOOL 是否是触发线程 true
callStackRootFrames Array 单线程仓库具体信息 见下一级级概况

callStackRootFrames 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
binaryUUID String uuid DC6B1885-FB91-34C4-A9FC-A539C17A08A7
offsetIntoBinaryTextSegment int 根据二进制macho的偏移,十进制 4339695616
sampleCount int 不知道 1
binaryName String 二进制macho的称号 xxxxx
address int 二进制macho的基址 4446737180
subFrames Array 诱发此次溃散的上一级线程 有或许循环递归callStackRootFrames内容

cpuExceptionDiagnostics 概况

每一个溃散为一个字典,具体内容为下

key 值类型 解说 demo值
version String Metrkit 结构版别 1.0.0
diagnosticMetaData 字典 溃散的一些中心信息(含App信息) 见二级概况
callStackTree 字典 仓库相关信息 见二级概况

diagnosticMetaData 字典概况

key 值类型 解说 demo值
appBuildVersion String build 12.29.0.1
appVersion String app 版别 12.29.0
regionFormat String 区域代码 CN
osVersion String iOS 操作体系 iPhone OS 15.1 (19B74)
deviceType String Model iPhone13,1
bundleIdentifier String bundle com.xxx
totalCPUTime String cpu时刻 20s
totalSampledTime String CPU总采样时刻 20s
platformArchitecture String cpu 架构 arm64e

callStackTree 字典概况

key 值类型 解说 demo值
callStacks Array 每个线程具体仓库 见三级概况
callStackPerThread BOOL 是否只搜集单线程 见二级概况

callStacks 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
threadAttributed BOOL 是否是触发线程 true
callStackRootFrames Array 单线程仓库具体信息 见下一级级概况

callStackRootFrames 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
binaryUUID String uuid DC6B1885-FB91-34C4-A9FC-A539C17A08A7
offsetIntoBinaryTextSegment int 根据二进制macho的偏移,十进制 4339695616
sampleCount int 不知道 1
binaryName String 二进制macho的称号 xxxxx
address int 二进制macho的基址 4446737180
subFrames Array 诱发此次溃散的上一级线程 有或许循环递归callStackRootFrames内容

hangDiagnostics 概况

每一个溃散为一个字典,具体内容为下

key 值类型 解说 demo值
version String Metrkit 结构版别 1.0.0
diagnosticMetaData 字典 溃散的一些中心信息(含App信息) 见二级概况
callStackTree 字典 仓库相关信息 见二级概况

diagnosticMetaData 字典概况

key 值类型 解说 demo值
appBuildVersion String build 12.29.0.1
appVersion String app 版别 12.29.0
regionFormat String 区域代码 CN
osVersion String iOS 操作体系 iPhone OS 15.1 (19B74)
deviceType String Model iPhone13,1
bundleIdentifier String bundle com.xxx
hangDuration String 卡顿时刻 20s
platformArchitecture String cpu 架构 arm64e

callStackTree 字典概况

key 值类型 解说 demo值
callStacks Array 每个线程具体仓库 见三级概况
callStackPerThread BOOL 是否只搜集单线程 见二级概况

callStacks 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
threadAttributed BOOL 是否是触发线程 true
callStackRootFrames Array 单线程仓库具体信息 见下一级级概况

callStackRootFrames 数组概况

数组中元素为字典,概况如下

key 值类型 解说 demo值
binaryUUID String uuid DC6B1885-FB91-34C4-A9FC-A539C17A08A7
offsetIntoBinaryTextSegment int 根据二进制macho的偏移,十进制 4339695616
sampleCount int 不知道 1
binaryName String 二进制macho的称号 xxxxx
address int 二进制macho的基址 4446737180
subFrames Array 诱发此次溃散的上一级线程 有或许循环递归callStackRootFrames内容