跳转到内容

Kratos Config 与 Log

Kratos 的 config 和 log 都采用“核心接口 + 可替换适配器”的方式。配置把 source、reader、value 和 observer 分开;日志基于标准库 slog,通过 decorator 注入 context 属性和过滤器。

先给答案:Kratos 的 config 和 log 都采用“核心接口 + 可替换适配器”的方式

Section titled “先给答案:Kratos 的 config 和 log 都采用“核心接口 + 可替换适配器”的方式”

Kratos 的 config 和 log 都采用“核心接口 + 可替换适配器”的方式。配置把 source、reader、value 和 observer 分开;日志基于标准库 slog,通过 decorator 注入 context 属性和过滤器。 正文沿“Config 数据流 -> Log 组装 -> 设计取舍”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。

主要失效边界集中在“watcher 短暂失败、配置类型变化、文件 rename”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

Source.Load -> Reader.Merge -> Reader.Resolve -> Value cache
| |
Source.Watch -> watcher.Next -> Merge -> Observer(key, value)

config.Config 接口和内部状态位于 config/config.go:25-40。Load 首先加载所有 source,再创建 watcher 并启动后台 watch::92-117。watch 线程合并并 resolve 新值,再比较 cached value,变化后触发 observer::58-89。

文件 source 只负责读取文件或目录:config/file/file.go:18-79;fsnotify watcher 负责 rename、重新读取和关闭:config/file/watcher.go:24-70。

log.NewHandler 默认 stderr、文本格式、Info 级别和 AttrsFromContext extractor:log/builder.go:79-95。handler 可以切换 JSON、级别、source、替换属性和 filter::47-76。ContextWithAttrs 把 attrs 存入 context,context handler 在 Handle 时追加到 record:log/context.go:10-26、:66-81。

替代方案:配置变更时直接替换全局配置对象,日志直接使用全局字段。 问题:请求中的旧引用不稳定,测试和动态更新难以控制。 设计:Value 提供可观察的缓存单元,slog handler 通过 context 在单次调用范围内传播结构化属性。

场景 风险 处理
watcher 短暂失败 配置线程退出 非 canceled 错误重试并记录日志
配置类型变化 observer 不触发 比较类型后再更新 Value
文件 rename watcher 丢失 重新 Add 新路径
handler 不带 context 请求字段缺失 使用 NewLogger/NewHandler 的 extractor

动态配置系统必须区分“原始 source 变化”和“解析后的业务值变化”,只有后者才应该通知业务观察者。

面试锚点

  • Kratos 配置 watch 为什么还要经过 Merge 和 Resolve?
  • Value cache 与 observer 如何避免每次读取都重新解析?
  • slog context handler 为什么需要 Clone record?