3、日志标签与领域:创建自定义日志标签、领域标识符(Domain)的作用与配置、多模块日志隔离

日志这东西,说白了就是给系统装个「黑匣子」。但黑匣子里的数据如果乱七八糟,那还不如不记。我刚开始做鸿蒙开发时,就吃过这个亏——日志打了一堆,真要查问题时,满屏都是杂音,根本找不到关键信息。

后来我慢慢摸索出套路:日志标签领域标识符,就是给每条日志贴上的「身份证」和「户口本」。今天咱们就聊聊这两个东西怎么用,以及怎么实现多模块日志隔离。

3.1 日志标签:给每条日志贴个标签

日志标签(Tag)是啥?就是一条日志的「名字」。比如你写了个网络模块,所有网络相关的日志都打上 NetModule 这个标签。这样过滤时,一眼就能看到网络模块在干什么。

在鸿蒙系统里,创建自定义日志标签很简单。我一般这么写:

import { hilog } from '@kit.PerformanceAnalysisKit';

// 定义标签常量
const TAG = 'MyApp_Network';

// 打印日志
hilog.info(0x0001, TAG, '网络连接成功,耗时 %d ms', 120);

嗯,这里要注意:标签长度最好控制在 32 个字符以内。太长了会被截断,反而看不全。我个人习惯用「模块名_子模块」的格式,比如 Payment_CheckoutUser_Login,这样层次清晰。

小技巧:标签命名建议统一风格。我团队里定了个规矩——全大写 + 下划线分隔。这样在日志里一眼就能认出是自定义标签,不会和系统日志混淆。

3.2 领域标识符(Domain):给日志上个「户口」

标签是「名字」,那领域标识符(Domain)就是「户口所在地」。鸿蒙系统里,Domain 是一个 32 位的整数,用来标识日志属于哪个子系统或功能领域。

为什么要搞个 Domain?你想想看,一个大型 App 可能有几十个模块,光靠标签过滤,还是会有重名风险。Domain 就像给每个模块划了块「自留地」,互不干扰。

配置 Domain 的规则是这样的:

Domain 范围 用途 示例
0x0000 - 0x00FF 系统保留 系统服务、内核日志
0x0100 - 0xFFFF 应用自定义 业务模块日志
0x10000 以上 扩展预留 第三方库、插件

我在项目中遇到过一个问题:两个团队用了相同的 Domain 值,结果日志混在一起,排查了整整两天。后来我们统一在项目文档里登记了每个模块的 Domain 范围,才彻底解决。

配置代码示例:

// 定义领域标识符
const DOMAIN_NETWORK = 0x0101;  // 网络模块
const DOMAIN_PAYMENT = 0x0102;  // 支付模块
const DOMAIN_USER    = 0x0103;  // 用户模块

// 使用领域标识符打印日志
hilog.info(DOMAIN_NETWORK, 'NetModule', 'DNS解析完成');
hilog.info(DOMAIN_PAYMENT, 'PayModule', '订单创建成功');
注意:Domain 值不要用 0x0000,那是系统保留的。我曾经看到有人偷懒直接传 0,结果日志被系统拦截了,查了半天才发现是 Domain 不对。

3.3 多模块日志隔离:让每个模块「自扫门前雪」

多模块日志隔离,说白了就是让 A 模块的日志不要跑到 B 模块的日志里去。鸿蒙系统提供了几种方式来实现:

3.3.1 基于 Domain 的隔离

这是最基础的方式。每个模块分配唯一的 Domain,日志自然就分开了。过滤时用 hilog -d 0x0101 就能只看网络模块的日志。

3.3.2 基于标签前缀的隔离

如果 Domain 不够用,可以用标签前缀做二次过滤。比如:

// 网络模块
hilog.info(DOMAIN_NETWORK, 'Net_HTTP', '请求发送');
hilog.info(DOMAIN_NETWORK, 'Net_DNS', '域名解析');

// 支付模块
hilog.info(DOMAIN_PAYMENT, 'Pay_Order', '订单创建');
hilog.info(DOMAIN_PAYMENT, 'Pay_Refund', '退款处理');

这样即使 Domain 相同,也能通过标签前缀快速定位子模块。

3.3.3 日志级别隔离

不同模块可以设置不同的日志级别。比如网络模块调试时用 DEBUG,上线后改成 INFO;支付模块因为涉及资金,始终保留 WARN 以上级别。

// 网络模块:调试时打开
if (isDebug) {
    hilog.debug(DOMAIN_NETWORK, 'NetModule', '当前网络状态: %s', status);
}

// 支付模块:始终记录错误
hilog.error(DOMAIN_PAYMENT, 'PayModule', '支付失败,错误码: %d', errCode);
核心思路:日志隔离不是「一刀切」,而是「各取所需」。调试时看细节,线上只看关键。我一般会在每个模块的初始化函数里统一配置日志级别,这样改起来方便。

3.4 实战:一个多模块日志配置示例

说了这么多,咱们来个完整的例子。假设你有个电商 App,分网络、支付、用户三个模块。我会这样组织日志:

// 日志配置中心
const LogConfig = {
    network: { domain: 0x0101, tag: 'Net', level: 'DEBUG' },
    payment: { domain: 0x0102, tag: 'Pay', level: 'INFO' },
    user:    { domain: 0x0103, tag: 'User', level: 'WARN' },
};

// 封装日志工具
function log(module, level, message, ...args) {
    const config = LogConfig[module];
    if (!config) return;
    
    // 级别过滤
    const levels = ['DEBUG', 'INFO', 'WARN', 'ERROR'];
    if (levels.indexOf(level) < levels.indexOf(config.level)) {
        return;
    }
    
    hilog[level.toLowerCase()](config.domain, config.tag, message, ...args);
}

// 使用
log('network', 'DEBUG', '连接耗时 %d ms', 50);  // 调试时输出
log('payment', 'ERROR', '扣款失败');              // 始终输出

这样做的好处是:改日志级别只需改一处配置,不用满世界找 hilog.info 去改。我曾经在一个大项目里用这种方式,上线前把网络模块从 DEBUG 切到 INFO,一行代码搞定。

3.5 知识体系总览

下面这张图,是我梳理的本章核心逻辑。你看一眼就能明白标签、Domain、隔离之间的关系:

日志标签与领域:知识体系 日志标签 (Tag) 模块名_子模块 ≤32字符 全大写+下划线 领域标识符 (Domain) 32位整数 0x0100+ 应用自定义 避免重复 多模块日志隔离 Domain隔离 标签前缀隔离 日志级别隔离 核心原则 标签管「谁」→ Domain管「哪」→ 隔离管「怎么分」 推荐实践流程 ① 分配Domain → ② 定义标签规范 → ③ 配置日志级别 → ④ 封装日志工具 (每个模块独立配置,统一管理)

说白了,日志标签和领域就是给系统装上一套「户籍管理系统」。标签是名字,Domain 是地址,隔离就是分小区管理。搞清楚了这三者的关系,你的日志就不再是噪音,而是真正的「黑匣子」——关键时刻能救命那种。

我的习惯:每个新项目启动时,第一件事就是拉个文档,把模块名、Domain、标签前缀、日志级别都列清楚。磨刀不误砍柴工,后面排查问题能省 80% 的时间。

公众号:蓝海资料掘金营,微信deep3321