关于 go-observability
go-observability 是面向 Go 生产服务开发者的可观测性技能,介绍结构化日志、OpenTelemetry 追踪与指标、告警、信号关联及遥测关闭,并提供按需参考资料。
主要功能
- 01使用 slog 进行结构化日志记录
- 02OpenTelemetry 追踪模式
- 03指标与基数管理指导
- 04告警与 SLO 实践
- 05关联日志、追踪与指标
- 06平稳关闭遥测组件
适用场景
- 01为 Go 服务添加可观测性
- 02将日志与请求追踪关联
- 03设计服务指标和告警
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ eduardo-sl/ go-agent-skills --skill go-observability安装后在 Claude Code 中输入/go-observability确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/alerting.mdmetrics.mdslog.mdtracing.md详细介绍
Go 可观测性
对于生产服务,可观测性不是可选项。每个服务都必须生成结构化日志、公开指标并传递跟踪上下文。使用标准库 log/slog 记录日志,并使用 OpenTelemetry 进行跟踪和指标采集。
社区默认规范。如果项目的 skill 或 agent-config 规则明确取代
go-observability,则优先遵循该规则。
按需加载的详细参考资料:
references/slog.md— 处理器设置、日志记录器注入、子日志记录器、LogValuer脱敏、跟踪 ID 处理器、热点路径、运行时级别。references/tracing.md— 跟踪器提供程序、跨度、上下文传播、采样、性能分析标签、关闭。references/metrics.md— 指标定义、HTTP 插桩。references/alerting.md— RED/USE、直方图与摘要、燃烧率告警、告警卫生、示例。
只有在下文内容不足时,才阅读参考文件。
1. 使用 slog 进行结构化日志记录
在生产环境中使用 log/slog(Go 1.21+)和 JSON 处理器。每一行都必须是键值对,绝不能是格式化句子:
// ✅ Good — structured, leveled
logger.Info("user created", slog.String("user_id", user.ID), slog.Duration("latency", elapsed))
// ❌ Bad — unparseable in production
log.Printf("user %s created in %v", user.ID, elapsed)
将日志记录器作为依赖项注入;绝不要使用包级全局变量。使用 logger.With(...) 派生子日志记录器,将组件、方法和请求 ID 附加一次,而不是在每个调用点都重复附加。参见 references/slog.md。
日志级别 — 保持一致
| 级别 | 用途 |
|---|---|
Debug | 详细诊断信息,在生产环境中禁用 |
Info | 正常操作:收到请求、任务完成 |
Warn | 可恢复的问题:重试成功、使用了已弃用功能 |
Error | 需要关注的故障:数据库宕机、外部调用失败 |
绝不要将预期情况记录为 Error 级别(未找到用户 → Info 或 Warn)。
敏感数据 — 绝不要记录
- 密码、令牌、API 密钥
- 完整信用卡号、SSN
- 个人标识信息:可用于识别个人的电子邮件地址、电话号码、IP 地址
- 包含 PII 的原始请求正文
// ✅ Good — an opaque internal ID, no personal data
logger.Info("auth attempt", slog.String("user_id", userID), slog.Bool("success", ok))
// ❌ Bad — leaks a credential and a personal identifier
logger.Info("auth attempt", slog.String("password", password))
logger.Info("auth attempt", slog.String("user", email))
记录稳定的内部 ID,并在允许存储个人数据的系统中关联个人数据。日志保留期限、搜索访问权限和第三方日志接收端,通常都达不到用户表所适用的保护标准。
将脱敏设为类型本身的特性:为密钥以及存储个人数据的结构体实现 slog.LogValuer,这样 slog.Any(user) 在任何地方都只会记录安全字段。
成本与控制
- 热点路径使用
logger.LogAttrs,并使用logger.Enabled防止生成昂贵的属性。 - 在
HandlerOptions中使用slog.LevelVar,即可在不重新部署的情况下更改级别。 slog.NewMultiHandler(Go 1.26+)可将日志分发给多个处理器。
2. 使用 OpenTelemetry 进行分布式跟踪
对于所有值得在瀑布图中观察的操作都启动一个跨度——入站请求、数据库调用、出站 HTTP、重要业务步骤——并始终使用 defer span.End()。
参考示例遵循的规则:
- 使用操作名称命名跨度(
GetUser、db.query),不要使用完全限定的函数名,也不要使用doStuff。 - 失败时调用
span.RecordError(err)和span.SetStatus(codes.Error, ...),否则失败请求会显示为绿色跨度。 - 将
ctx沿整个调用链传递。在调用链中途使用context.Background()会悄然启动新的跟踪,并断开父级关联。 - 使用
ParentBased(TraceIDRatioBased(r))进行采样,确保各服务对同一跟踪达成一致;通过收集器中的尾部采样保留错误和慢请求。 - 性能分析是第四种信号:在生产环境中持续进行性能分析,并使用范围受限的
pprof.Labels(路由、租户等级)拆分热点函数。
设置和示例见 references/tracing.md。
3. 使用 OpenTelemetry / Prometheus 记录指标
| 类型 | 用途 | 示例 |
|---|---|---|
| Counter | 单调递增的值 | 请求总数、错误总数 |
| Gauge | 可升可降的值 | 活跃连接数、队列深度 |
| Histogram | 值的分布 | 请求延迟、响应大小 |
命名格式为 <namespace>_<subsystem>_<name>_<unit>:
http_request_duration_seconds ✅ (unit in name)
http_requests_total ✅ (counter with _total suffix)
db_connections_active ✅ (gauge, no suffix needed)
user_signups ❌ (missing _total for counter)
requestLatency ❌ (camelCase, no unit)
保持基数有界。使用路由模式、方法和状态码作为标签——
切勿使用用户 ID、请求 ID 或原始 r.URL.Path;这些值会为每个取值创建新的
时间序列,最终导致指标后端宕机。
定义和中间件见 references/metrics.md。
4. 关联日志、追踪和指标
没有追踪 ID 的日志行无法关联到生成它的请求。将处理程序包装一次,让每个
*Context 日志调用都从 ctx 添加 trace_id 和 span_id——包装器还必须重写
WithAttrs 和 WithGroup,否则子日志记录器会丢失这些字段。为延迟直方图附加示例(追踪 ID),以便从 p99 峰值跳转到问题追踪。
5. 告警和 SLO
- 对服务按路由衡量 RED(速率、错误、时长),对资源池和队列衡量 USE (利用率、饱和度、错误)。
- 延迟必须使用 Histogram,而非 Summary——Summary 分位数无法跨实例 聚合。围绕 SLO 阈值设置桶。
- 同时基于长窗口和短窗口的 SLO 消耗速率触发页面告警;较慢的消耗则创建工单。
- 针对症状而非原因设置告警;使用
rate()而非irate();对 必须存在的序列使用absent();每条页面告警都附上运行手册链接。
查询和示例接线方式见 references/alerting.md。
6. 遥测的优雅关闭
批处理 span 处理器会将 spans 保存在内存中。退出时使用其独立的超时时间调用 tp.Shutdown(ctx),否则崩溃前最后几秒的 spans——那些最值得关注的——将永远无法到达收集器。
示例见 references/tracing.md。
验证清单
- 所有日志都使用
log/slog和结构化键值对,而非fmt.Printf或log.Printf - Logger 作为依赖注入,而非用作全局变量
- 日志输出中不包含敏感数据(密码、令牌、PII)
- 通过
context.Context在所有函数调用间传递追踪上下文 - 为重要操作(数据库调用、HTTP 请求、业务逻辑)创建 spans
- 使用
span.RecordError(err)记录 span 错误并设置错误状态 - 指标遵循命名约定:
_seconds、_total、_bytes - 指标中不使用高基数标签(用户 ID、请求 ID)
- 服务退出时优雅关闭遥测提供程序
- 在日志条目中包含追踪 ID,以便关联
- 使用直方图记录延迟;页面告警应基于 SLO 消耗速率,并附带运行手册