Go log/slog 包详解
概述
log/slog 包是 Go 1.21 引入的结构化日志记录包,提供了现代化的日志 API。它支持结构化日志输出(JSON 和文本格式)、日志级别控制、属性添加、日志采样等功能。该包设计用于替代传统的 log 包,提供更强大、更灵活的日志记录能力,特别适合现代分布式系统和微服务架构。
包导入
import "log/slog"
基本使用
1. 简单日志输出
package main
import (
"log/slog"
)
func main() {
// 基本日志输出
slog.Info("这是一条日志信息")
// 带属性的日志
slog.Info("用户登录", "user_id", 123, "ip", "192.168.1.1")
// 带格式化的属性
slog.Info("处理请求",
"method", "GET",
"path", "/api/users",
"duration_ms", 150,
)
}
2. 不同级别的日志
package main
import (
"log/slog"
)
func main() {
// Debug 级别
slog.Debug("调试信息", "detail", "详细信息")
// Info 级别
slog.Info("普通信息", "status", "success")
// Warn 级别
slog.Warn("警告信息", "code", "W001")
// Error 级别
slog.Error("错误信息", "error", "连接失败")
}
3. 创建自定义 Logger
package main
import (
"log/slog"
"os"
)
func main() {
// 创建 JSON 格式的 logger
jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(jsonLogger)
slog.Info("JSON 格式日志")
// 输出:{"time":"2026-04-04T10:30:00Z","level":"INFO","msg":"JSON 格式日志"}
// 创建文本格式的 logger
textLogger := slog.New(slog.NewTextHandler(os.Stdout, nil))
slog.SetDefault(textLogger)
slog.Info("文本格式日志")
// 输出:time=2026-04-04T10:30:00Z level=INFO msg="文本格式日志"
}
一、核心类型
Logger
定义:
type Logger struct {
// 包含未导出的字段
}
说明:
- 功能:结构化日志记录器
- 特点:
- 线程安全
- 支持链式调用(With、Group)
- 可配置 Handler
- 支持日志级别过滤
- 用途:记录结构化日志
方法总览:
| 方法 | 参数 | 返回值 | 描述 |
|---|---|---|---|
Debug | msg string, attrs ...any | 无 | 记录 Debug 级别日志 |
Info | msg string, attrs ...any | 无 | 记录 Info 级别日志 |
Warn | msg string, attrs ...any | 无 | 记录 Warn 级别日志 |
Error | msg string, attrs ...any | 无 | 记录 Error 级别日志 |
Log | ctx context.Context, level Level, msg string, attrs ...any | 无 | 记录指定级别日志 |
LogAttrs | ctx context.Context, level Level, msg string, attrs ...Attr | 无 | 记录指定级别日志(Attr 类型) |
With | attrs ...any | *Logger | 创建带属性的新 Logger |
WithGroup | name string | *Logger | 创建带分组的 Logger |
Enabled | ctx context.Context, level Level | bool | 检查级别是否启用 |
Handler | 无 | Handler | 获取 Handler |
示例:
package main
import (
"context"
"log/slog"
"os"
)
func main() {
// 创建 logger
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// 基本日志
logger.Info("用户登录", "user_id", 123)
// 使用 With 添加公共属性
requestLogger := logger.With("request_id", "abc123")
requestLogger.Info("处理请求")
requestLogger.Error("请求失败", "error", "timeout")
// 使用 WithGroup 分组
groupLogger := logger.WithGroup("auth")
groupLogger.Info("认证信息", "token", "xyz")
// 使用 Log 方法指定级别
logger.Log(context.Background(), slog.LevelInfo, "自定义级别日志")
// 使用 LogAttrs(Attr 类型)
logger.LogAttrs(context.Background(), slog.LevelInfo, "Attr 日志",
slog.String("name", "张三"),
slog.Int("age", 25),
)
// 检查级别是否启用
if logger.Enabled(context.Background(), slog.LevelDebug) {
logger.Debug("调试信息")
}
}
Attr
定义:
type Attr struct {
Key string
Value Value
}
说明:
- 功能:表示一个键值对属性
- 字段:
Key- 属性键(字符串)Value- 属性值(Value 类型)
- 用途:构建类型安全的日志属性
示例:
package main
import (
"log/slog"
)
func main() {
// 创建 Attr
attr1 := slog.String("name", "张三")
attr2 := slog.Int("age", 25)
attr3 := slog.Bool("active", true)
// 使用 Attr 记录日志
slog.Info("用户信息", attr1, attr2, attr3)
// 或者直接构造
attr4 := slog.Attr{
Key: "email",
Value: slog.StringValue("test@example.com"),
}
slog.Info("联系信息", attr4)
}
Value
定义:
type Value struct {
// 包含未导出的字段
}
说明:
- 功能:表示日志属性的值
- 特点:支持多种类型(字符串、整数、浮点数、布尔值、时间、Duration 等)
- 用途:类型安全的值存储
示例:
package main
import (
"log/slog"
"time"
)
func main() {
// 创建不同类型的 Value
v1 := slog.StringValue("hello")
v2 := slog.IntValue(42)
v3 := slog.Float64Value(3.14)
v4 := slog.BoolValue(true)
v5 := slog.TimeValue(time.Now())
v6 := slog.DurationValue(time.Second)
v7 := slog.AnyValue([]int{1, 2, 3})
// 使用 Value
slog.Info("各种类型的值",
"string", v1,
"int", v2,
"float", v3,
"bool", v4,
"time", v5,
"duration", v6,
"slice", v7,
)
}
Level
定义:
type Level int
说明:
- 功能:表示日志级别
- 底层类型:int
- 用途:控制日志输出的详细程度
常量:
const (
LevelDebug Level = -4
LevelInfo Level = 0
LevelWarn Level = 4
LevelError Level = 8
)
示例:
package main
import (
"log/slog"
)
func main() {
// 使用预定义级别
slog.Debug("调试信息") // LevelDebug
slog.Info("普通信息") // LevelInfo
slog.Warn("警告信息") // LevelWarn
slog.Error("错误信息") // LevelError
// 自定义级别
var customLevel slog.Level = 2
slog.Log(context.Background(), customLevel, "自定义级别")
// 级别比较
if slog.LevelInfo > slog.LevelDebug {
println("Info 级别高于 Debug")
}
}
Record
定义:
type Record struct {
// 包含未导出的字段
}
说明:
- 功能:表示一条日志记录
- 字段:
Time- 日志时间Level- 日志级别Message- 日志消息PC- 程序计数器(用于获取调用位置)
- 用途:在 Handler 中使用
方法:
AddAttrs(attrs ...Attr)- 添加属性Add(args ...any)- 添加键值对NumAttrs()- 获取属性数量
示例:
package main
import (
"context"
"log/slog"
"os"
)
// 自定义 Handler
type CustomHandler struct{}
func (h *CustomHandler) Enabled(ctx context.Context, level slog.Level) bool {
return true
}
func (h *CustomHandler) Handle(ctx context.Context, record slog.Record) error {
// 访问记录字段
println("时间:", record.Time.String())
println("级别:", record.Level.String())
println("消息:", record.Message)
// 遍历属性
record.Attrs(func(a slog.Attr) bool {
println("属性:", a.Key, "=", a.Value.String())
return true
})
return nil
}
func (h *CustomHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return h
}
func (h *CustomHandler) WithGroup(name string) slog.Handler {
return h
}
func main() {
logger := slog.New(&CustomHandler{})
logger.Info("测试日志", "key", "value")
}
二、Handler 类型
Handler 接口
定义:
type Handler interface {
Enabled(ctx context.Context, level Level) bool
Handle(ctx context.Context, record Record) error
WithAttrs(attrs []Attr) Handler
WithGroup(name string) Handler
}
说明:
- 功能:定义日志处理接口
- 方法:
Enabled- 检查级别是否启用Handle- 处理日志记录WithAttrs- 添加属性WithGroup- 添加分组
JSONHandler
定义:
type JSONHandler struct {
// 包含未导出的字段
}
说明:
- 功能:JSON 格式日志处理器
- 输出格式:每行一个 JSON 对象
- 用途:机器可读的日志格式
示例:
package main
import (
"log/slog"
"os"
)
func main() {
// 创建 JSON Handler
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
logger := slog.New(handler)
logger.Info("用户操作",
"action", "login",
"user_id", 123,
"success", true,
)
// 输出:
// {"time":"2026-04-04T10:30:00Z","level":"INFO","msg":"用户操作","action":"login","user_id":123,"success":true}
}
TextHandler
定义:
type TextHandler struct {
// 包含未导出的字段
}
说明:
- 功能:文本格式日志处理器
- 输出格式:键=值 格式
- 用途:人类可读的日志格式
示例:
package main
import (
"log/slog"
"os"
)
func main() {
// 创建 Text Handler
handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
logger := slog.New(handler)
logger.Info("用户操作",
"action", "login",
"user_id", 123,
"success", true,
)
// 输出:
// time=2026-04-04T10:30:00Z level=INFO msg="用户操作" action=login user_id=123 success=true
}
三、包级别函数
Debug
定义:
func Debug(msg string, args ...any)
说明:
- 功能:记录 Debug 级别日志到默认 Logger
- 参数:
msg- 日志消息args- 键值对属性
- 用途:调试信息
示例:
slog.Debug("调试信息", "var", value)
Info
定义:
func Info(msg string, args ...any)
说明:
- 功能:记录 Info 级别日志到默认 Logger
- 参数:
msg- 日志消息args- 键值对属性
- 用途:普通信息
示例:
slog.Info("服务启动", "port", 8080)
Warn
定义:
func Warn(msg string, args ...any)
说明:
- 功能:记录 Warn 级别日志到默认 Logger
- 参数:
msg- 日志消息args- 键值对属性
- 用途:警告信息
示例:
slog.Warn("资源不足", "memory", "90%")
Error
定义:
func Error(msg string, args ...any)
说明:
- 功能:记录 Error 级别日志到默认 Logger
- 参数:
msg- 日志消息args- 键值对属性
- 用途:错误信息
示例:
slog.Error("请求失败", "error", err, "url", url)
Log
定义:
func Log(ctx context.Context, level Level, msg string, args ...any)
说明:
- 功能:记录指定级别日志到默认 Logger
- 参数:
ctx- 上下文level- 日志级别msg- 日志消息args- 键值对属性
示例:
slog.Log(context.Background(), slog.LevelInfo, "自定义级别日志")
LogAttrs
定义:
func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)
说明:
- 功能:记录指定级别日志(Attr 类型)
- 参数:
ctx- 上下文level- 日志级别msg- 日志消息attrs- Attr 类型属性
示例:
slog.LogAttrs(context.Background(), slog.LevelInfo, "类型安全日志",
slog.String("name", "张三"),
slog.Int("age", 25),
)
SetDefault
定义:
func SetDefault(l *Logger)
说明:
- 功能:设置默认 Logger
- 参数:
l- 新的默认 Logger - 用途:替换全局默认 Logger
示例:
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)
Default
定义:
func Default() *Logger
说明:
- 功能:获取默认 Logger
- 返回值:
*Logger- 默认 Logger 实例
示例:
defaultLogger := slog.Default()
defaultLogger.Info("使用默认 Logger")
With
定义:
func With(args ...any) *Logger
说明:
- 功能:创建带属性的新 Logger
- 参数:
args- 键值对属性 - 返回值:
*Logger- 新的 Logger 实例
示例:
requestLogger := slog.With("request_id", "abc123")
requestLogger.Info("处理请求")
四、辅助函数
String
定义:
func String(key, value string) Attr
示例:
slog.Info("用户", slog.String("name", "张三"))
Int
定义:
func Int(key string, value int) Attr
示例:
slog.Info("计数", slog.Int("count", 100))
Int64
定义:
func Int64(key string, value int64) Attr
示例:
slog.Info("时间戳", slog.Int64("timestamp", 1234567890))
Float64
定义:
func Float64(key string, value float64) Attr
示例:
slog.Info("价格", slog.Float64("price", 99.99))
Bool
定义:
func Bool(key string, value bool) Attr
示例:
slog.Info("状态", slog.Bool("active", true))
Time
定义:
func Time(key string, value time.Time) Attr
示例:
slog.Info("事件", slog.Time("time", time.Now()))
Duration
定义:
func Duration(key string, value time.Duration) Attr
示例:
slog.Info("耗时", slog.Duration("duration", time.Second))
Any
定义:
func Any(key string, value any) Attr
说明:
- 功能:自动推断类型的属性
- 用途:处理任意类型
示例:
slog.Info("任意类型",
slog.Any("slice", []int{1, 2, 3}),
slog.Any("map", map[string]int{"a": 1}),
)
Group
定义:
func Group(key string, args ...any) Attr
说明:
- 功能:创建属性分组
- 用途:组织相关属性
示例:
slog.Info("用户信息",
slog.Group("user",
"id", 123,
"name", "张三",
),
slog.Group("address",
"city", "北京",
"district", "朝阳",
),
)
五、典型示例
示例 1:Web 服务日志
package main
import (
"log/slog"
"net/http"
"os"
"time"
)
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 创建带请求 ID 的 logger
logger := slog.With(
"method", r.Method,
"path", r.URL.Path,
"request_id", r.Header.Get("X-Request-ID"),
)
logger.Info("请求开始")
// 调用下一个 handler
next.ServeHTTP(w, r)
// 记录耗时
logger.Info("请求完成",
"duration_ms", time.Since(start).Milliseconds(),
)
})
}
func main() {
// 设置 JSON 格式日志
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
slog.SetDefault(slog.New(handler))
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
slog.Info("处理首页请求")
w.Write([]byte("Hello"))
})
http.ListenAndServe(":8080", loggingMiddleware(mux))
}
示例 2:多级别日志配置
package main
import (
"log/slog"
"os"
)
func main() {
// 开发环境:输出 Debug 级别
devHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
devLogger := slog.New(devHandler)
// 生产环境:只输出 Warn 及以上级别
prodHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelWarn,
})
prodLogger := slog.New(prodHandler)
// 根据环境选择
if os.Getenv("ENV") == "production" {
slog.SetDefault(prodLogger)
} else {
slog.SetDefault(devLogger)
}
// 使用
slog.Debug("调试信息") // 生产环境不会输出
slog.Info("普通信息") // 生产环境不会输出
slog.Warn("警告信息") // 都会输出
slog.Error("错误信息") // 都会输出
}
示例 3:结构化错误日志
package main
import (
"errors"
"fmt"
"log/slog"
"os"
)
type APIError struct {
Code int
Message string
Details string
}
func (e *APIError) Error() string {
return fmt.Sprintf("API Error %d: %s", e.Code, e.Message)
}
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// 记录错误
err := &APIError{
Code: 404,
Message: "Not Found",
Details: "Resource not found",
}
logger.Error("API 错误",
"error", err,
"code", err.Code,
"message", err.Message,
"details", err.Details,
)
// 使用 Any 记录任意错误
if err := doSomething(); err != nil {
logger.Error("操作失败",
"error", err,
"error_type", fmt.Sprintf("%T", err),
)
}
}
func doSomething() error {
return errors.New("示例错误")
}
示例 4:日志采样
package main
import (
"context"
"log/slog"
"math/rand"
"os"
"sync/atomic"
)
// SampledHandler 采样处理器
type SampledHandler struct {
handler slog.Handler
rate float64
count atomic.Int64
}
func (h *SampledHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.handler.Enabled(ctx, level)
}
func (h *SampledHandler) Handle(ctx context.Context, record slog.Record) error {
// 采样逻辑:只记录 10% 的日志
if rand.Float64() > h.rate {
return nil
}
return h.handler.Handle(ctx, record)
}
func (h *SampledHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &SampledHandler{
handler: h.handler.WithAttrs(attrs),
rate: h.rate,
}
}
func (h *SampledHandler) WithGroup(name string) slog.Handler {
return &SampledHandler{
handler: h.handler.WithGroup(name),
rate: h.rate,
}
}
func main() {
baseHandler := slog.NewJSONHandler(os.Stdout, nil)
sampledHandler := &SampledHandler{
handler: baseHandler,
rate: 0.1, // 10% 采样率
}
logger := slog.New(sampledHandler)
// 模拟大量日志
for i := 0; i < 1000; i++ {
logger.Info("高频日志", "iteration", i)
}
}
示例 5:自定义 Handler
package main
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"strings"
)
// ColorHandler 彩色文本处理器
type ColorHandler struct {
w io.Writer
}
func (h *ColorHandler) Enabled(ctx context.Context, level slog.Level) bool {
return true
}
func (h *ColorHandler) Handle(ctx context.Context, record slog.Record) error {
// 根据级别添加颜色
var color string
switch record.Level {
case slog.LevelDebug:
color = "\033[36m" // 青色
case slog.LevelInfo:
color = "\033[32m" // 绿色
case slog.LevelWarn:
color = "\033[33m" // 黄色
case slog.LevelError:
color = "\033[31m" // 红色
}
reset := "\033[0m"
// 格式化输出
var sb strings.Builder
sb.WriteString(fmt.Sprintf("%s[%s]%s %s", color, record.Level, reset, record.Message))
// 添加属性
record.Attrs(func(a slog.Attr) bool {
sb.WriteString(fmt.Sprintf(" %s=%v", a.Key, a.Value))
return true
})
fmt.Fprintln(h.w, sb.String())
return nil
}
func (h *ColorHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return h
}
func (h *ColorHandler) WithGroup(name string) slog.Handler {
return h
}
func main() {
logger := slog.New(&ColorHandler{w: os.Stdout})
logger.Debug("调试信息")
logger.Info("普通信息")
logger.Warn("警告信息")
logger.Error("错误信息")
}
六、最佳实践
1. 使用结构化属性
// 不好的做法
slog.Info("用户 张三 登录,IP: 192.168.1.1")
// 好的做法
slog.Info("用户登录",
"username", "张三",
"ip", "192.168.1.1",
)
2. 使用合适的级别
// Debug: 详细的调试信息
slog.Debug("变量值", "x", x, "y", y)
// Info: 正常的业务操作
slog.Info("订单创建", "order_id", orderID)
// Warn: 需要注意但不影响运行的情况
slog.Warn("缓存未命中", "key", key)
// Error: 错误情况
slog.Error("数据库连接失败", "error", err)
3. 添加上下文信息
// 为每个请求创建带上下文的 logger
func handleRequest(w http.ResponseWriter, r *http.Request) {
logger := slog.With(
"request_id", generateRequestID(),
"method", r.Method,
"path", r.URL.Path,
"remote_addr", r.RemoteAddr,
)
logger.Info("请求开始")
// ... 处理请求
logger.Info("请求完成")
}
4. 避免性能问题
// 避免构造昂贵的属性
if logger.Enabled(context.Background(), slog.LevelDebug) {
logger.Debug("详细信息", "data", expensiveOperation())
}
5. 错误字段命名
// 使用一致的字段名
slog.Error("操作失败", "error", err)
slog.Error("另一个错误", "error", err2)
// 多个错误时使用不同的字段名
slog.Error("比较失败",
"expected", expectedErr,
"actual", actualErr,
)
七、与其他包配合
1. 与 context 配合
package main
import (
"context"
"log/slog"
)
type contextKey string
const loggerKey = contextKey("logger")
func withLogger(ctx context.Context, logger *slog.Logger) context.Context {
return context.WithValue(ctx, loggerKey, logger)
}
func loggerFromContext(ctx context.Context) *slog.Logger {
if logger, ok := ctx.Value(loggerKey).(*slog.Logger); ok {
return logger
}
return slog.Default()
}
func handler(ctx context.Context) {
logger := loggerFromContext(ctx)
logger.Info("处理中")
}
2. 与 errors 配合
package main
import (
"errors"
"fmt"
"log/slog"
)
func main() {
err := errors.New("简单错误")
slog.Error("错误发生", "error", err)
// 格式化错误
wrappedErr := fmt.Errorf("包装错误:%w", err)
slog.Error("包装错误",
"error", wrappedErr,
"cause", errors.Unwrap(wrappedErr),
)
}
3. 与 time 配合
package main
import (
"log/slog"
"time"
)
func main() {
start := time.Now()
// 记录耗时
slog.Info("操作完成",
"duration", time.Since(start),
"duration_ms", time.Since(start).Milliseconds(),
)
// 记录时间点
slog.Info("事件发生",
"time", time.Now(),
"unix", time.Now().Unix(),
)
}
八、快速参考
类型总览
| 类型名 | 描述 |
|---|---|
Logger | 结构化日志记录器 |
Attr | 键值对属性 |
Value | 属性值 |
Level | 日志级别 |
Record | 日志记录 |
Handler | 日志处理器接口 |
JSONHandler | JSON 格式处理器 |
TextHandler | 文本格式处理器 |
包级别函数总览
| 函数名 | 描述 |
|---|---|
Debug/Info/Warn/Error | 记录对应级别日志 |
Log | 记录指定级别日志 |
LogAttrs | 记录指定级别日志(Attr 类型) |
SetDefault | 设置默认 Logger |
Default | 获取默认 Logger |
With | 创建带属性的 Logger |
辅助函数总览
| 函数 | 用途 |
|---|---|
String/Int/Int64/Float64/Bool | 创建基本类型 Attr |
Time/Duration | 创建时间类型 Attr |
Any | 创建任意类型 Attr |
Group | 创建分组 Attr |
日志级别
| 级别 | 值 | 用途 |
|---|---|---|
LevelDebug | -4 | 调试信息 |
LevelInfo | 0 | 普通信息 |
LevelWarn | 4 | 警告信息 |
LevelError | 8 | 错误信息 |
格式对比
| 格式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| JSON | 机器可读、易解析 | 人类不友好 | 生产环境、日志系统 |
| Text | 人类可读 | 难解析 | 开发环境、调试 |
九、注意事项
1. 键值对配对
// 错误:奇数个参数
slog.Info("日志", "key1", "value1", "key2") // ✗
// 正确:偶数个参数
slog.Info("日志", "key1", "value1", "key2", "value2") // ✓
2. 避免敏感信息
// 错误:记录敏感信息
slog.Info("用户登录", "password", password) // ✗
// 正确:脱敏处理
slog.Info("用户登录", "user_id", userID) // ✓
3. Logger 是不可变的
// Logger 的 With 方法返回新实例
logger := slog.Default()
logger2 := logger.With("key", "value")
// logger 本身不会改变
logger.Info("原始 logger")
logger2.Info("带属性的 logger")
4. 并发安全
// slog 是并发安全的
go slog.Info("goroutine 1")
go slog.Info("goroutine 2")
5. 性能考虑
// 使用 Enabled 检查避免不必要的计算
if logger.Enabled(context.Background(), slog.LevelDebug) {
logger.Debug("详细信息", "data", expensiveJSON())
}
十、完整示例:日志中间件
package main
import (
"context"
"log/slog"
"net/http"
"os"
"time"
)
// RequestLogger 请求日志中间件
func RequestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 创建请求 logger
logger := slog.With(
"request_id", generateRequestID(),
"method", r.Method,
"path", r.URL.Path,
"remote_addr", r.RemoteAddr,
)
// 记录请求开始
logger.Info("请求开始")
// 包装 ResponseWriter 以捕获状态码
rw := &responseWriter{ResponseWriter: w, statusCode: 200}
// 调用下一个 handler
next.ServeHTTP(rw, r)
// 记录请求完成
logger.Info("请求完成",
"status", rw.statusCode,
"duration_ms", time.Since(start).Milliseconds(),
"bytes_written", rw.bytesWritten,
)
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
bytesWritten int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
func (rw *responseWriter) Write(b []byte) (int, error) {
n, err := rw.ResponseWriter.Write(b)
rw.bytesWritten += n
return n, err
}
func generateRequestID() string {
// 简化实现
return "req-123"
}
func main() {
// 设置日志格式
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
AddSource: true,
})
slog.SetDefault(slog.New(handler))
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
slog.Info("处理首页")
w.Write([]byte("Hello World"))
})
http.ListenAndServe(":8080", RequestLogger(mux))
}
最后更新: 2026-04-04
Go 版本: 1.21+
包文档: https://pkg.go.dev/log/slog