
本文介绍在 Go 应用中通过 defer + recover 捕获 panic 后,使用 glog 正确将错误日志写入指定日志文件的方法,关键在于手动调用 glog.Flush() 避免日志缓冲丢失。
本文介绍在 go 应用中通过 defer + recover 捕获 panic 后,使用 glog 正确将错误日志写入指定日志文件的方法,关键在于手动调用 `glog.flush()` 避免日志缓冲丢失。
在 Go 中,glog(Google 的日志库)默认采用缓冲写入机制:日志消息先暂存于内存缓冲区,定期或显式调用 glog.Flush() 时才真正落盘到目标日志文件(如 INFO, ERROR 等命名的文件)。当 panic 发生并被 recover() 捕获后,若程序未主动触发 flush,缓冲区中的日志(包括 glog.Errorf 记录)可能尚未写入磁盘,导致日志“消失”——实际并非丢失,而是仍滞留在内存中,最终随进程异常终止而被丢弃。此时系统可能将未捕获的 panic 或 runtime 错误转交 syslog,因此你看到日志出现在 /var/log/messages,而非预期的 glog 日志目录。
正确做法是在 defer 函数中恢复 panic 后,立即调用 glog.Flush() 强制刷新缓冲区。以下是修复后的示例代码:
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
defer func() {
if r := recover(); r != nil {
glog.Errorf("Recovered from panic: %v", r)
glog.Flush() // ✅ 关键:确保日志写入文件
}
}()
panic("THIS IS A PANIC") // 注意拼写修正
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
⚠️ 注意事项:
- glog.Flush() 必须在 recover() 之后、函数返回前调用;若 defer 中有多个操作,Flush() 应置于日志记录之后、且不可被后续 panic 中断;
- glog 已归档(deprecated),生产环境建议迁移到更现代的日志库(如 zap 或 log/slog),它们对 panic 场景和同步写入支持更健壮;
- 若使用 glog,请确保已正确初始化(如设置 -log_dir 参数),否则日志可能仅输出到 stderr;
- 不要依赖 os.Exit() 或未处理 panic 来“保证 flush”——这恰恰会导致 flush 失败。
总结:panic 本身不是“无法记录”的理由,而是日志缓冲机制与程序生命周期不匹配所致。glog.Flush() 是 bridge the gap 的标准解法——它让日志从内存安全落地,确保可观测性不因异常中断而失效。











