Go 日志

Go 标准库与第三方日志方案,涵盖 slog 结构化日志、日志级别、上下文集成与生产环境最佳实践。

#type / concept #status / growing #tech / dev #resource / go

[!info] related notes

Go 日志

一句话定义

Go 日志是从标准库 loglog/slog(Go 1.21+)再到第三方库的演进路径,核心目标是在服务中输出结构化、可查询、可关联的日志。

核心机制 / 工作原理

标准库 log 的局限:仅支持非结构化的纯文本输出,无日志级别,无键值对字段,每次输出自动加时间戳但格式固定。适合脚本和工具,不适合生产服务。

log/slog(Go 1.21+)

  • Handler 接口slog.Handler 定义了日志输出的抽象层。TextHandler 输出人类可读文本,JSONHandler 输出机器可解析 JSON。
  • 日志级别Debug < Info < Warn < Error,通过 slog.LevelVar 可运行时动态调整。
  • 结构化字段slog.String("key", "value")slog.Int("count", 42) 等类型安全的属性。
  • Context 集成slog.With() 创建带固定字段的 Logger,slog.WithGroup() 组织字段命名空间。
// 创建 JSON Handler,设置最低级别为 Info
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
})
logger := slog.New(handler)

// 结构化日志输出
logger.Info("user login",
    slog.String("user_id", "u-123"),
    slog.String("ip", "10.0.0.1"),
    slog.Duration("latency", 42*time.Millisecond),
)

// 带 Context 的 Logger(可注入 trace ID)
logger = logger.With(slog.String("trace_id", "abc-123"))
logger.Info("order created", slog.String("order_id", "o-456"))

第三方库

  • zerolog:零分配设计,极致性能。链式 API:log.Info().Str("key", "val").Msg("done")
  • zap:Uber 开源,高性能结构化日志。zap.Loggerzap.SugaredLogger 两种模式。

最小例子 / 最小场景

package main

import (
    "context"
    "log/slog"
    "os"
)

func main() {
    // 生产环境推荐 JSON 输出
    handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    })
    slog.SetDefault(slog.New(handler))

    ctx := context.Background()
    slog.InfoContext(ctx, "server starting",
        slog.Int("port", 8080),
        slog.String("env", "production"),
    )
}
// 输出: {"time":"2026-06-25T10:00:00Z","level":"INFO","msg":"server starting","port":8080,"env":"production"}

为什么重要

  • 可观测性基础:日志是排查线上问题的第一道防线,结构化日志可被 ELK、Loki 等系统高效索引和查询。
  • 日志关联:通过 trace_id 将同一请求链路的日志串联,是分布式追踪的关键环节。
  • 性能影响:非结构化日志在高 QPS 下成为瓶颈;slog/zerolog 的零分配设计避免 GC 压力。
  • 运维需求:动态日志级别允许在不重启服务的情况下临时开启 Debug 日志排查问题。

边界与易混淆点

  • log vs sloglog 是全局单例、无级别、无结构;slog 是标准库的现代化替代,但 Go 1.21 才引入。旧项目迁移需逐步替换。
  • Logger 注入方式:推荐通过 context.Context 传递 Logger(slog.With() 返回新实例),而非使用全局变量,便于测试和请求级字段关联。
  • zerolog vs zap vs slog:slog 是标准库,无额外依赖;zerolog 性能最佳但 API 风格不同;zap 功能最全但依赖较重。新项目优先 slog。
  • 日志级别不是越多越好:Debug/Info/Warn/Error 四级足够。Trace 和 Fatal 往往被滥用——Fatal 会 os.Exit(1) 跳过 defer 清理。
  • 敏感信息:密码、token、PII 永远不要写入日志。使用脱敏函数或在 Handler 层统一过滤。
创建于 2026/6/25 更新于 2026/6/25