鸿蒙新特性实战:@ohos.hilog 打造日志诊断实验室
前言
日志是开发者在调试阶段使用最频繁的工具,没有之一。无论是排查线上故障、追踪调用链路,还是验证业务流程,都离不开日志系统。然而在鸿蒙应用开发中,很多开发者对 HiLog 的认识停留在"打印一条日志看看"——对 domain 的分配、tag 的命名规范、isLoggable 检测、日志级别选择等细节缺乏系统性理解。
HarmonyOS NEXT 提供了 @ohos.hilog 模块,它不仅提供了 debug/info/warn/error/fatal 五级日志输出,还提供了 isLoggable 检测能力,让你在调用日志之前就能判断该条日志是否会被输出,避免无效的字符串格式化开销。本文用一个可交互的"HiLog 日志诊断实验室",把 HiLog 的核心用法讲透。
全文含完整可运行代码,适合需要系统化管理应用日志的中级开发者。
一、HiLog 概述与架构
1.1 什么是 HiLog
HiLog 是 HarmonyOS 的系统级日志框架,位于 @kit.PerformanceAnalysisKit。它和 Android 的 Logcat 类似,但设计上更强调"领域隔离"和"按标签过滤"。
HiLog 的三要素:
- Domain(域):一个 16 位十六进制整数(0x0 ~ 0xFFFF),用于标识日志所属的业务模块。系统域(如 0x0000 ~ 0x00FF)由华为框架使用,应用应使用 0x0100 ~ 0xFFFF 之间的自定义值。
- Tag(标签):不超过 32 字节的字符串,标识日志的具体来源(如类名、模块名)。
- Level(级别):DEBUG < INFO < WARN < ERROR < FATAL,共五级,决定了日志的严重程度和是否被输出。
这三要素组合在一起,决定了"这条日志从哪里来、有多重要、能不能被看到"。
1.2 与其他日志系统的对比
| 维度 | HiLog | Android Logcat | iOS NSLog/os_log |
|---|---|---|---|
| 领域隔离 | domain (0x0~0xFFFF) | 无标准域概念 | subsystem + category |
| 级别过滤 | 五级 + isLoggable 预检查 | 七级 (V/D/I/W/E/F/S) | 四级 (Default/Info/Debug/Error/Fault) |
| 日志隐私 | %{public}s / %{private}s 强制标注 | 无 | 无 |
| 命令行工具 | hilog 命令 | logcat 命令 | log 命令 |
HiLog 最独特的设计是强制隐私标注——format 字符串中的参数必须用 %{public} 或 %{private} 修饰,否则编译时不会报错但运行时日志会被隐藏。这是 HarmonyOS 在隐私保护方面的重要设计。
二、核心 API 详解
2.1 导入方式
import hilog from '@ohos.hilog';
注意:这是 default import,不是从 @kit.ArkTS 的命名导入。HiLog 属于 @kit.PerformanceAnalysisKit,但直接 import 自 @ohos.hilog 即可。
2.2 五级日志输出
hilog.debug(domain, tag, format, ...args); // 调试信息
hilog.info(domain, tag, format, ...args); // 一般信息
hilog.warn(domain, tag, format, ...args); // 警告
hilog.error(domain, tag, format, ...args); // 错误
hilog.fatal(domain, tag, format, ...args); // 致命错误(FATAL会导致应用退出)
每个函数的参数签名完全相同:
domain: number— 十六进制域值(0x0 ~ 0xFFFF),超出范围日志不会被打印tag: string— 日志标签,最长 32 字节,超出部分会被截断format: string— 格式化字符串,支持%{public}s、%{private}s、%{public}d等占位符...args: any[]— 可变参数,按顺序替换 format 中的占位符
2.3 isLoggable —— 日志预检
const level: hilog.LogLevel = hilog.LogLevel.INFO;
const printable: boolean = hilog.isLoggable(0x0011, 'DemoApp', level);
isLoggable 接受 domain、tag、level 三个参数,返回 boolean,表示"当前系统设置下,这条日志是否会被实际输出"。这是一个纯判断函数,不会产生任何日志输出,性能开销极小。
它的核心价值在于:避免无效的字符串操作。考虑以下场景:
// 不推荐:即使日志不会被输出,JSON.stringify 也会执行
hilog.debug(0x0011, 'Data', '%{public}s', JSON.stringify(largeObject));
// 推荐:先检查再输出
if (hilog.isLoggable(0x0011, 'Data', hilog.LogLevel.DEBUG)) {
hilog.debug(0x0011, 'Data', '%{public}s', JSON.stringify(largeObject));
}
对于频繁调用的调试日志中包含复杂数据序列化的情况,isLoggable 预检可以显著减少性能浪费。
2.4 LogLevel 枚举
enum LogLevel {
DEBUG = 3, // 调试级:详细的开发调试信息
INFO = 4, // 信息级:常规运行信息
WARN = 5, // 警告级:潜在问题
ERROR = 6, // 错误级:可恢复的错误
FATAL = 7 // 致命级:不可恢复,应用将退出
}
注意 LogLevel 的数值从 3(DEBUG)到 7(FATAL),数值越大严重程度越高。默认情况下,Release 版本的最低输出级别是 INFO(4),DEBUG 日志不会被输出——这也是 isLoggable(domain, tag, LogLevel.DEBUG) 在 Release 包中返回 false 的原因。


三、实战:HiLog 日志诊断实验室
3.1 整体设计
实验室页面的功能布局:
- Domain 配置区:Hex 输入框 + 4 个预设快捷按钮(0x0001/0x0011/0x0F00/0xFFFF)
- Tag 配置区:文本输入框 + 5 个预设快捷按钮(DemoApp/Network/Database/UI/Worker)
- isLoggable 检查矩阵:5 级 x 1 行的矩阵,绿色=可通过,灰色=被拦截
- 日志级别选择 + 发送:5 级横向按钮 + 消息输入 + 发送按钮
- 发送历史:带颜色标签的日志条目列表,实时追加
3.2 状态与导入
import { router } from '@kit.ArkUI';
import hilog from '@ohos.hilog';
import { FontSize, Spacing } from '../common/Constants';
interface LogEntry {
domain: string;
tag: string;
level: string;
levelColor: string;
message: string;
}
@Entry
@Component
struct HiLogLabPage {
@State domain: string = '0x0011';
@State tag: string = 'DemoApp';
@State message: string = 'Hello from HiLog lab!';
@State levels: string[] = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'];
@State selectedLevel: number = 0;
@State logHistory: LogEntry[] = [];
@State loggableMatrix: boolean[] = [false, false, false, false, false];
private levelColors: string[] = ['#4A90D9', '#52C41A', '#D4880F', '#FF4D4F', '#8C1D1D'];
}
logHistory 是一个 LogEntry[] 数组,存储每条已发送日志的元信息。因为 HiLog 的输出直接进入系统缓冲区,应用层拿不回来,所以我们在应用内维护自己的"发送历史",用不同颜色区分日志级别。
3.3 Domain 与 Tag 配置
private domainToNum(): number {
const parsed: number = parseInt(this.domain, 16);
if (isNaN(parsed)) {
return 0;
}
return parsed;
}
parseInt(domainStr, 16) 将用户输入的十六进制字符串转为数字。非法输入时返回 0,hilog.debug(0, ...) 不会被打印(0 是无效域),所以不影响系统。
Domain 和 Tag 各自配了预设按钮:
private presetDomains: string[] = ['0x0001', '0x0011', '0x0F00', '0xFFFF'];
private presetTags: string[] = ['DemoApp', 'Network', 'Database', 'UI', 'Worker'];
0x0011 是华为官方示例中常用的应用域;0xFFFF 是最大可用值;0x0001 和 0x0F00 分别代表系统底层域和中间件域。
3.4 isLoggable 矩阵
private checkLoggable(): void {
const d: number = this.domainToNum();
for (let i = 0; i < this.levels.length; i++) {
this.loggableMatrix[i] = hilog.isLoggable(d, this.tag, i as hilog.LogLevel);
}
}
这里的关键技巧:i as hilog.LogLevel 将数字索引直接转为 LogLevel 枚举。因为 DEBUG=3, INFO=4, …, FATAL=7,数组索引 0~4 映射到 Level 3~7。这个类型断言利用了 LogLevel 枚举的数值顺序。
5 个级别的检查结果显示为 5 个色块——绿色 #52C41A 表示可通过,灰色 #D9D9D9 表示被拦截。每修改 Domain 或 Tag 都会实时刷新矩阵。
3.5 发送日志
private sendLog(): void {
const d: number = this.domainToNum();
if (this.selectedLevel === 0) {
hilog.debug(d, this.tag, '%{public}s', this.message);
} else if (this.selectedLevel === 1) {
hilog.info(d, this.tag, '%{public}s', this.message);
} else if (this.selectedLevel === 2) {
hilog.warn(d, this.tag, '%{public}s', this.message);
} else if (this.selectedLevel === 3) {
hilog.error(d, this.tag, '%{public}s', this.message);
} else {
hilog.fatal(d, this.tag, '%{public}s', this.message);
}
// 追加到本地历史
const entry: LogEntry = { domain: this.domain, tag: this.tag,
level: this.levels[this.selectedLevel],
levelColor: this.levelColors[this.selectedLevel],
message: this.message };
this.logHistory = [entry].concat(this.logHistory).slice(0, 50);
this.checkLoggable();
}
注意 ArkTS 严格模式下不能用动态属性名调用函数(如 hilog[levelName](...)),所以需要显式的 if/else 分支。
发送后立即追加到 logHistory 头部(最新的排最前),限制 50 条避免内存溢出。同时触发 checkLoggable() 刷新矩阵——因为某些级别的日志设置可能受运行时状态影响。
3.6 发送历史展示
每条历史记录用色标 + 层级标签 + 元信息 + 内容的形式展示:
Row() {
Column() {
Text(entry.level)
.fontSize(10)
.fontColor(entry.levelColor)
.fontWeight(FontWeight.Bold)
}
.width(48).height(24).borderRadius(4)
.backgroundColor(entry.levelColor + '20') // 20 = 12% alpha
Column() {
Text('[' + entry.domain + '] ' + entry.tag)
.fontSize(11)
.fontColor('#90A4AE')
Text(entry.message)
.fontSize(13)
.fontColor('#263238')
}
.layoutWeight(1)
}
entry.levelColor + '20' 将颜色字符串拼接 '20' 得到约 12% 透明度的同色背景——这是一种在 ArkTS 中无需计算 RGBA 即可实现浅色标签背景的技巧。
四、几个实战要点与坑
4.1 Domain 为 0 时日志不输出
当 domain 参数为 0 时,HiLog 不会打印该日志。如果用户清空了 Domain 输入框或在 parseInt 失败时返回了 0,日志将静默丢失。建议始终用非零的合法 domain 值,并在 domainToNum() 中做校验。
4.2 FATAL 会导致应用退出
hilog.fatal() 输出日志后,系统会终止应用进程。这和 Java 的 System.exit() 类似——所以 FATAL 只在真正不可恢复的场景下使用。在我们的实验室中,点击 FATAL 按钮时要确保这是你预期的行为。
4.3 隐私标注必须使用
HiLog 的 format 字符串中,每个参数都必须用 %{public} 或 %{private} 标注。不标注的参数在 Release 版本中会被替换为 <private>。常见格式:
hilog.info(0x0011, 'Tag', 'user: %{public}s, age: %{public}d', name, age);
hilog.info(0x0011, 'Tag', 'token: %{private}s', token); // 隐私字段用 private
%{public}s 表示该字符串参数可以在 Release 日志中暴露;%{private}s 表示该参数只应在 Debug 日志中可见,Release 中会被 <private> 替换。
4.4 isLoggable 的性能价值
在一个高频日志点(如列表滚动、手势跟踪)中,即使日志不输出,hilog.debug() 调用本身也会执行参数求值和字符串格式化。对于复杂参数(如 JSON.stringify(someObj)),这种开销不可忽略。
// 反例:每秒 60 帧的滚动回调中,JSON.stringify 一直在执行
onScroll((offset) => {
hilog.debug(0x0011, 'Scroll', 'data: %{public}s', JSON.stringify(state));
});
// 正例:先检查,避免无效序列化
onScroll((offset) => {
if (hilog.isLoggable(0x0011, 'Scroll', hilog.LogLevel.DEBUG)) {
hilog.debug(0x0011, 'Scroll', 'data: %{public}s', JSON.stringify(state));
}
});
isLoggable 本质上是读一个标志位,几乎没有性能开销。
4.5 LogLevel 不是从 0 开始
LogLevel.DEBUG = 3,不是 0 也不是 1。如果错误地以为 0 = DEBUG, 1 = INFO, ... 并在代码中硬编码数字,会导致日志级别判断错误。
五、Domain 分配最佳实践
在一个中大型应用中,如何分配 domain 值直接影响到日志检索效率。推荐的分层方案:
| Domain 范围 | 分配建议 | 示例 |
|---|---|---|
| 0x0000 ~ 0x00FF | 系统保留,勿用 | — |
| 0x0100 ~ 0x0FFF | 应用级公共模块 | 网络(0x0100)、数据库(0x0101)、缓存(0x0102) |
| 0x1000 ~ 0x1FFF | 业务模块 A | 用户(0x1000)、订单(0x1001)、支付(0x1002) |
| 0x2000 ~ 0x2FFF | 业务模块 B | 商品(0x2000)、库存(0x2001)、物流(0x2002) |
| 0xF000 ~ 0xFFFF | 开发调试专用 | 临时调试(0xFF00)、原型验证(0xFFF0) |
每个模块分配唯一的 domain 后,使用 hilog 命令行工具可以按 domain 精确过滤:
hilog -D 0x0100 # 只看网络模块日志
hilog -D 0x1000 -I DEBUG # 只看用户模块的DEBUG级别
hilog -D 0x0100 -T "Network" # 只看网络模块 + Network标签
5.1 Tag 命名规范
Tag 建议使用模块名或类名,遵循以下约定:
- 长度控制:不超过 20 字节(留 12 字节缓冲),英文用 PascalCase,中文避免
- 保持稳定:Tag 是日志过滤的主要维度之一,频繁改名会破坏已有的过滤配置
- 避免敏感信息:Tag 中不要包含用户 ID、Token 等隐私数据
六、小结
本文以"HiLog 日志诊断实验室"为载体,系统讲解了 HarmonyOS NEXT 的 @ohos.hilog:
- 核心 API:debug/info/warn/error/fatal 五级日志输出 + isLoggable 预检 + LogLevel 枚举
- 三要素:domain(业务隔离)、tag(来源定位)、level(严重程度),三者组合构成日志的唯一标识
- isLoggable 的价值:避免无效的字符串格式化开销,在高频日志场景中尤为关键
- 隐私标注:
%{public}vs%{private}的强制选择,体现了 HarmonyOS 的隐私设计哲学 - Domain 分配方案:从 0x0100 到 0xFFFF 的分层规划,配合 hilog 命令行工具实现精准过滤
- 工程注意事项:Domain 不能为 0、FATAL 会终止进程、LogLevel 从 3 开始
日志系统是开发者的"眼睛"。用好 HiLog,意味着在问题排查时能快速定位、在性能优化时能精确度量、在线上监控时能有效告警。它不仅是一个 print 的替代品,更是一个需要用心规划的基础设施。
更多推荐


所有评论(0)