当前位置: 首页 > news >正文

With 注入通用属性

时,可以用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% 的性能提升:

http://www.jsqmd.com/news/1093079/

相关文章:

  • 动画角色机器人化:从《冰雪奇缘》Olaf看强化学习与机械设计创新
  • 基于复合粒子群优化的模糊神经预测控制的研究附Matlab代码
  • go-sqlmock
  • AI数字人平台热门十三问|必火AI数字人全维度专业解答
  • 如何高效优化电子书阅读体验:Kindle Comic Converter的完整漫画转换方案
  • 卡梅德生物技术快报|羊驼纳米抗体文库筛选实操全流程:天然 / 合成文库构建与淘选参数汇总
  • Windows虚拟显示器终极指南:Parsec VDD免费开源解决方案
  • 从 0 开始学 Python:装好环境,写一下demo实例
  • Kali Linux下使用apk2url从APK提取URL与IP的实战指南
  • 高效智能的网盘直链下载解决方案:一站式专业级工具LinkSwift深度解析
  • GPU硬件故障排查终极指南:5分钟完成显卡内存稳定性检测
  • 收藏!小白程序员必看:如何将大模型Agent从Demo成功落地工程实践?
  • 2026年大模型知识库优化实战?GEO策略如何重塑TOB品牌获客新路径
  • 收藏!小白程序员必看:一文搞懂AI Agent核心原理与实战代码
  • [Android] iVCam(手机变电脑摄像头)专业版
  • 01 TCP 协议是流式协议
  • Lean 4实战指南:5个步骤掌握下一代定理证明编程语言
  • Fatal error: require(): Failed opening required...” 以及如何彻底避免它再次出现
  • 2026年AI Agent大爆发!小白程序员必看:收藏这份从入门到精通指南,抓住时代红利!
  • 5个技巧轻松解决经典游戏兼容问题:开源dxwrapper完全指南
  • Vibe Coding:说人话就能做软件,超简单开发流程全讲明白
  • Netty 高性能网络编程:从零构建高并发服务器
  • 【TSP问题】基于帝企鹅算法AFO求解单仓库多旅行商问题MTSP附Matlab代码
  • XSS防御实战:从同源策略到CSP的纵深安全体系构建
  • Kafka2.4-Windows安装教程
  • 无需同看同一张图:跨被试神经表征对齐的VAE新范式
  • 一文吃透Java IO流!从底层原理到实战代码(新手必看)
  • 只有 B 级能力的大模型,怎么干出 A 级的活?
  • 续流二极管:电机断电瞬间的“高压泄洪道”
  • 容器化 Java 应用 CPU 使用率监控口径解析:node exporter vs cAdvisor vs JMX