闽公网安备 35020302035485号
在本文中,我将简单介绍 slog 包、它的功能以及如何在 Go 应用程序中使用它。
slog 提供结构化日志记录,其中的日志记录包括一条消息、level 和其他各种以键值对表示的属性。
import "log/slog"这里写一个非常简单的例子:
func main() {
slog.Info("hello, world!", "coding", "happy")
}
输出:2023/09/15 13:42:27 INFO hello, world! coding=happy
func main() {
// 堆代码 duidaima.com
textHandler := slog.NewTextHandler(os.Stdout, nil)
textLogger := slog.New(textHandler)
textLogger.Info("TextDemo",
slog.String("app-version", "v0.0.1"),
slog.Int("release-version", 1),
)
jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
jsonLogger := slog.New(jsonHandler)
jsonLogger.Info("JsonDemo",
slog.String("app-version", "v0.0.1"),
slog.Int("release-version", 1),
)
}
输出为:time=2023-09-15T13:48:37.424+08:00 level=INFO msg=TextDemo app-version=v0.0.1 release-version=1
{"time":"2023-09-15T13:48:37.4647782+08:00","level":"INFO","msg":"JsonDemo","app-version":"v0.0.1","release-version":1}
从上面我们可以看到,代码中使用了类似slog.String的方法,slog提供了指定属性的功能。有多种类型的属性可供选择:func main() {
jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
jsonLogger := slog.New(jsonHandler)
jsonLogger.Info(
"attributes",
slog.String("version", "1.0.0"),
slog.Int("app-version", 1),
slog.Float64("point-value", 1.2),
slog.Bool("status", true),
slog.Duration("duration", time.Hour*1),
slog.Time("time", time.Now()),
slog.Group(
"request",
slog.String("path", "<https://example.com>"),
slog.String("method", "get"),
),
)
}
对应的输出,我已经将其格式化了:{
"time": "2023-09-15T13:53:43.8848272+08:00",
"level": "INFO",
"msg": "attributes",
"version": "1.0.0",
"app-version": 1,
"point-value": 1.2,
"status": true,
"duration": 3600000000000,
"time": "2023-09-15T13:53:43.8848272+08:00",
"request": {
"path": "<https://example.com>",
"method": "get"
}
}
func main() {
jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
jsonLogger := slog.New(jsonHandler)
jsonLogger.Debug("Hello, world!")
jsonLogger.Info("Hello, world!")
jsonLogger.Warn("Hello, world!")
jsonLogger.Error("Hello, world!")
}
NOTE: 记得在NewHandler时设置级别。func main() {
jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
jsonLogger := slog.New(jsonHandler).WithGroup("request")
jsonLogger.Info("",
slog.String("url", "<https://example.com>"),
slog.String("method", "GET"),
slog.Int("response-code", 200),
)
}
这里有个比较好的实践:type Handler interface {
Enabled(Level) bool
Handle(Record) error
WithAttrs([]Attr) Handler
WithGroup(string) Handler
}
下面举例说明如何创建一个将日志信息写入文件的自定义handler:type FileHandler struct {
file *os.File
}
func NewFileHandler(filename string) (*FileHandler, error) {
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
return &FileHandler{file}, nil
}
func (h *FileHandler) Enabled(_ context.Context, level slog.Level) bool {
return true
}
func (h *FileHandler) Handle(_ context.Context, record slog.Record) error {
_, err := h.file.WriteString(record.Message + "\n")
return err
}
func (h *FileHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return h
}
func (h *FileHandler) WithGroup(name string) slog.Handler {
return h
}
func (h *FileHandler) Close() error {
return h.file.Close()
}
func main() {
fileHandler, err := NewFileHandler("log.log")
if err != nil {
panic(err)
}
defer fileHandler.Close()
logger := slog.New(fileHandler)
logger.Info("Hello, world!")
logger.Debug("Debugging errors")
}
这个时候运行程序时,控制台就不会有对应的日志输出了,而是输出到对应文件上:slogDemo cat .\log.log Hello, world! Debugging errors总结