golang新一代标准日志库slog

log/slog 是 Go 1.21 引入的一个新的日志记录包,旨在提供比传统 log 包更灵活和现代化的日志功能。它支持结构化日志、可配置的日志级别、灵活的日志输出格式等功能,弥补了旧版 log 包的不足。

对比旧版 log 包

特性 log slog
日志级别支持 内置支持(Debug、Info 等)
结构化日志 支持键值对记录
日志格式 简单文本 文本或 JSON 格式
可扩展性 支持自定义处理器
性能和灵活性

使用方法

1. 创建日志记录器

slog 的核心是 Logger,可以通过默认记录器或自定义记录器来记录日志

使用默认日志记录器示例

func main() {
// 使用默认日志记录器,此模式日志输出格式为text文本型,且不会输出Debug级别日志
    logger := slog.Default()

// 输出结构化日志
    logger.Debug("This is a debug message")
    logger.Info("Starting qkp platform log","version","v3.2.2")
    logger.Warn("Low disk space","remaining","500MB")
    logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
}
2024/12/08 21:55:08 INFO Starting qkp platform log version=v3.2.2
2024/12/08 21:55:08 WARN Low disk space remaining=500MB
2024/12/08 21:55:08 ERROR Failed to connect to ETCD cluster error="connection timeout"

2. 日志级别控制

slog 支持以下日志级别

  • slog.LevelDebug
  • slog.LevelInfo
  • slog.LevelWarn
  • slog.LevelError

HandlerOptions 是 log/slog 提供的一种配置结构,用于自定义日志处理器的行为。通过配置 HandlerOptions,可以实现日志的源位置跟踪、日志级别动态调整,以及对日志属性的定制化处理,参数包括如下:

  • AddSource:启用源代码位置记录,便于定位日志位置
  • Level:控制日志级别,可静态或动态调整
  • ReplaceAttr:修改、移除或过滤属性,支持灵活的日志定制

按照日志级别控制,并输出JSON格式

package main

import(
"log/slog"
"os"
)

func main(){
    handler := slog.NewJSONHandler(os.Stdout,&slog.HandlerOptions{
Level: slog.LevelDebug,
})

    logger := slog.New(handler)

// 输出结构化日志
    logger.Debug("This is a debug message")
    logger.Info("Starting qkp platform log","version","v3.2.2")
    logger.Warn("Low disk space","remaining","500MB")
    logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
}
{"time":"2024-12-08T22:04:02.194775+08:00","level":"DEBUG","msg":"This is a debug message"}
{"time":"2024-12-08T22:04:02.195138+08:00","level":"INFO","msg":"Starting qkp platform log","version":"v3.2.2"}
{"time":"2024-12-08T22:04:02.195144+08:00","level":"WARN","msg":"Low disk space","remaining":"500MB"}
{"time":"2024-12-08T22:04:02.195149+08:00","level":"ERROR","msg":"Failed to connect to ETCD cluster","error":"connection timeout"}

3. 自定义日志处理器(Handler)

slog.Handler 是日志输出的核心接口,允许自定义日志处理行为 内置处理器

  • slog.NewTextHandler: 以文本形式输出日志(默认格式)
  • slog.NewJSONHandler: 以 JSON 格式输出日志

4. 使用上下文记录器

slog 支持通过上下文管理附加信息

package main

import(
"log/slog"
"os"
)

func main(){
    handler := slog.NewJSONHandler(os.Stdout,&slog.HandlerOptions{
Level: slog.LevelDebug,
})

    logger := slog.New(handler).With("platform","qkp","version","v3.2.2")

// 输出结构化日志
    logger.Debug("This is a debug message")
    logger.Info("Starting qkp platform log","version","v3.2.2")
    logger.Warn("Low disk space","remaining","500MB")
    logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
}
{"time":"2024-12-08T22:09:02.400349+08:00","level":"DEBUG","msg":"This is a debug message","platform":"qkp","version":"v3.2.2"}
{"time":"2024-12-08T22:09:02.400673+08:00","level":"INFO","msg":"Starting qkp platform log","platform":"qkp","version":"v3.2.2","version":"v3.2.2"}
{"time":"2024-12-08T22:09:02.400678+08:00","level":"WARN","msg":"Low disk space","platform":"qkp","version":"v3.2.2","remaining":"500MB"}
{"time":"2024-12-08T22:09:02.400682+08:00","level":"ERROR","msg":"Failed to connect to ETCD cluster","platform":"qkp","version":"v3.2.2","error":"connection timeout"}

5. 集成lumberjack进行日志切片和归档

package main

import(
"gopkg.in/natefinch/lumberjack.v2"
"log/slog"
)

func main(){
// 配置 lumberjack 日志归档
    lumberjackLogger :=&lumberjack.Logger{
Filename:"/tmp/app.log",// 日志文件路径
MaxSize:10,// 单个日志文件最大大小(单位:MB)
MaxBackups:5,// 保留的旧日志文件个数
MaxAge:30,// 保留的旧日志文件最大天数(单位:天)
Compress:true,// 是否压缩旧日志文件
}

    handler := slog.NewJSONHandler(lumberjackLogger,&slog.HandlerOptions{
AddSource:true,// 如果设置为 true,日志输出中将包含源代码的位置(文件名和行号),默认值:false(不记录源位置)
Level:     slog.LevelDebug,
})

    logger := slog.New(handler).With("platform","qkp","version","v3.2.2")

// 输出结构化日志
    logger.Debug("This is a debug message")
    logger.Info("Starting qkp platform log","version","v3.2.2")
    logger.Warn("Low disk space","remaining","500MB")
    logger.Error("Failed to connect to ETCD cluster","error","connection timeout")

在/tmp目录下查询app.log日志

cat /tmp/app.log
{"time":"2024-12-08T22:17:46.720471+08:00","level":"DEBUG","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":42},"msg":"This is a debug message","platform":"qkp","version":"v3.2.2"}
{"time":"2024-12-08T22:17:46.720688+08:00","level":"INFO","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":43},"msg":"Starting qkp platform log","platform":"qkp","version":"v3.2.2","version":"v3.2.2"}
{"time":"2024-12-08T22:17:46.720696+08:00","level":"WARN","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":44},"msg":"Low disk space","platform":"qkp","version":"v3.2.2","remaining":"500MB"}
{"time":"2024-12-08T22:17:46.720702+08:00","level":"ERROR","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":45},"msg":"Failed to connect to ETCD cluster","platform":"qkp","version":"v3.2.2","error":"connection timeout"}

6. 结合归档日志级别以及替换关键字格式化日志

package main

import(
"gopkg.in/natefinch/lumberjack.v2"
"log/slog"
)

func main(){
// 配置 lumberjack 日志归档
    lumberjackLogger :=&lumberjack.Logger{
        Filename:"/tmp/app.log",// 日志文件路径
        MaxSize:10,// 单个日志文件最大大小(单位:MB)
        MaxBackups:5,// 保留的旧日志文件个数
        MaxAge:30,// 保留的旧日志文件最大天数(单位:天)
        Compress:true,// 是否压缩旧日志文件
    }

    handler := slog.NewJSONHandler(lumberjackLogger,&slog.HandlerOptions{
        AddSource:true,// 如果设置为 true,日志输出中将包含源代码的位置(文件名和行号),默认值:false(不记录源位置)
        Level:     slog.LevelDebug,
        ReplaceAttr:func(groups []string, a slog.Attr) slog.Attr{
            // 替换关键字platform 的值从qkp变成kubernetes
            if a.Key=="platform"{
                return slog.Attr{Key: a.Key,Value: slog.StringValue("kubernetes")}
            }
            return a
        },
    })

    logger := slog.New(handler).With("platform","qkp","version","v3.2.2")

    // 输出结构化日志
    logger.Debug("This is a debug message")
    logger.Info("Starting qkp platform log","version","v3.2.2")
    logger.Warn("Low disk space","remaining","500MB")
    logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
}

输出结果:

{"time":"2024-12-08T22:28:49.965694+08:00","level":"DEBUG","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":49},"msg":"This is a debug message","platform":"kubernetes","version":"v3.2.2"}
{"time":"2024-12-08T22:28:49.966204+08:00","level":"INFO","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":50},"msg":"Starting qkp platform log","platform":"kubernetes","version":"v3.2.2","version":"v3.2.2"}
{"time":"2024-12-08T22:28:49.966243+08:00","level":"WARN","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":51},"msg":"Low disk space","platform":"kubernetes","version":"v3.2.2","remaining":"500MB"}
{"time":"2024-12-08T22:28:49.966259+08:00","level":"ERROR","source":{"function":"main.main","file":"/Users/hurricane/github/test01/main.go","line":52},"msg":"Failed to connect to ETCD cluster","platform":"kubernetes","version":"v3.2.2","error":"connection timeout"}

原文阅读