关于 golang-samber-slog
介绍 samber/slog 系列 Go 包的技能,使用标准 slog.Handler 接口构建结构化日志管道。涵盖处理器组合、采样、属性格式化、HTTP 中间件和后端接收器。
主要功能
- 01可组合的 slog 处理器
- 02路由、广播、故障转移与负载分配
- 03控制日志量的采样策略
- 04属性格式化与 PII 遮蔽
- 05HTTP 中间件和后端接收器
适用场景
- 01将错误日志路由到指定处理器
- 02通过采样减少重复日志
- 03导出前移除敏感属性
- 04为 HTTP 日志添加请求数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-samber-slog安装后在 Claude Code 中输入/golang-samber-slog确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/backend-handlers.mdhttp-middlewares.mdpipeline-patterns.mdsampling-strategies.md详细介绍
**角色:**你是一名 Go 日志架构师。你设计的日志管道会让每条记录都流经合适的处理器——采样会尽早丢弃噪声,格式化器会在记录离开进程前剥离个人身份信息(PII),路由器则会将错误发送到 Sentry,并将信息级日志发送到 Loki。
samber/slog-**** — Go 结构化日志管道
20 多个可组合的 slog.Handler 包,适用于 Go 1.21+。包含三个核心管道库,以及都实现了标准 slog.Handler 接口的 HTTP 中间件和后端接收器。
官方资源:
- github.com/samber/slog-multi — 处理器组合
- github.com/samber/slog-sampling — 吞吐量控制
- github.com/samber/slog-formatter — 属性转换
本技能并未涵盖所有内容——更多信息请参阅库文档和代码示例:
- 如需 Go 包文档、符号、版本、导入方和已知漏洞信息,→ 请参阅
samber/cc-skills-golang@golang-pkg-go-dev技能(godig);查询 Go 包信息时优先于 Context7。 - 如需在自己的代码中查看此库的用法(定义、调用点、诊断信息),→ 请参阅
samber/cc-skills-golang@golang-gopls技能(gopls)。 - 对于未被 pkg.go.dev 收录的文档,Context7 仍可作为备用方案。
管道模型
每个 samber/slog 管道都遵循规范的顺序。记录从左向右流动——将采样放在最前面,以便尽早丢弃记录,避免在最终不会到达接收器的记录上浪费 CPU。
record → [Sampling] → [Pipe: trace/PII] → [Router] → [Sinks]
顺序很重要:先采样再格式化可以节省 CPU。先格式化再路由可确保所有接收器收到的属性都是干净的。颠倒顺序会在最终被丢弃的记录上浪费资源。
核心库
| 库 | 用途 | 主要构造函数 |
|---|---|---|
slog-multi | 处理器组合 | Fanout、Router、FirstMatch、Failover、Pool、Pipe |
slog-sampling | 吞吐量控制 | UniformSamplingOption、ThresholdSamplingOption、AbsoluteSamplingOption、CustomSamplingOption |
slog-formatter | 属性转换 | PIIFormatter、ErrorFormatter、FormatByType[T]、FormatByKey、FlattenFormatterMiddleware |
slog-multi — 处理器组合
六种组合模式,分别适用于不同的路由需求:
| 模式 | 行为 | 延迟影响 |
|---|---|---|
Fanout(handlers...) | 依次向所有处理器广播 | 所有处理器延迟之和 |
Router().Add(h, predicate).Handler() | 路由到所有匹配的处理器 | 匹配的处理器延迟之和 |
Router().Add(...).FirstMatch().Handler() | 仅路由到第一个匹配项 | 单个处理器的延迟 |
Failover()(handlers...) | 依次尝试,直到有一个成功 | 主处理器的延迟(正常路径) |
Pool()(handlers...) | 负载均衡:每条记录发送到一个处理器 | 单个处理器的延迟 |
Pipe(middlewares...).Handler(sink) | 在接收器之前执行中间件链 | 中间件开销 + 接收器开销 |
// Route errors to Sentry, all logs to stdout
logger := slog.New(
slogmulti.Router().
Add(sentryHandler, slogmulti.LevelIs(slog.LevelError)).
Add(slog.NewJSONHandler(os.Stdout, nil)).
Handler(),
)
内置谓词:LevelIs、LevelIsNot、MessageIs、MessageIsNot、MessageContains、MessageNotContains、AttrValueIs、AttrKindIs。
有关每种模式的完整代码示例,请参阅管道模式。
slog-sampling — 吞吐量控制
| 策略 | 行为 | 适用场景 |
|---|---|---|
| Uniform | 丢弃所有记录中固定百分比的记录 | 减少开发/预发布环境中的噪声 |
| Threshold | 每个时间间隔内记录前 N 条,之后按 R 的采样率采样 | 生产环境——保留初始可见性 |
| Absolute | 全局限制每个时间间隔内最多记录 N 条 | 严格控制成本 |
| Custom | 用户函数按记录返回采样率 | 基于级别或时间的规则 |
采样 MUST 是管道中最外层的处理器——如果将其放在格式化之后,会浪费 CPU 来处理最终被丢弃的记录。
// Threshold: log first 10 per 5s, then 10% — errors always pass through via Router
logger := slog.New(
slogmulti.
Pipe(slogsampling.ThresholdSamplingOption{
Tick: 5 * time.Second, Threshold: 10, Rate: 0.1,
}.NewMiddleware()).
Handler(innerHandler),
)
匹配器会将相似记录分组以进行去重:MatchByLevel()、MatchByMessage()、MatchByLevelAndMessage()(默认)、MatchBySource()、MatchByAttribute(groups, key)。
有关策略比较和配置详情,请参阅 采样策略。
slog-formatter — 属性转换
将其用作 Pipe 中间件,以便所有下游处理器都能接收到干净的属性。
logger := slog.New(
slogmulti.Pipe(slogformatter.NewFormatterMiddleware(
slogformatter.PIIFormatter("user"), // mask PII fields
slogformatter.ErrorFormatter("error"), // structured error info
slogformatter.IPAddressFormatter("client"), // mask IP addresses
)).Handler(slog.NewJSONHandler(os.Stdout, nil)),
)
关键格式化器:PIIFormatter、ErrorFormatter、TimeFormatter、UnixTimestampFormatter、IPAddressFormatter、HTTPRequestFormatter、HTTPResponseFormatter。通用格式化器:FormatByType[T]、FormatByKey、FormatByKind、FormatByGroup、FormatByGroupKey。使用 FlattenFormatterMiddleware 展平嵌套属性。
HTTP 中间件
各框架使用一致的模式:router.Use(slogXXX.New(logger))。
可用项:slog-gin、slog-echo、slog-fiber、slog-chi、slog-http(net/http)。
它们都共享一个 Config 结构体,包含:DefaultLevel、ClientErrorLevel、ServerErrorLevel、WithRequestBody、WithResponseBody、WithUserAgent、WithRequestID、WithTraceID、WithSpanID、Filters。
// Gin with filters — skip health checks
router.Use(sloggin.NewWithConfig(logger, sloggin.Config{
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
WithRequestBody: true,
Filters: []sloggin.Filter{
sloggin.IgnorePath("/health", "/metrics"),
},
}))
有关特定框架的设置,请参阅 HTTP 中间件。
后端接收器
全部采用 Option{}.NewXxxHandler() 构造函数模式。
| 类别 | 包 |
|---|---|
| 云服务 | slog-datadog、slog-sentry、slog-loki、slog-graylog |
| 消息传递 | slog-kafka、slog-fluentd、slog-logstash、slog-nats |
| 通知 | slog-slack、slog-telegram、slog-webhook |
| 存储 | slog-parquet |
| 桥接 | slog-zap、slog-zerolog、slog-logrus |
批处理器需要优雅关闭——slog-datadog、slog-loki、slog-kafka 和 slog-parquet 会在内部缓冲记录。关闭时请刷新缓冲区(例如,Datadog 使用 handler.Stop(ctx),Loki 使用 lokiClient.Stop(),Kafka 使用 writer.Close()),否则缓冲的日志将会丢失。
有关配置示例和关闭模式,请参阅 后端处理器。
常见错误
| 错误 | 失败原因 | 修正方法 |
|---|---|---|
| 在格式化后采样 | 格式化最终被丢弃的记录会浪费 CPU | 将采样器置于最外层处理器 |
| 扇出到多个同步处理器 | 会阻塞调用方——延迟是所有处理器延迟之和 | 使用 Pool() 并发分发 |
| 批处理器关闭时未刷新缓冲区 | 关闭时缓冲的日志会丢失 | 使用 defer handler.Stop(ctx)(Datadog)、defer lokiClient.Stop()(Loki)、defer writer.Close()(Kafka) |
| 路由器没有默认/兜底处理器 | 未匹配的记录会被静默丢弃 | 添加一个没有谓词的处理器作为兜底 |
使用 AttrFromContext,但未配置 HTTP 中间件 | 上下文中没有可提取的请求属性 | 先安装 slog-gin/echo/fiber/chi 中间件 |
使用 Pipe,但没有中间件 | 空操作包装器会增加每条记录的开销 | 如果不需要中间件,则移除 Pipe() |
性能警告
- Fanout 延迟 = 所有处理器延迟之和(顺序执行)。有 5 个处理器且每个耗时 10ms 时,每次日志调用都会耗时 50ms。使用
Pool()将其降低至最大延迟 - Pipe 中间件会增加每条记录的函数调用开销——将链保持简短(2-4 个中间件)
- slog-formatter 会按顺序处理属性——格式化器过多会累积开销。对于热路径上的属性格式化,建议改为在类型上实现
slog.LogValuer - 基准测试你的流水线:在部署到生产环境前运行
go test -bench
**诊断:**测量流水线每条记录的分配量和延迟,并找出链中分配量最大的处理器。
最佳实践
- 先采样,再格式化,最后路由——这一经典顺序可最大限度减少无效工作,并确保所有接收端都能看到干净的数据
- 使用 Pipe 处理横切关注点——追踪 ID 注入和 PII 清理应放在中间件中,而非各处理器的逻辑中
- 使用
slogmulti.NewHandleInlineHandler测试流水线——无需真实接收端,即可断言到达各阶段的记录 - 使用
AttrFromContext将请求范围的属性从 HTTP 中间件传递到所有处理器 - 当处理器需要不同的记录子集时,优先使用 Router 而非 Fanout——Router 会评估谓词并跳过不匹配的处理器
交叉引用
- → 关于 slog 基础知识(级别、上下文、处理器设置、迁移),请参阅
samber/cc-skills-golang@golang-observability技能 - → 关于日志记录或返回规则,请参阅
samber/cc-skills-golang@golang-error-handling技能 - → 关于日志中的 PII 处理,请参阅
samber/cc-skills-golang@golang-security技能 - → 关于使用
samber/oops提供结构化错误上下文,请参阅samber/cc-skills-golang@golang-samber-oops技能
如果你在任何 samber/slog-* 包中遇到错误或意外行为,请在相应的代码仓库中提交 issue(例如,slog-multi/issues、slog-sampling/issues)。