日志格式化技巧:参数占位符%s、%d使用、打印对象与数组、格式化输出对齐

日志格式化,说白了就是让日志说人话。

我刚开始做鸿蒙开发时,也踩过不少坑。那时候打印日志全靠拼字符串,代码里全是 "用户ID:" + userId + ",姓名:" + name 这种写法。后来发现,日志一多,眼睛都看花了。嗯,格式化才是正解。

一、参数占位符:%s 和 %d 的正确打开方式

鸿蒙的 HiLog 支持两种最常用的占位符:%s%d。前者管字符串,后者管整数。用法很简单,但细节决定成败。

// 基础用法
HiLog.info(LABEL, "用户登录:账号 = %s,尝试次数 = %d", account, retryCount);

// 多个占位符,按顺序对应
HiLog.info(LABEL, "请求耗时:%d ms,状态码 = %d,描述 = %s", costTime, statusCode, description);

我个人习惯把占位符当成「填空游戏」。你挖几个坑,后面就填几个参数。顺序不能乱,类型要对上。

⚠️ 我曾经踩过的坑:

%d 打印 long 类型变量,结果输出了一串乱码。后来才发现,long 类型要用 %ld。鸿蒙的 HiLog 对类型要求比较严格,别偷懒。

💡 小技巧:

如果你不确定某个变量该用哪个占位符,先试试 %s。它会调用对象的 toString() 方法,至少不会崩溃。当然,性能上会差一点点。

二、打印对象与数组:别让日志变成天书

你想想看,如果日志里全是 com.example.User@1a2b3c 这种地址,调试起来得多痛苦?

打印对象,核心思路是重写 toString() 方法。鸿蒙的 Java 层和 ArkTS 层都支持。

// Java 层:重写 toString()
public class User {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

// 打印时直接传对象
HiLog.info(LABEL, "当前用户信息:%s", user);
// ArkTS 层:使用 JSON.stringify()
let userInfo = {
    name: "张三",
    age: 28,
    roles: ["admin", "editor"]
};
HiLog.info(LABEL, "用户数据:%s", JSON.stringify(userInfo));

打印数组也类似。我建议用 Arrays.toString() 或者 JSON.stringify(),别自己写循环拼接。

// Java 数组打印
int[] scores = {85, 92, 78, 90};
HiLog.info(LABEL, "成绩列表:%s", Arrays.toString(scores));

// 多维数组用 Arrays.deepToString()
int[][] matrix = {{1,2}, {3,4}};
HiLog.info(LABEL, "矩阵数据:%s", Arrays.deepToString(matrix));
🔑 核心原则:

日志里出现的对象,一定要能看出「这是什么」。如果 toString() 返回的是无意义的内容,那这个日志等于白写。

三、格式化输出对齐:让日志整整齐齐

日志一多,最怕什么?最怕对不齐。你看一眼日志,左边歪歪扭扭,右边参差不齐,找关键信息全靠肉眼扫描。太累了。

格式化对齐,说白了就是给每个字段分配固定的宽度。鸿蒙的 HiLog 本身不支持 printf 那种 %-10s 的写法,但我们可以自己动手。

// 手动对齐:固定宽度
String formatLog = String.format("%-20s | %-10s | %-8s", "模块名称", "状态码", "耗时(ms)");
HiLog.info(LABEL, formatLog);

// 实际数据对齐
HiLog.info(LABEL, String.format("%-20s | %-10d | %-8d", "登录模块", 200, 35));
HiLog.info(LABEL, String.format("%-20s | %-10d | %-8d", "数据加载", 404, 1200));
HiLog.info(LABEL, String.format("%-20s | %-10d | %-8d", "图片渲染", 200, 89));

输出效果:

模块名称              | 状态码      | 耗时(ms)
登录模块              | 200         | 35
数据加载              | 404         | 1200
图片渲染              | 200         | 89

你看,整整齐齐的。一眼就能看出哪行是异常,哪行耗时高。

💡 我的习惯:

我会在日志开头加一个表头,然后每条数据对齐。这样日志文件打开,扫一眼就能定位问题。尤其是排查性能问题时,耗时列对齐了,谁高谁低一目了然。

四、知识体系总览

下面这张图,是我自己总结的日志格式化核心逻辑。你可以把它当成一个检查清单。

日志格式化核心知识体系 参数占位符 %s 字符串 %d 整数 %ld 长整数 对象与数组 重写 toString() JSON.stringify() Arrays.toString() 格式化对齐 String.format() %-Ns 左对齐 表头 + 数据行 核心目标:让日志可读、可查、可分析 类型匹配 → 内容清晰 → 格式整齐

五、避坑指南:我踩过的那些坑

做日志格式化,有几个坑特别容易踩。我一个个说。

  1. 占位符和参数数量不匹配 —— 少传一个参数,日志直接崩。多传一个参数,后面的被忽略。我建议每次写完都数一遍。
  2. 对象没重写 toString() —— 打印出来全是 类名@哈希码,等于没打。尤其是自定义的实体类,一定要重写。
  3. 数组直接传引用 —— HiLog.info(LABEL, "数组:%s", array) 这种写法,打印出来的是地址。要用 Arrays.toString() 包一层。
  4. 对齐时中文和英文混排 —— 中文占两个字符宽度,英文占一个。用 %-20s 对齐时,中文会多占位置,导致对不齐。我的解决办法是:统一用英文或数字做对齐,中文单独处理。
⚠️ 我曾经踩过的大坑:

有一次线上排查问题,日志里打印了一个大对象,结果 toString() 里循环引用了,直接栈溢出。从那以后,我所有对象的 toString() 都只打印关键字段,绝不打印关联对象。

六、总结

日志格式化,说白了就三件事:

  • 占位符用对,类型匹配
  • 对象和数组要能看懂
  • 输出要对齐,一眼能定位

做到这三点,你的日志就不再是「天书」,而是真正的调试利器。


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