上一篇文章讲解了 log/slog 包中的自定义日志属性字段和日志级别,本文讲解下分组、上下文和属性值类型
slog 支持将字段放在组中并且可以给分组指定名称。如何展示分组的内容,取决于使用的 handler,例如 TextHandler 使用点号分隔组名和属性,JSONHandler 将每个组视为单独的 JSON 对象,并以组名作为键。分别看下 TextHandler 和 JSONHandler 的示例。
TextHandler:
package main
import (
"log/slog"
"os"
)
func main() {
h := slog.NewTextHandler(os.Stdout, nil)
logger := slog.New(h)
logger = logger.WithGroup("request")
logger.Info("路多辛的博客", "method", "post", "url", "xxx.com/post")
}
输出内容如下:
time=2023-09-24T18:17:45.642+08:00 level=INFO msg=路多辛的博客 request.method=post request.url=xxx.com/post
JSONHandler:
package main
import (
"log/slog"
"os"
)
func main() {
h := slog.NewJSONHandler(os.Stdout, nil)
logger := slog.New(h)
logger = logger.WithGroup("request")
logger.Info("路多辛的博客", "method", "post", "url", "xxx.com/post")
}
输出内容如下:
{"time":"2023-09-24T18:19:39.025697+08:00","level":"INFO","msg":"路多辛的博客","request":{"method":"post","url":"xxx.com/post"}}
一些 handler 或者自定义的 handlers 可能希望得到包含上下文(context.Context)的信息,例如链路追踪的场景,需要从上下文中获取到当前的 span 信息。slog 包提供了对这种场景的支持,Logger.log 和 Logger.LogAttrs 方法将 context.Context 类型的参数作为第一个参数,还有记录几种级别日志的方法,都同时提供了带上下文的方法,对应的方法就是后面跟上 Context。简单示例如下:
package main
import (
"context"
"log/slog"
)
func main() {
slog.InfoContext(context.Background(), "路多辛的博客")
}
属性是一个键值对,日志输出方法接受交替出现的属性和值,例如:
package main
import (
"log/slog"
)
func main() {
slog.Info("路多辛的博客", "count", 3)
}
也可写为如下形式:
package main
import (
"log/slog"
)
func main() {
slog.Info("路多辛的博客", slog.Int("count", 3))
}
这里的 slog.Int 返回一个 slog.Attr 类型的值,slog.Attr 用来表示一个键值对。 slog 还提供了生成其他类型的键值对的函数,例如 float、string 和 Bool 等,属性的值是 slog.Value 类型,像 any 一样,Value 可以保存任何值。要获得最高效的日志输出,可以使用 Logger.LogAttrs,只接受 slog.Attr 类型的日志内容,不接受键值交替出现的值。例如:
package main
import (
"context"
"log/slog"
"os"
)
func main() {
h := slog.NewTextHandler(os.Stdout, nil)
logger := slog.New(h)
logger = logger.WithGroup("request")
logger.LogAttrs(context.Background(), slog.LevelInfo, "路多辛的博客", slog.Int("count", 3))
}
输出效果和如下的代码是一样的:
package main
import (
"log/slog"
)
func main() {
slog.Info("路多辛的博客", "count", 3)
}