鸿蒙Next获取应用崩溃日志

应用闪退是一个非常严重的问题,当我们做性能分析时,需要获取到用户的崩溃信息,查明崩溃原因。以下两种情况会导致程序异常退出:
1.Native代码未处理异常时
2.Js/ArkTS代码未处理异常时
接下来,主要讲述一下获取ArkTS层的崩溃信息。
HiAppEvent是在系统层面为应用开发者提供的一种事件打点机制,帮助应用记录在运行过程中发生的故障信息、统计信息、安全信息、用户行为信息,支撑开发者分析应用的运行情况

实现过程:

1.创建订阅者 Watcher配置和管理事件的观察者

名称说明
name观察者名称,用于唯一标识观察者
triggerCondition订阅回调触发条件
appEventFilters订阅过滤条件
onTrigger订阅回调函数
onReceive订阅实时回调函数
let watcher: hiAppEvent.Watcher = {
  // 自定义观察者名称,首字符必须为字母字符,中间字符必须为数字字符、字母字符或下划线字符,结尾字符必须为数字字符或字母字符
  name: "watcher",
  // 订阅了崩溃事件
  appEventFilters: [
    {
      domain: hiAppEvent.domain.OS,   //系统事件领域
      names: [hiAppEvent.event.APP_CRASH]
    }
  ],
  // 实时回调函数
  onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
    
  }
};
hiAppEvent.addWatcher(watcher);

2.处理回调信息AppEventGroup

名称说明
domain事件领域
name事件名称
eventType事件类型
params系统事件中params包含的字段已由各系统事件定义

3.params字段解析,存储到自定义的一个事件对象中

名称说明
time事件触发时间,单位为毫秒。
crash_type崩溃类型
foreground是否处于前台状态
bundle_version应用版本
bundle_name应用名称
pid应用的进程ID
uid应用的用户ID
uuid根据故障信息生成的故障特征码
exception异常信息
hilog日志信息,最多显示100行hilog日志
threads仅NativeCrash类型的崩溃事件提供
external_log故障日志文件路径
log_over_limit生成的故障日志文件与已存在的日志文件总大小是否超过5MB上限
onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
  for (const eventGroup of appEventGroups) {
    //watcher中我只订阅了崩溃事件
    for (const eventInfo of eventGroup.appEventInfos) {
      let eventInfoParam:EventInfoParam = {
        domain: eventInfo.domain,
        eventType: eventInfo.eventType,
        time: eventInfo.params['time'],
        crash_type: eventInfo.params['crash_type'],
        foreground: eventInfo.params['foreground'],
        bundle_version: eventInfo.params['bundle_version'],
        bundle_name: eventInfo.params['bundle_name'],
        pid: eventInfo.params['pid'],
        uid: eventInfo.params['uid'],
        uuid: eventInfo.params['uuid'],
        exception_name: eventInfo.params['exception']['name'],
        exception_message: eventInfo.params['exception']['message'],
        exception_stack: eventInfo.params['exception']['stack'],
        size: eventInfo.params['hilog'].length,
        external_log: JSON.stringify(eventInfo.params['external_log']),
        log_over_limit: eventInfo.params['log_over_limit'],
      }
      AppStorage.setOrCreate('EventInfoParam', eventInfoParam);
    }
  }
}

4.触发机制:当应用发生闪退后,再次打开会获取上次闪退的日志信息。
5.触发闪退,查看日志

I     =========EntryAbility: onCreate()
I     =========EntryAbility: onWindowStageCreate()
I     =========EntryAbility: onForeground()
I     =========EntryAbility: 获取到闪退日志
I     =========EntryAbility: 上传日志

由上可知,应用重启获取闪退日志是在程序进入到前台之后
闪退日志信息
详情.PNG
以上可以看到JsError异常的详细信息,基本可以帮我们定位到闪退原因。
补充一下JS Crash异常类型

名称说明
TypeError类型错误,运行时最常见的异常,表示变量或参数不是预期类型
SyntaxError语法错误,表示不符合编程语言的语法规范。
RangeError超出有效范围时发生的异常,列如数字类型的方法参数超出预定义范围
ReferenceError引用一个不存在的变量时发生的错误
URI Error在调用URI相关的方法中URL无效时抛出的异常
源码:
EntryAbility
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  console.log('=========EntryAbility:','onCreate()')
  let watcher: hiAppEvent.Watcher = {
    // 自定义观察者名称,首字符必须为字母字符,中间字符必须为数字字符、字母字符或下划线字符,结尾字符必须为数字字符或字母字符
    name: "watcher",
    // 订阅了崩溃事件
    appEventFilters: [
      {
        domain: hiAppEvent.domain.OS,   //系统事件领域
        names: [hiAppEvent.event.APP_CRASH]
      }
    ],
    // 实时回调函数
    onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
      for (const eventGroup of appEventGroups) {
        for (const eventInfo of eventGroup.appEventInfos) {
          let eventInfoParam:EventInfoParam = {
            domain: eventInfo.domain,
            eventType: eventInfo.eventType,
            time: eventInfo.params['time'],
            crash_type: eventInfo.params['crash_type'],
            foreground: eventInfo.params['foreground'],
            bundle_version: eventInfo.params['bundle_version'],
            bundle_name: eventInfo.params['bundle_name'],
            pid: eventInfo.params['pid'],
            uid: eventInfo.params['uid'],
            uuid: eventInfo.params['uuid'],
            exception_name: eventInfo.params['exception']['name'],
            exception_message: eventInfo.params['exception']['message'],
            exception_stack: eventInfo.params['exception']['stack'],
            size: eventInfo.params['hilog'].length,
            external_log: JSON.stringify(eventInfo.params['external_log']),
            log_over_limit: eventInfo.params['log_over_limit'],
          }
          AppStorage.setOrCreate('EventInfoParam', eventInfoParam);
        }
      }
      setTimeout(()=>{
        console.log('=========EntryAbility:','上传日志')
      },3000)
    }
  };
  hiAppEvent.addWatcher(watcher);
}

import { EventInfoParam } from '../model/EventInfoParam'
@Entry
@ComponentV2
struct EventInfoTest{
  eventInfoParam:EventInfoParam|undefined = AppStorage.get('EventInfoParam')
  build() {
    Scroll(){
      Column(){
        Text('JsError崩溃信息:')
        Text('事件领域:'+this.eventInfoParam?.domain)
        Text('事件类型:'+this.eventInfoParam?.crash_type)
        Text('事件触发时间:'+this.eventInfoParam?.time)
        Text('是否处于前台状态:'+this.eventInfoParam?.foreground)
        Text('应用版本:'+this.eventInfoParam?.bundle_version)
        Text('应用名称:bundleName')
        Text('进程ID:'+this.eventInfoParam?.pid)
        Text('用户ID:'+this.eventInfoParam?.uid)
        Text('uuid:根据故障信息生成的故障特征码,用于标识特征相同的崩溃故障')
        Text('JsError异常类型:'+this.eventInfoParam?.exception_name)
        Text('JsError异常原因:'+this.eventInfoParam?.exception_message)
        Text('JsError异常调用栈:'+this.eventInfoParam?.exception_stack)
        Text('日志信息:最多显示100行hilog日志')
        Text('故障日志文件路径:'+this.eventInfoParam?.external_log)
        Text('生成的故障日志文件与已存在的日志文件总大小是否超过5MB上限:'+this.eventInfoParam?.log_over_limit)
      }
      .alignItems(HorizontalAlign.Start)
    }.height('100%')
  }
}

export interface EventInfoParam {
  domain: string
  eventType: number
  time: number
  crash_type: string
  foreground: boolean
  bundle_version: string
  bundle_name: string
  pid: number
  uid: number
  uuid: string
  exception_name: string
  exception_message: string
  exception_stack: string
  size: number
  external_log: string
  log_over_limit: boolean
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值