kratos通过helper封装日志调用,统一由logger实现格式化、valuer注入全局字段、filter脱敏重写,业务代码仅需helper.info("msg", key, val);logger.log要求keyvals长度为偶数,否则panic。

用 Helper 封装日志调用,屏蔽底层格式差异
Kratos 不靠硬编码固定日志格式,而是把格式控制权交给 Logger 实现,业务代码只通过 Helper 打日志。这样哪怕你换掉底层日志库(比如从 zap 换成 logrus),只要新 Logger 实现了统一接口,Helper.Info("user login", "uid", 123) 这种写法完全不用改。
关键点在于:Helper 把 keyvals 平铺数组("msg", "user login", "uid", 123)传给 Logger.Log(),而格式化、时间戳、traceID 注入这些事,全由 Logger 的具体实现或它挂载的 Valuer/Filter 完成。
通过 Valuer 绑定全局字段,避免重复写 context
你不需要每次打日志都手动塞 "trace_id", traceID, "instance_id", os.Getenv("HOSTNAME") —— 这些属于“固定上下文”,应该用 Valuer 一次性注册。
-
Valuer是函数类型,返回任意值,比如func() interface{} { return middleware.GetTraceID(ctx) } - 注册后,所有经
Helper发出的日志都会自动带上该字段,无需业务层感知 - 常见绑定项:traceID、spanID、服务名、实例 ID、部署环境(dev/staging/prod)
用 Filter 做日志脱敏和字段重写,不污染业务逻辑
敏感字段(如手机号、token、密码)不能靠业务代码一个个判断过滤,否则漏掉一个就可能出事。Kratos 的 Filter 接口在日志真正输出前介入,可以安全地做:
- 匹配 key 名(如
"phone"、"auth_token")并替换为"***" - 删除整条日志中含特定 pattern 的字段(如正则匹配
^secret_.*$) - 把
"error"字段内容转成小写、截断或加哈希标识,便于日志平台聚合
注意:Filter 是链式执行的,多个 Filter 可以组合使用,但顺序会影响最终效果。
Logger 实现必须保证 keyvals 是偶数长度,否则 panic
这是最容易踩的坑——Logger.Log() 接收的 keyvals 必须是偶数长度切片,否则直接 panic。比如 logger.Log(LevelInfo, "msg", "ok", "uid") 少了一个 value,运行时就会崩。
原因在于 Kratos 默认按两两配对解析:keyvals[0] 是 key,keyvals[1] 是 value,依此类推。如果你动态拼 keyvals,务必检查 len % 2 == 0。
建议做法:
- 所有业务日志走 Helper,它内部已做校验
- 自定义 Logger 实现时,在 Log() 方法开头加 if len(keyvals)%2 != 0 { return errors.New("keyvals length must be even") }
日志格式统一真正的难点不在“怎么写”,而在“谁负责写”——Kratos 把格式决策权彻底交给 infra 层(Logger + Valuer + Filter),业务代码只管表达意图。一旦团队约定好日志字段命名规范(比如统一用 user_id 而不是 uid 或 userID),后续加字段、换格式、上脱敏规则,都不需要动一行业务代码。











