1. 鸿蒙日志系统概述:HiLog 与 kernel log 的区别,日志系统架构与设计理念

大家好,我是你们的老朋友。今天咱们来聊聊鸿蒙的日志系统。说实话,做嵌入式开发这么多年,我调试过 Linux、Android、RTOS 各种系统,但第一次接触鸿蒙的日志体系时,还是被它的设计思路惊艳到了。

为什么这么说?你想想看,一个系统要同时跑在手机、手表、电视、甚至微波炉上,日志系统如果设计得不够灵活,调试起来简直要命。鸿蒙的日志系统,说白了就是为这种「万物互联」场景量身打造的。

1.1 HiLog 与 kernel log:两个世界的对话

先讲个我踩过的坑。有一次在调试一个外设驱动,死活找不到问题在哪。我习惯性地去翻 kernel log,结果发现日志里全是「设备注册成功」「中断触发」这种底层信息,应用层到底传了什么数据过来,完全看不到。

后来我才意识到,鸿蒙把日志分成了两个世界:HiLogkernel log。它们俩各管一摊,互不干扰。

对比项 HiLog kernel log
所属层级 用户态(应用层、框架层) 内核态(驱动、内核模块)
输出目标 hilogd 守护进程 dmesg / kernel ring buffer
日志格式 结构化(域、标签、级别) 纯文本(printk 风格)
过滤能力 按域、标签、级别精准过滤 按关键词 grep
性能开销 低(异步写入) 极低(直接写环形缓冲区)
典型场景 业务逻辑调试、性能分析 驱动开发、内核崩溃分析

我个人习惯是:应用层问题用 HiLog,内核问题用 kernel log。千万别混着用,否则你会被海量信息淹没。

小技巧: 如果你不确定当前日志属于哪一层,可以看日志前缀。HiLog 通常带有 [domain.tag] 格式,而 kernel log 开头是时间戳和进程号。

1.2 日志系统架构:三层两通道

鸿蒙的日志系统架构,我给它起了个名字叫「三层两通道」。听起来复杂,其实很好理解。

第一层:日志产生层

就是咱们写代码时调用的那些 API。比如在应用层用 HiLog.info(),在内核用 printk()。这一层只负责把日志扔出去,不关心后续怎么处理。

第二层:日志传输层

这里就有意思了。鸿蒙没有用传统的 syslog 或者 logcat 那种方式,而是搞了一套自己的 hilogd 守护进程。它负责从各个进程收集日志,然后统一写入缓冲区。

我记得第一次看源码时,发现 hilogd 居然用了 mmap 共享内存 来传递日志。这意味着什么?意味着日志写入几乎不涉及系统调用,性能开销极低。嗯,这里要注意,如果你在写高频日志,这个设计能帮你省下不少 CPU。

第三层:日志消费层

就是咱们调试时用的工具,比如 hilog 命令行、DevEco Studio 的日志面板。它们从 hilogd 读取日志,然后展示给我们看。

核心设计理念: 日志产生和日志消费完全解耦。你尽管写日志,至于日志是存到文件、发到网络、还是直接丢弃,都由 hilogd 决定。这种设计在低内存设备上特别有用。

1.3 设计理念:为什么这么设计?

你可能会问:为什么鸿蒙不直接用 Linux 那套日志系统?

原因很简单:场景太复杂了。Linux 的日志系统是为服务器设计的,假设你有无限的内存和磁盘。但鸿蒙要跑在只有几百 KB 内存的 IoT 设备上,传统方案根本扛不住。

鸿蒙日志系统的设计理念,我总结为三点:

  • 零开销原则:日志写入不能影响主业务流程。所以用了异步写入、共享内存、无锁队列这些技术。
  • 按需过滤:不是所有日志都要看。通过域(domain)、标签(tag)、级别(level)三级过滤,让你只看到想看的。
  • 可裁剪性:在 Release 版本里,你可以把 HiLog 整个裁掉,一点痕迹都不留。这在 Android 里几乎做不到。
避坑指南: 我曾经在一个低端手表项目上,因为日志没关,导致系统频繁卡顿。后来发现是 hilogd 的缓冲区太小,日志写满了之后开始阻塞。解决方案很简单:Release 版本把日志级别调到 ERROR 以上,或者直接关闭 HiLog。

1.4 实战:快速区分 HiLog 和 kernel log

说了这么多理论,咱们来点实际的。怎么在代码里区分用哪个?

看个例子:

// 用户态 - 用 HiLog
#include <hilog/log.h>
static constexpr HiLogLabel LABEL = {LOG_CORE, 0x0001, "MyApp"};
HiLogInfo(LABEL, "用户点击了按钮,参数: %d", param);

// 内核态 - 用 printk
#include <linux/printk.h>
printk(KERN_INFO "驱动初始化完成,设备ID: %x\n", dev_id);

看到了吗?写法完全不同。HiLog 需要指定域和标签,而 kernel log 就是简单的 printk。

我个人建议:所有应用层代码统一用 HiLog,别图省事用 printf。为什么?因为 HiLog 的日志可以被 hilog 工具按域过滤,而 printf 只能输出到 stdout,调试时根本找不到。

好了,这一章咱们把鸿蒙日志系统的整体框架讲清楚了。下一章我会深入 HiLog 的 API 细节,包括怎么配域、怎么设标签、怎么控制日志级别。到时候我会分享一些我在实际项目中总结的「日志规范」,保证让你少走弯路。