go语言.浅析log.Println和fmt.Println

这是一个很自然的直觉——表面上看确实像(都是控制台打印一行字),但本质上它们不一样,只是底层都绕不开"往一个输出目标写字节"这件事。准确的说法是:它俩有共同的底层机制,但定位和能力差别很大。

相同点(让你觉得"一样"的原因)

  • 最终都调用底层的写入操作,把格式化后的字节送到一个 io.Writer;
  • 终端里直接运行时,肉眼看到的输出位置几乎相同;
  • 参数风格类似,都是 Println(x...)。

本质区别

维度 fmt.Println log.Println
定位 格式化输出工具,负责"把数据按格式变成文本" 日志工具,负责"记录带上下文的运行信息"
默认去向 标准输出 os.Stdout 标准错误 os.Stderr
时间前缀 无 默认带 日期 时间
输出目标可否全局切换 不能,每次得显式指定 Writer log.SetOutput() 一改全局生效
换行 自动加 自动加
设计层级 底层原语,log 内部格式化也借助 fmt 的能力 建立在 fmt 之上的"应用层"设施

一个关键事实:log 包内部其实就是在用 fmt 来做格式化。所以不是平级的两个东西,而更像 fmt 是"写字"的基础能力,log 是在它外面包了一层"日志该有的样子"(时间戳、统一出口、logger 实例)。

举个具体例子

fmt.Println("完毕")
// 完毕

log.Println("完毕")
// 2026/10/04 10:00:00 完毕

输出内容本身就不同——log 多了时间戳,这就是"日志"和"普通输出"最直观的分野。

怎么选用(这才是重点)

  • 程序的正常结果、要给下游/管道消费的内容 → 用 fmt(走 stdout)。比如 CLI 工具输出查询结果、打印生成的文本。
  • 给人看的运行过程、诊断、报错信息 → 用 log(走 stderr)。比如"连接成功""处理到第几个""出错了"。

这样分流的好处在重定向时才真正体现:

go run . >result.txt 2>error.log

程序结果干净地进 result.txt,日志诊断进 error.log,互不污染。如果两者都用 fmt 打到 stdout,就没法这样分离了。、

go run . 2>err.log     # 只把 stderr(log 的内容)收进 err.log
go run . >out.log      # 只把 stdout(fmt 的内容)收进 out.log

在 VS Code/Trae 这类 IDE 的调试控制台、输出面板里,两个流通常也会被合并展示。

另外想改去向:log.SetOutput

log.SetOutput(os.Stdout)                  // 改为标准输出
log.SetOutput(f)                          // 改为某个文件
log.SetOutput(io.MultiWriter(f, os.Stderr)) // 文件和控制台同时写

一句话总结

底层"写字节"的机制相同,但 fmt 是通用格式化输出,log 是带时间戳、走 stderr、可统一配置出口的专用日志设施——后者是前者之上的一层封装。 把它们当成"同一个东西"在小程序里不会出问题,但养成"结果用 fmt、日志用 log"的习惯,对以后写服务很重要。

posted @ 2026-10-04 16:37  海利鸟  阅读(2)  评论(0)    收藏  举报