时,可以用With方法为 logger 添加通用属性。这些属性会自动附加到每条日志记录中,适合注入服务名、环境、版本等上下文信息。
package main import ( "fmt" "log/slog" "os" "time" ) func main() { jsonLogger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ AddSource: true, Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { if t, ok := a.Value.Any().(time.Time); ok { a.Value = slog.StringValue(t.Format(time.RFC3339)) } } if a.Key == slog.SourceKey { source := a.Value.Any().(*slog.Source) shortFile := source.File for i := len(source.File) - 1; i > 0; i-- { if source.File[i] == '/' { shortFile = source.File[i+1:] break } } return slog.String("source", fmt.Sprintf("%s:%d", shortFile, source.Line)) } return a }, })).With("logger", "json", "env", "production") jsonLogger.Debug("Hello world") jsonLogger.Info("Hello world") jsonLogger.Warn("Hello world") jsonLogger.Error("Hello world") jsonLogger.Info("this is a message", "name", "zhangsan") }运行输出:
$ go run main.go {"time":"2026-02-15T13:24:38+08:00","level":"DEBUG","source":"main.go:42","msg":"Hello world","logger":"json","env":"production"} {"time":"2026-02-15T13:24:38+08:00","level":"INFO","source":"main.go:43","msg":"Hello world","logger":"json","env":"production"} {"time":"2026-02-15T13:24:38+08:00","level":"WARN","source":"main.go:44","msg":"Hello world","logger":"json","env":"production"} {"time":"2026-02-15T13:24:38+08:00","level":"ERROR","source":"main.go:45","msg":"Hello world","logger":"json","env":"production"} {"time":"2026-02-15T13:24:38+08:00","level":"INFO","source":"main.go:47","msg":"this is a message","logger":"json","env":"production","name":"zhangsan"}使用 Group 对属性分组
当日志属性较多时,可以使用slog.Group将相关属性组织在一起,使输出结构更清晰:
package main import ( "fmt" "log/slog" "os" "time" ) func main() { jsonLogger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ AddSource: true, Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { if t, ok := a.Value.Any().(time.Time); ok { a.Value = slog.StringValue(t.Format(time.RFC3339)) } } if a.Key == slog.SourceKey { source := a.Value.Any().(*slog.Source) shortFile := source.File for i := len(source.File) - 1; i > 0; i-- { if source.File[i] == '/' { shortFile = source.File[i+1:] break } } return slog.String("source", fmt.Sprintf("%s:%d", shortFile, source.Line)) } return a }, })) jsonLogger = jsonLogger.With("logger", "json") // 使用 Group 组织相关属性 jsonLogger.Info("系统状态", slog.Group("metrics", slog.Int("cpu", 4), slog.Float64("memPercent", 2.33), ), slog.Group("request", slog.String("method", "GET"), slog.String("path", "/api/users"), ), ) }运行输出:
$ go run main.go {"time":"2026-02-15T13:30:08+08:00","level":"INFO","source":"main.go:43","msg":"系统状态","logger":"json","metrics":{"cpu":4,"memPercent":2.33},"request":{"method":"GET","path":"/api/users"}}高性能场景使用 LogAttrs
如果需要在高性能循环中打印日志,建议使用LogAttrs方法。它使用强类型属性(slog.Attr),避免了反射带来的性能开销。
package main import ( "context" "log/slog" "os" "time" ) func main() { jsonLogger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ AddSource: true, Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { if t, ok := a.Value.Any().(time.Time); ok { a.Value = slog.StringValue(t.Format(time.RFC3339)) } } if a.Key == slog.SourceKey { source := a.Value.Any().(*slog.Source) shortFile := source.File for i := len(source.File) - 1; i > 0; i-- { if source.File[i] == '/' { shortFile = source.File[i+1:] break } } return slog.String("source", fmt.Sprintf("%s:%d", shortFile, source.Line)) } return a }, })).With("logger", "json") for i := range 5 { jsonLogger.LogAttrs( context.Background(), slog.LevelInfo, "执行遍历", slog.Int("round", i), slog.String("task_name", "cleanup"), slog.Duration("duration", time.Second*time.Duration(i+1)), ) } }运行输出:
$ go run main.go {"time":"2026-02-15T13:38:21+08:00","level":"INFO","source":"main.go:45","msg":"执行遍历","logger":"json","round":0,"task_name":"cleanup","duration":1000000000} {"time":"2026-02-15T13:38:21+08:00","level":"INFO","source":"main.go:45","msg":"执行遍历","logger":"json","round":1,"task_name":"cleanup","duration":2000000000} {"time":"2026-02-15T13:38:21+08:00","level":"INFO","source":"main.go:45","msg":"执行遍历","logger":"json","round":2,"task_name":"cleanup","duration":3000000000} {"time":"2026-02-15T13:38:21+08:00","level":"INFO","source":"main.go:45","msg":"执行遍历","logger":"json","round":3,"task_name":"cleanup","duration":4000000000} {"time":"2026-02-15T13:38:21+08:00","level":"INFO","source":"main.go:45","msg":"执行遍历","logger":"json","round":4,"task_name":"cleanup","duration":5000000000}性能对比
根据官方基准测试,LogAttrs相比普通方法调用有约 30% 的性能提升: