Go日志框架slog使用入门与结构化日志解析
slog是Go 1.21版本引入的标准库结构化日志包(log/slog
),它提供了结构化日志记录功能,比传统的log
包更强大和灵活。
1. slog基础使用
1.1 快速开始
package main
import (
"log/slog"
"os"
)
func main() {
// 默认的文本处理器
slog.Info("hello world")
slog.Error("oops", "status", 500, "err", "file not found")
// 创建JSON格式的日志处理器
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("hello world", "user", "John")
}
1.2 日志级别
slog定义了以下日志级别:
const (
LevelDebug Level = -4
LevelInfo Level = 0
LevelWarn Level = 4
LevelError Level = 8
)
使用示例:
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Debug("debug message") // 默认不显示
logger.Info("info message")
logger.Warn("warning message")
logger.Error("error message")
2. 结构化日志
2.1 添加属性
logger.Info(
"user login",
"user_id", 12345,
"ip", "192.168.1.1",
"success", true,
)
2.2 使用slog.Attr
更高效的方式是使用slog.Attr
:
logger.LogAttrs(
context.Background(),
slog.LevelInfo,
"user login",
slog.Int("user_id", 12345),
slog.String("ip", "192.168.1.1"),
slog.Bool("success", true),
)
2.3 分组属性
logger.Info(
"request completed",
slog.Group("request",
slog.String("method", "GET"),
slog.String("path", "/api/users"),
),
slog.Group("response",
slog.Int("status", 200),
slog.Duration("duration", 123*time.Millisecond),
),
)
3. 处理器(Handler)配置
3.1 文本处理器
handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug, // 设置日志级别
AddSource: true, // 添加源文件位置
})
logger := slog.New(handler)
3.2 JSON处理器
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
logger := slog.New(handler)
3.3 自定义处理器
type CustomHandler struct {
slog.Handler
}
func (h *CustomHandler) Handle(ctx context.Context, r slog.Record) error {
// 自定义处理逻辑
fmt.Printf("[%s] %s\n", r.Level, r.Message)
return nil
}
func main() {
handler := &CustomHandler{
Handler: slog.NewJSONHandler(os.Stdout, nil),
}
logger := slog.New(handler)
logger.Info("custom handler message")
}
4. 上下文集成
func handleRequest(w http.ResponseWriter, r *http.Request) {
logger := slog.FromContext(r.Context())
logger.Info("request handled", "path", r.URL.Path)
}
func main() {
handler := slog.NewJSONHandler(os.Stdout, nil)
logger := slog.New(handler)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = slog.NewContext(ctx, logger.With("request_id", "12345"))
handleRequest(w, r.WithContext(ctx))
})
http.ListenAndServe(":8080", nil)
}
5. 日志解析
由于slog输出的是结构化日志,解析起来非常方便:
5.1 JSON日志解析示例
type LogEntry struct {
Time time.Time `json:"time"`
Level string `json:"level"`
Message string `json:"msg"`
UserID int `json:"user_id,omitempty"`
IP string `json:"ip,omitempty"`
}
func parseLogLine(line string) (*LogEntry, error) {
var entry LogEntry
err := json.Unmarshal([]byte(line), &entry)
if err != nil {
return nil, err
}
return &entry, nil
}
5.2 使用日志收集系统
结构化日志可以轻松集成到日志收集系统如ELK、Loki、Splunk等。
6. 实践
- 始终使用结构化日志:避免使用fmt.Sprintf构建日志消息
- 合理设置日志级别:生产环境通常使用Info级别
- 添加有用的上下文:请求ID、用户ID等有助于追踪问题
- 避免敏感信息:不要在日志中记录密码、令牌等
- 性能考虑:对于高频日志,使用LogAttrs比传递键值对更高效
7. 与第三方日志库比较
| 特性 | slog | logrus | zap |
|------------|------|--------|-----|
| 结构化日志 | ✅ | ✅ | ✅ |
| 标准库 | ✅ | ❌ | ❌ |
| 高性能 | 中等 | 低 | 高 |
| 上下文支持 | ✅ | ✅ | ✅ |
| 日志级别 | ✅ | ✅ | ✅ |
slog作为标准库,虽然性能不如zap,但提供了良好的平衡性和未来兼容性。
slog为Go带来了现代化的结构化日志记录能力,是未来Go日志记录的标准方式。通过合理使用slog,可以大大提高日志的可读性和可维护性,同时为日志分析和监控提供更好的支持。
(本文地址:https://www.nzw6.com/6819.html)