Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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
    • 支持日志级别过滤
  • 用途:记录结构化日志

方法总览:

方法参数返回值描述
Debugmsg string, attrs ...any记录 Debug 级别日志
Infomsg string, attrs ...any记录 Info 级别日志
Warnmsg string, attrs ...any记录 Warn 级别日志
Errormsg string, attrs ...any记录 Error 级别日志
Logctx context.Context, level Level, msg string, attrs ...any记录指定级别日志
LogAttrsctx context.Context, level Level, msg string, attrs ...Attr记录指定级别日志(Attr 类型)
Withattrs ...any*Logger创建带属性的新 Logger
WithGroupname string*Logger创建带分组的 Logger
Enabledctx context.Context, level Levelbool检查级别是否启用
HandlerHandler获取 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日志处理器接口
JSONHandlerJSON 格式处理器
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调试信息
LevelInfo0普通信息
LevelWarn4警告信息
LevelError8错误信息

格式对比

格式优点缺点适用场景
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