必须显式调用 glog.flush() 才能确保 glog.errorf 记录的日志写入指定文件,否则因缓冲机制未刷盘,日志会丢失或落入 /var/log/messages。

直接写 glog.Errorf 或 log.Printf 不会自动落盘到你指定的日志文件——必须显式刷新缓冲区或正确配置输出目标,否则日志大概率进 /var/log/messages 或丢弃。
glog.Errorf 后不写入文件?缺 glog.Flush()
glog 默认启用内存缓冲,glog.Errorf 只把日志塞进缓冲区,不主动刷盘。panic 被 recover() 捕获后,goroutine 继续执行,但若没调用 glog.Flush(),缓冲区内容会在函数返回时被丢弃,不会写入 -log_dir 下的 ERROR 文件。
- 必须在
recover()之后、函数返回前立即调用glog.Flush() -
glog.Flush()是同步阻塞操作,但在 panic 恢复路径中开销可接受 - 若使用多个
defer,确保glog.Flush()在日志记录之后、且不会被后续 panic 中断 - 启动程序时务必传
-log_dir=./logs,否则glog退回到 stderr 输出
标准库 log 写文件失败?没传 *os.File
log.SetOutput("app.log") 会编译报错:cannot use "app.log" (type string) as type io.Writer。标准库 log 不接受路径字符串,只认实现了 io.Writer 的对象。
- 先用
os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)获取*os.File - 检查返回的
err,目录不存在时需提前os.MkdirAll -
*os.File并发写安全,但多 goroutine 同时log.Print可能导致行内混杂(如时间戳和消息错位) - 长期运行建议加
bufio.NewWriter提升性能,但需手动Flush()防丢失
panic 日志没堆栈?只打 r 不够
仅 log.Printf("panic: %v", r) 或 glog.Errorf("%v", r) 只输出 panic 值(比如字符串),完全丢失调用链。线上排查几乎无法定位。
- 用
runtime/debug.Stack()获取完整 goroutine 堆栈,和 panic 值一起记录 - 示例:
glog.Errorf("panic: %v\n%s", r, debug.Stack()) - 若用标准
log,同样要拼接debug.Stack(),不能只依赖log.Panicln—— 它只触发 panic,不记录上下文 - HTTP handler 中 recover 失效常见于子 goroutine,每个
go fn()必须自带defer/recover
最易忽略的是:glog 缓冲机制不是 bug,是设计契约;而标准库 log 不自动 flush 也不是缺陷,是接口抽象的必然结果。写日志这件事,从来不是“调了就完事”,而是“写了 + 刷了 + 有上下文”才算真正落地。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











