slog.with 不自动关联请求上下文,必须显式提取 header 中 trace_id 并用 slog.with("trace_id", id) 封装;需链式调用如 .info() 才输出,避免存入 context、慎用嵌套过深 group。

slog.With 本身不自动关联请求上下文,必须显式提取、封装、传递——漏一次,trace_id 就断链。
HTTP 中间件里怎么安全提取并注入 trace_id
Go 的 context.Context 不跨进程,HTTP 请求进来时,X-Trace-ID 或 X-Correlation-ID 只在 header 里,不在原生 context 中。你得手动从 request header 提取,再塞进新 context 或直接用于构建 logger。
- 入口中间件中用
r.Header.Get("X-Trace-ID")获取,若为空可生成一个(如用uuid.NewString()) - 别把子 logger 存进
context.WithValue—— 并发下易覆盖、难调试、违反 slog 设计意图 - 推荐方式:
reqLogger := slog.With("trace_id", traceID),然后作为参数传给 handler 或 service 层 - 高频请求下可复用固定字段 logger,例如
baseLogger := slog.With("service", "user-api", "env", "prod"),再叠加 trace_id
slog.With 后字段不出现?常见三类原因
日志里看不到 trace_id 或其他字段,不是 slog 坏了,而是调用姿势或值类型出了问题。
-
slog.With("trace_id", cid)单独一行不会输出任何日志——它只返回新 logger,必须链式调用,如slog.With("trace_id", cid).Info("request started") - 值是 struct、*http.Request、map 等非基础类型时,默认转成
{}或空字符串;应拆解为slog.String("path", r.URL.Path)等明确字段 - 用了自定义
slog.Handler却没正确遍历Record.Attrs()迭代器,或忽略attr.Value.Resolve(),导致嵌套 group 或复杂值丢失
WithGroup 和 With 混用会导致日志平台解析失败
字段命名和嵌套结构直接影响 Loki、Grafana、ELK 等后端的字段提取能力,不能随意混搭。
-
logger.WithGroup("http").Info("req", slog.String("path", "/login"))输出的是http.path字段,有层级语义 -
logger.With("http.path", "/login").Info("req")输出的是平级字段http.path,但无 group 结构,部分平台会拒绝解析或归类错误 - 嵌套过深如
http.auth.token.verify可能超平台字段名长度限制(Loki 默认约 200 字符),建议控制在 2–3 层以内
最易被忽略的一点:slog 从不读 context,也不自动提取 trace_id;所有上下文字段都靠你主动传、主动拼、主动封装。哪怕只在一个 handler 分支里忘了用 .With,那条日志就脱离了整条链路。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











