Go 标准库 log 包仅适合轻量级单进程调试,不支持分级、滚动、多目标或结构化字段,无法满足日志收集需求;推荐换用 zap 或 zerolog 等结构化日志库。
Go 标准库 log 包适合轻量级、单进程的日志记录,但**不支持日志分级、滚动切片、多输出目标或结构化字段**——直接用它做“日志收集”会很快遇到瓶颈。
log.Printf 做日志收集标准 log 是同步写入、无缓冲、无级别控制的简单封装。常见问题包括:
log.Output,无法区分 INFO/ERROR 并路由到不同文件或网络端点os.OpenFile + log.SetOutput 手动轮转极易丢失日志或并发写冲突[date] [prefix] msg,不兼容 JSON 或 Fluentd 等采集器要求log.SetOutput + io.MultiWriter 实现基础多目标输出若暂时不能引入第三方库,可组合标准包实现“一份日志同时写文件和 stderr”:
file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) multi := io.MultiWriter(file, os.Stderr) log.SetOutput(multi)
注意:
os.Stderr 是行缓冲的,file 是全缓冲的,混用可能导致日志顺序错乱(尤其 panic 时)file.Close(),否则进程退出时可能丢最后几条日志log.New 构造带前缀的专用 logger(避免全局污染)全局 log 不利于模块隔离。推荐每个子系统用独立 logger:
dbLogger := log.New(os.Stdout, "[DB] ", log.LstdFlags|log.Lshortfile) httpLogger := log.New(os.Stdout, "[HTTP] ", log.LstdFlags|log.Lshortfile)
关键点:
[DB]2025/05/01... 会粘连log.Lshortfile 开销较大,生产环境慎用;调试阶段可加,上线建议去掉log.New 中传入未同步的 io.Writer(如未加锁的 bytes.Buffer),并发写会 paniczap 或 zerolog
标准 log 的定位是“快速打点调试”,不是日志收集系统。实际项目中应切换:
zap:高性能、结构化、支持 hooks(可对接 Loki / ES / Kafka)zerolog:零内存分配、API 简洁,JSON 输出开箱即用例如用 zerolog 输出带 trace ID 的 JSON:
log.Logger = log.With().Str("trace_id", "abc123").Logger()
log.Info().Str("event", "user_login").Int("user_id", 1001).Send()
这段输出是标准 JSON 行,可被 Filebeat、Vector 直接解析——这才是日志收集链路的起点。
标准 log 的最大陷阱,是让人误以为“能打印就算完成日志工作”。真正的收集,从输出格式、字段语义、写入可靠性,到采集器兼容性,每一步都绕不开结构化与可扩展性设计。