DEBUG、INFO、WARN、ERROR、FATAL 应该怎么分?HiLog 日志级别实战【鸿蒙心迹】

你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌 关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀
全文目录:
前言
写日志这件事,很多开发者要么全堆 info,要么遇到异常一律 error,久而久之日志就成了噪音。翻 Logcat 的时候,满屏 ERROR,但大多数只是一个接口返回了空值;满屏 INFO,但其中混着几条真正需要关注的状态变化。
HiLog 提供了五个日志级别,每一个都有官方明确的使用场景定义。这篇文章就围绕这五个级别,结合一个最小示例,说清楚它们之间的边界在哪里。
一、HiLog 是什么,先简单说一下边界
HiLog 是 HarmonyOS 提供给应用层使用的日志打印系统,对应 @ohos.hilog 模块。在 ArkTS 工程中,直接 import hilog from '@ohos.hilog' 即可使用,无需额外权限配置。
这里要先区分两个常见误区:
console.log在 HarmonyOS 应用开发中也可以用,但它是 ArkTS 运行时提供的基础输出,不具备日志级别过滤、域标签管理等能力,生产场景不推荐依赖它来管理日志。- HiLog 对应的是 HarmonyOS 官方日志系统,可以通过 DevEco Studio 的 Log 面板按 Level、Tag 过滤。
HiLog 在 ArkTS 侧的 API 基本信息:
| 方法 | 对应级别 | API 起始支持版本 |
|---|---|---|
hilog.debug() | DEBUG | API 7 |
hilog.info() | INFO | API 7 |
hilog.warn() | WARN | API 7 |
hilog.error() | ERROR | API 7 |
hilog.fatal() | FATAL | API 7 |
hilog.isLoggable() | 级别过滤判断 | API 7 |
这五个方法从 API 7 开始支持,HarmonyOS 5.x(API Level 12+)及当前主流版本均可使用,无设备限制,适用于 Phone、Tablet、2in1 等全形态。
二、五个级别的官方定义
HiLog 官方文档对五个级别的定义如下,这里直接引用官方表述,不做二次演绎:
DEBUG
详细的流程记录,通过该级别的日志可以更详细地分析业务流程和定位分析问题。该级别日志在正式发布版本中一般不会输出,只有在调试版本或特意打开调试日志功能时才会生效。
INFO
用于记录业务关键流程节点,以及异常情况下的关键信息,这类信息应该对排查问题有帮助。
WARN
用于记录较为严重的不预期情况,但是此时运行环境依然正常。
ERROR
应用发生了错误,该错误需要被关注和修复,该错误的发生会影响用户使用或功能运行。
FATAL
重大致命异常,即将发生严重的程序错误。
这五段官方定义里,有几个词值得单独注意:
- DEBUG 的定位是"详细流程",它明确说明正式发布版本一般不会输出。这意味着 debug 级别的日志在 release 包里默认可能被过滤,不适合用来记录任何需要在生产环境追踪的信息。
- WARN 的关键词是"运行环境依然正常"。也就是说,warn 不代表出错,只代表出现了不预期的情况,业务还在跑。
- ERROR 的关键是"需要被关注和修复",而且"影响用户使用或功能运行"。如果某个异常根本不影响用户感知,就不应该是 error。
- FATAL 是"即将发生严重的程序错误",这个级别通常意味着应用可能即将崩溃或进入不可恢复状态。
三、基本调用方式
HiLog 的调用格式是固定的:
hilog.级别(domain, tag, format, ...args)
| 参数 | 类型 | 说明 |
|---|---|---|
| domain | number | 日志所属业务域,十六进制,范围 0x0~0xFFFF |
| tag | string | 用于标识调用者,最长 31 字节 |
| format | string | 格式化字符串,支持 %{public}s、%{private}s 等隐私标识 |
| args | any[] | 对应格式化参数 |
关于 domain:这是一个用来标识日志所属子系统或模块的数字,应用开发中通常自定义一个固定值,例如 0x0001,用来区分不同业务模块的日志。
关于隐私标识:格式化参数中,%{public}s 表示公开输出,%{private}s 表示隐私数据(在日志中会被替换为 <private>)。如果什么都不标注,默认是 %{private}s,也就是默认不暴露参数内容。
四、最小实践:五个级别各写一条
下面用一个最小示例,围绕一个模拟的"用户订单查询"流程,演示五个级别各自适合记录什么。
这段代码的目标是:用同一个业务流程,展示五个日志级别的合理使用位置,而不是逐一罗列 API 用法。
import hilog from '@ohos.hilog';
const DOMAIN = 0x0001;
const TAG = 'OrderService';
function queryOrder(userId: string, orderId: string): void {
// DEBUG:记录详细的入参和内部流程,用于调试阶段追踪执行路径
hilog.debug(DOMAIN, TAG, 'queryOrder called, userId=%{public}s, orderId=%{public}s', userId, orderId);
if (!userId || !orderId) {
// ERROR:参数缺失会直接导致功能无法运行,需要修复
hilog.error(DOMAIN, TAG, 'queryOrder failed: userId or orderId is empty');
return;
}
const cachedResult = getFromCache(orderId);
if (!cachedResult) {
// WARN:缓存未命中不是错误,但属于"不预期的情况",业务依然能继续
hilog.warn(DOMAIN, TAG, 'Cache miss for orderId=%{public}s, fallback to network', orderId);
}
// INFO:记录关键业务节点,表示正式发起了网络请求
hilog.info(DOMAIN, TAG, 'Requesting order data from server, orderId=%{public}s', orderId);
const response = fetchOrderFromServer(orderId);
if (response === null) {
// FATAL:服务端连接完全失败,可能意味着整个业务链路已经断裂
hilog.fatal(DOMAIN, TAG, 'Server response is null, network or server may be unavailable');
}
}
function getFromCache(orderId: string): object | null {
// 模拟缓存查询,这里直接返回 null 模拟未命中
return null;
}
function fetchOrderFromServer(orderId: string): object | null {
// 模拟网络请求,这里返回 null 模拟失败
return null;
}
真正需要关注的几个地方:
debug用在了函数入口,记录入参。这类信息调试时非常有用,但在 release 包里不需要输出,正好对应 DEBUG 级别的定义。warn用在了缓存未命中。缓存未命中是预期内可能发生的情况,业务还在走,用error就过重了。info用在了真正发起网络请求的时刻。这是业务关键节点,排查问题时"是否发起了请求"是第一个要确认的问题。error用在了参数为空导致直接return的情况。这类问题需要开发者介入修复。fatal用在了服务端完全不可用、整个业务链路断裂的情况。这里是否用fatal可以根据实际场景评估,核心判断标准是"是否意味着应用即将进入不可恢复状态"。
五、几个容易理解偏差的地方
1. 所有 try-catch 里的 catch 都用 error?
这是最常见的误用。catch 住的异常不一定都是 error 级别。
例如,某个图片解码失败,但应用会自动显示占位图,用户感知不到任何问题——这种情况用 warn 更合适。只有当异常会影响用户正常使用某个功能,才应该上升到 error。
2. debug 是"我在调试,所以用 debug"?
不是。debug 是一个日志级别,代表"这条日志在 release 包里不需要输出",而不是"我现在正在调试"。如果某条日志在生产环境也需要可见,就不应该用 debug。
3. 同一条日志能不能先 info 再 error?
不应该。每条日志只对应一个级别,级别应该由"这条信息在运行时代表的含义"决定,而不是由"写代码的人当时的心情"决定。
4. format 中的参数默认是不可见的
前面提到,参数默认是 %{private}s,也就是在日志中会被替换成 <private> 输出。如果在调试时发现参数没有输出,记得检查是否加了 %{public}s。这一点在刚开始写 HiLog 时很容易被忽略。
5. isLoggable 的作用
HiLog 提供了 hilog.isLoggable(domain, tag, level) 方法,可以在打印前判断当前日志级别是否可输出,避免构造复杂的日志字符串产生不必要的性能开销。在日志内容构造本身有一定代价时,建议先用这个方法判断一下。
if (hilog.isLoggable(DOMAIN, TAG, hilog.LogLevel.DEBUG)) {
const detail = buildExpensiveDebugInfo(); // 只在 debug 可输出时才构造
hilog.debug(DOMAIN, TAG, 'Detail: %{public}s', detail);
}
六、容易踩坑的地方
domain 范围越界
domain 的合法范围是 0x0~0xFFFF,如果传入超出范围的值,按照官方接口约束,行为是未定义的。建议统一在一个常量文件里定义好各个模块的 domain 值,避免散落在各处。
tag 长度超限
tag 最长 31 字节。如果用了中文 tag,注意 UTF-8 编码下中文字符占 3 个字节,31 字节实际能容纳的中文字符并不多。
format 字符串中使用 %d、%f 等格式符
HiLog 支持标准的 C 风格格式符,例如 %d(整数)、%f(浮点数)、%s(字符串)。注意格式符和实际参数类型要匹配,类型不一致可能导致输出异常。
不要在 debug 里记录需要在生产排查的信息
重申一次:debug 日志在 release 版本中默认不输出。如果某条日志在出现生产问题时必须能看到,就不能用 debug 级别。
七、排查日志级别混乱的思路
如果项目里日志用得比较乱,可以按下面顺序梳理:
- 先看 error 和 fatal 是不是真的需要关注。把所有 error 过一遍,问一个问题:这个 error 发生时,用户感知到了什么?如果什么都没发生,降到 warn 或 info。
- 再看 info 是不是太多。info 应该是"关键节点",不是"每一步都记录"。如果每个函数入口都有 info,考虑把纯流程追踪的改成 debug。
- 检查 debug 里是不是有不该在生产消失的信息。如果有,及时升级级别。
- 检查 warn 是不是被当成了 info 用。warn 代表"出现了不预期的情况",如果只是记录正常流程中的一个分支,用 info 即可。
- 检查 fatal 的使用频率。fatal 应该极少出现,如果频繁出现,说明要么使用过重,要么系统确实有严重问题需要处理。
开发经验总结
- 五个级别的核心区分标准是:这条日志代表的运行时含义,而不是代码位置或个人习惯。
debug的定位是调试辅助,release 版本默认不输出,不适合记录生产环境需要的信息。warn不是轻量版 error,它代表"不预期但不影响运行",两者有明确的语义区别。- 不要因为某个地方写了 try-catch 就自动打 error,影响程度才是决定级别的标准。
- 注意 format 参数的隐私标识,默认不公开,调试时没有输出要先检查这里。
isLoggable可以避免在日志不可见时构造无意义的字符串,在性能敏感路径上值得加上。
如果你的项目已经积累了一段时间的日志代码,可以尝试按模块统计一下各级别的比例——如果 error 和 info 的数量远远多于 warn,通常是日志级别规划出了问题,值得重新梳理一遍。
❤️ 如果本文帮到了你…
- 请点个赞,让我知道你还在坚持阅读技术长文!
- 请收藏本文,因为你以后一定还会用上!
- 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
更多推荐



所有评论(0)