HarmonyOS鸿蒙Next中是否支持将自定义日志写到系统的异常log中

HarmonyOS鸿蒙Next中是否支持将自定义日志写到系统的异常log中 比如,在App崩溃时,会产生log文件,这些log文件会上报到aps,或者可联机查看。

当App将要崩溃时,有没有什么方法把一些自定义的日志记录在这个崩溃产生的log中。

9 回复

【解决方案】

  1. 新建一个ArkTS应用工程,编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件,导入依赖模块:

    import { BusinessError } from '@kit.BasicServicesKit';
    import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit';
    
  2. 编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件,在onCreate函数中设置事件的自定义参数,示例代码如下:

     // 开发者完成参数键值对赋值
     let params: Record<string, hiAppEvent.ParamType> = {
       "test_data": 100,
     };
     // 开发者可以设置崩溃事件的自定义参数
     hiAppEvent.setEventParam(params, hiAppEvent.domain.OS, hiAppEvent.event.APP_CRASH).then(() => {
       hilog.info(0x0000, 'testTag', `HiAppEvent success to set svent param`);
     }).catch((err: BusinessError) => {
       hilog.error(0x0000, 'testTag', `HiAppEvent code: ${err.code}, message: ${err.message}`);
     });
    
  3. 编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件,在onCreate函数中添加系统事件的订阅,示例代码如下:

     hiAppEvent.addWatcher({
       // 开发者可以自定义观察者名称,系统会使用名称来标识不同的观察者
       name: "watcher",
       // 开发者可以订阅感兴趣的系统事件,此处是订阅了崩溃事件
       appEventFilters: [
         {
           domain: hiAppEvent.domain.OS,
           names: [hiAppEvent.event.APP_CRASH]
         }
       ],
       // 开发者可以自行实现订阅实时回调函数,以便对订阅获取到的事件数据进行自定义处理
       onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
         hilog.info(0x0000, 'testTag', `HiAppEvent onReceive: domain=${domain}`);
         for (const eventGroup of appEventGroups) {
           // 开发者可以根据事件集合中的事件名称区分不同的系统事件
           hilog.info(0x0000, 'testTag', `HiAppEvent eventName=${eventGroup.name}`);
           for (const eventInfo of eventGroup.appEventInfos) {
             // 开发者可以对事件集合中的事件数据进行自定义处理,此处是将事件数据打印在日志中
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.domain=${eventInfo.domain}`);
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.name=${eventInfo.name}`);
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.eventType=${eventInfo.eventType}`);
             // 开发者可以获取到崩溃事件发生的时间戳
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.time=${eventInfo.params['time']}`);
             // 开发者可以获取到崩溃事件发生的崩溃类型
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.crash_type=${eventInfo.params['crash_type']}`);
             // 开发者可以获取到崩溃应用的前后台状态
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.foreground=${eventInfo.params['foreground']}`);
             // 开发者可以获取到崩溃应用的版本信息
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_version=${eventInfo.params['bundle_version']}`);
             // 开发者可以获取到崩溃应用的包名
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_name=${eventInfo.params['bundle_name']}`);
             // 开发者可以获取到崩溃应用的进程id
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.pid=${eventInfo.params['pid']}`);
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.uid=${eventInfo.params['uid']}`);
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.uuid=${eventInfo.params['uuid']}`);
             // 开发者可以获取到崩溃事件发生的异常类型、异常原因和异常调用栈
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.exception=${JSON.stringify(eventInfo.params['exception'])}`);
             // 开发者可以获取到崩溃事件发生时日志信息
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.hilog.size=${eventInfo.params['hilog'].length}`);
             // 开发者可以获取到崩溃事件发生时的故障日志文件
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.external_log=${JSON.stringify(eventInfo.params['external_log'])}`);
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.log_over_limit=${eventInfo.params['log_over_limit']}`);
             // 开发者可以获取到崩溃事件的自定义数据test_data
             hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.test_data=${eventInfo.params['test_data']}`);
           }
         }
       }
     });
    

更多关于HarmonyOS鸿蒙Next中是否支持将自定义日志写到系统的异常log中的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


不支持直接将自定义日志内容写入到系统自动生成的崩溃日志文件中


1. 系统崩溃日志的生成机制

  • 崩溃日志(如 NativeCrash、JsError)由系统底层模块(如 FaultLogger)自动生成,记录的是故障发生时的现场信息(寄存器、堆栈、内存映射等)。
  • 这些日志有固定格式和内容规范,开发者无法直接修改或追加自定义内容到这些系统生成的日志文件中

2. 替代方案:在崩溃时记录自定义日志

虽然不能直接修改系统崩溃日志,但可以通过以下方式在崩溃发生时同时记录自定义信息

✅ 方案一:通过 HiAppEvent 订阅崩溃事件并附加自定义参数

  • 使用 hiAppEvent.setEventParam() 接口在崩溃前预置自定义参数(如用户ID、业务状态等),这些参数会随着崩溃事件上报(存储在 params 字段中)。
  • 示例代码
    let customParams: Record<string, hiAppEvent.ParamType> = {
      "user_id": "12345",
      "business_state": "pending"
    };
    hiAppEvent.setEventParam(customParams, hiAppEvent.domain.OS, hiAppEvent.event.APP_CRASH);
    
  • 当崩溃发生时,这些自定义参数会通过 HiAppEvent 的回调(OnTake)返回,开发者可在回调中处理或存储这些数据。

✅ 方案二:在崩溃回调中记录独立日志

  • 通过 JSVM-API 注册崩溃回调(如 OH_JSVM_SetHandlerForFatalError),在回调中用 HiLog 或 HiAppEvent 单独记录自定义日志
    void FatalErrorHandler(const char* message) {
        // 记录自定义日志到独立文件或流水日志
        OH_LOG_ERROR(LOG_APP, "Custom crash info: user_data=%{public}s", "your_data");
    }
    
  • 这些自定义日志会通过 HiLog 输出,但不会合并到系统崩溃日志中,需开发者自行关联(如通过时间戳或进程ID匹配)。

3. 注意事项

  • 系统崩溃日志的只读性:崩溃日志由内核级模块生成,格式固定,无法直接注入自定义内容。
  • 时序限制:在崩溃回调中记录日志需确保操作是异步且非阻塞的,避免影响崩溃恢复流程。
  • 日志关联:自定义日志需通过时间戳、进程ID等与系统崩溃日志关联,便于后续分析。

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

订阅App崩溃事件

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/hiappevent-watcher-crash-events-arkts-V14

https://gitee.com/harmonyos_samples/exception-handling(git示例)

EntryAbility.ets

 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
  hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

  // 开发者完成参数键值对赋值
  let params: Record<string, hiAppEvent.ParamType> = {
   "test_data": 100,
   };
  // 开发者可以设置崩溃事件的自定义参数
  hiAppEvent.setEventParam(params, hiAppEvent.domain.OS, hiAppEvent.event.APP_CRASH).then(() => {
    hilog.info(0x0000, 'testTag', `HiAppEvent success to set event param`);
   }).catch((err: BusinessError) => {
    hilog.error(0x0000, 'testTag', `HiAppEvent code: ${err.code}, message: ${err.message}`);
   });


  this.watcher = {
   // 开发者可以自定义观察者名称,系统会使用名称来标识不同的观察者
   name: "watcher",
   // 开发者可以订阅感兴趣的系统事件,此处是订阅了崩溃事件
   appEventFilters: [
     {
       domain: hiAppEvent.domain.OS,
       names: [hiAppEvent.event.APP_CRASH]
     }
    ],
   // 开发者可以自行实现订阅实时回调函数,以便对订阅获取到的事件数据进行自定义处理
   onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
    hilog.info(0x0000, 'testTag', `HiAppEvent onReceive: domain=${domain}`);
    for (const eventGroup of appEventGroups) {
      // 开发者可以根据事件集合中的事件名称区分不同的系统事件
      hilog.info(0x0000, 'testTag', `HiAppEvent eventName=${eventGroup.name}`);
      for (const eventInfo of eventGroup.appEventInfos) {
        // 开发者可以对事件集合中的事件数据进行自定义处理,此处是将事件数据打印在日志中
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.domain=${eventInfo.domain}`);
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.name=${eventInfo.name}`);
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.eventType=${eventInfo.eventType}`);
        // 开发者可以获取到崩溃事件发生的时间戳
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.time=${eventInfo.params['time']}`);
        // 开发者可以获取到崩溃事件发生的崩溃类型
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.crash_type=${eventInfo.params['crash_type']}`);
        // 开发者可以获取到崩溃应用的前后台状态
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.foreground=${eventInfo.params['foreground']}`);
        // 开发者可以获取到崩溃应用的版本信息
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_version=${eventInfo.params['bundle_version']}`);
        // 开发者可以获取到崩溃应用的包名
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_name=${eventInfo.params['bundle_name']}`);
        // 开发者可以获取到崩溃应用的进程id
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.pid=${eventInfo.params['pid']}`);
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.uid=${eventInfo.params['uid']}`);
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.uuid=${eventInfo.params['uuid']}`);
        // 开发者可以获取到崩溃事件发生的异常类型、异常原因和异常调用栈
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.exception=${JSON.stringify(eventInfo.params['exception'])}`);
        // 开发者可以获取到崩溃事件发生时日志信息
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.hilog.size=${eventInfo.params['hilog'].length}`);
        // 开发者可以获取到崩溃事件发生时的故障日志文件
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.external_log=${JSON.stringify(eventInfo.params['external_log'])}`);
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.log_over_limit=${eventInfo.params['log_over_limit']}`);
        // 开发者可以获取到崩溃事件的自定义数据test_data
        hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.test_data=${eventInfo.params['test_data']}`);
      }
     }
   }
  };
  hiAppEvent.addWatcher(this.watcher);
 }

Index.ets

@Entry
@Component
struct Index {
 @State message: string = 'Hello World';

 build() {
  RelativeContainer() {
    Text(this.message)
      .id('HelloWorld')
      .fontSize($r('app.float.page_text_font_size'))
      .fontWeight(FontWeight.Bold)
      .alignRules({
       center: { anchor: '__container__', align: VerticalAlign.Center },
       middle: { anchor: '__container__', align: HorizontalAlign.Center }
      })
      .onClick(()=>{
        // 在按钮点击函数中构造一个crash场景,触发应用崩溃事件
        let result: object = JSON.parse("");
      })
   }
   .height('100%')
   .width('100%')
 }
}

嗯,定义局部变量或者按你说的直接添加就行,this.watcher没有是因为只发了部分代码,声明的代码没贴过来,

订阅崩溃事件

import hiAppEvent from '@kit.HiviewDFX';
import { BusinessError } from '@kit.BasicServicesKit';

// 订阅应用崩溃事件
hiAppEvent.addWatcher({
  // 声明订阅事件类型
  watcher: {
    name: "crashWatcher",
    appCrash: true  // 开启应用崩溃监听
  },
  // 事件回调处理
  onTrigger: (event: hiAppEvent.AppEvent) => {
    if (event.event === "APP_CRASH") {
      // 获取系统生成的崩溃日志路径
      const externalLogs = event.params['external_log'];
      if (externalLogs && externalLogs.length > 0) {
        appendCustomLog(externalLogs); // 向日志文件追加内容
      }
    }
  }
});

使用 hiAppEvent 订阅崩溃事件
通过 hiAppEvent.addWatcher 接口订阅应用崩溃事件,在回调中获取系统生成的崩溃日志路径,并将自定义日志追加到该文件中或同步上报:

import hiAppEvent from '@ohos.hiAppEvent';
import { BusinessError } from '@ohos.base';
import fs from '@ohos.file.fs';

// 订阅崩溃事件
hiAppEvent.addWatcher({
  name: 'crash_watcher',
  appEventFilters: [{ domain: 'APP_CRASH' }]
}, (err: BusinessError, eventInfo: hiAppEvent.AppEventInfo) => {
  if (err) {
    console.error('订阅失败:', err.code, err.message);
    return;
  }
  // 获取系统生成的崩溃日志路径
  const externalLogs: string[] = eventInfo.params['external_log'];
  // 自定义日志内容
  const customLog = '[CUSTOM_LOG] App encountered critical error before crash.';
  // 将自定义日志写入崩溃日志文件
  externalLogs.forEach((logPath) => {
    fs.appendFileSync(logPath, customLog + '\n', { encoding: fs.Encoding.UTF8 });
  });
});

通过全局异常捕获或信号处理函数,在崩溃发生前将自定义日志写入临时文件,确保日志能被系统崩溃日志包含

// 示例:捕获未处理的Promise异常
process.on('unhandledRejection', (reason) => {
  const crashLogPath = '/data/app/el2/log/hiappevent/crash_custom.log';
  fs.writeFileSync(crashLogPath, `[UNHANDLED_REJECTION] ${reason}\n`, { encoding: fs.Encoding.UTF8 });
});

HarmonyOS Next不支持将自定义日志直接写入系统异常日志。系统异常日志仅记录由系统框架层捕获的运行时异常和崩溃信息。开发者可通过HiLog接口将自定义日志写入应用日志文件,日志级别分为DEBUG、INFO、WARN、ERROR。ERROR级别日志会与系统异常日志同步存储,但独立分类。日志查看需使用DevEco Studio的Logcat工具或hilog命令行筛选特定TAG。

在HarmonyOS Next中,可以通过HiLog模块的崩溃日志捕获机制实现自定义日志与系统异常日志的整合。具体方案如下:

  1. 注册崩溃信号处理器
    使用signal()函数捕获SIGABRT等崩溃信号,在信号回调中调用自定义日志记录方法:

    signal(SIGABRT, crashSignalHandler);
    
  2. 同步自定义日志到系统流
    在崩溃回调中,将内存中的环形缓冲区日志通过HiLogLabel写入系统日志:

    OH_HiLog_Print(LOG_APP, LOG_ERROR, 0xFF00, "CRASH", "Custom log: %s", buffer);
    
  3. 关键时机捕获
    通过pthread_cleanup_push或析构函数,确保在进程终止前执行日志刷写:

    __attribute__((destructor)) void flushLogs() {
        // 将缓存日志写入HiLog
    }
    
  4. 日志关联性
    自定义日志会携带与崩溃日志相同的进程ID、时间戳等元数据,方便在APSS(应用崩溃分析服务)中关联分析。

注意事项:

  • 需在config.json中声明ohos.permission.READ_LOGS权限
  • 异步日志需确保线程安全,避免在崩溃处理中二次崩溃
  • 日志内容长度受系统策略限制(单条通常不超过4KB)

此方案适用于定位复杂崩溃场景的上下文信息,但需注意频繁日志写入可能影响性能。

回到顶部