
log.Fatalln 会立即终止程序,因此后续代码(如 fmt.Print(&buf))不会执行;若需在退出前确保日志输出,必须将 logger 输出目标设为标准错误流(如 os.Stderr)或显式刷新缓冲区。
`log.fatalln` 会立即终止程序,因此后续代码(如 `fmt.print(&buf)`)不会执行;若需在退出前确保日志输出,必须将 logger 输出目标设为标准错误流(如 `os.stderr`)或显式刷新缓冲区。
在 Go 语言中,log.Fatal* 系列函数(如 Fatalln、Fatalf、Fatal)并非仅记录日志后返回,而是在写入日志后调用 os.Exit(1) 强制终止进程。这是其设计本质——用于不可恢复的严重错误场景。因此,任何位于 Fatalln 调用之后的语句(包括 fmt.Print(&buf))永远不会被执行,这正是示例中第二行 fmt.Print(&buf) 消失的根本原因。
关键误区在于:logInfo.Fatalln("Ut oh") 并非“没输出”,而是它确实尝试向 &buf 写入了日志,但紧接着进程就退出了,导致缓冲区内容来不及被读取或打印。由于 bytes.Buffer 是内存中的临时载体,且未被显式读取(如 buf.String()),其内容在进程终止时即被丢弃。
✅ 正确做法是:将 logger 的输出目标设为持久化或即时可见的 io.Writer,最常用且符合 Unix 哲学的方式是 os.Stderr:
package main
import (
"log"
"os"
)
func main() {
// 使用 os.Stderr 作为输出目标,确保 Fatalln 日志可立即看到
logInfo := log.New(os.Stderr, "[Info] ", log.Lshortfile)
logInfo.Print("Hello, log file!")
logInfo.Printf("Hello, %s", "crazy")
logInfo.Fatalln("Ut oh") // ✅ 此行会输出并立即退出,终端可见全部三行
}运行结果(终端直接输出):
立即学习“go语言免费学习笔记(深入)”;
[Info] main.go:12: Hello, log file! [Info] main.go:13: Hello, crazy [Info] main.go:14: Ut oh exit status 1
⚠️ 注意事项:
- log.New(w, prefix, flag) 中的 w 必须支持即时写入;bytes.Buffer 适合捕获日志做断言测试,但不适用于 Fatal 类操作(除非你主动调用 buf.String() 在 Fatalln 前完成读取)。
- 若仍需使用缓冲器并兼容 Fatalln,可手动刷新+panic 替代(不推荐,破坏标准行为):
logInfo.Println("Ut oh") fmt.Print(buf.String()) // 显式输出缓冲内容 os.Exit(1) - 所有 log.Fatal* 函数等价于 log.Print() + os.Exit(1),无异常捕获机制,不可被 defer 或 recover 拦截。
总结:理解 Fatalln 的“写入+退出”原子性是使用自定义 logger 的前提。生产环境中,应始终将关键 logger(尤其是含 Fatal 方法的实例)配置为输出到 os.Stderr 或日志文件,避免依赖内存缓冲器,确保错误信息不丢失。










