go 使用 recover 捕获 panic 并且打印代码堆栈日志
背景
用过 golang 的相信都知道,我们在开发中为了防止程序出现 panic ,导致整个程序宕机停止,我们通常都会使用 recover 对 panic 进行捕获,这样子程序就不会因为某个 bug panic 导致终止了,
Go中的
panic是“运行时异常”,比如空指针引用、数组越界、除以零等,一旦触发且未处理,会导致:
程序直接崩溃:如果是线上服务,会导致服务不可用,影响用户体验。
无详细错误链路:默认只打印简单错误信息(如“panic: runtime error: nil pointer dereference”),没有调用堆栈,很难定位具体哪行代码出错。
而
recover的作用就是“拦截”panic,让程序从异常中恢复,同时配合runtime包打印堆栈日志,实现“不崩溃+可追溯”。核心原则是:recover必须在defer函数中调用,因为defer函数会在panic触发后、程序退出前执行。
尤其是在开启 goroutine 协程时,recover 机制显得非常好用,也是程序安全的一种手段之一
但是同时也存在一个问题,recover() 的结果在打印出来时仅有错误❌原因,并没有具体代码调用堆栈信息,这让我们在问题排查上显得有些许吃力
那么如何在 recover 的同时打印调用堆栈信息呢?实际上是可以进行打印的
实现
我们可以使用官方提供的 recover() 机制对程序 panic 进行捕获,在捕获的同时,使用 runtime.Stack 打印代码调用堆栈:
具体代码实现如下:
func main(){
defer func() {
if rec := recover(); rec != nil {
buf := make([]byte, 1<<16) // 分配 64KB 缓冲区
runtime.Stack(buf, true) // 获取完整的调用栈
log.Errorf("recover result ", string(buf)) // 记录调用栈详情
}
}()
panic("test err")
}为什么选择
1<<16(64KB)?普通程序的调用栈通常不会超过 64KB,这个大小能覆盖绝大多数情况
当然也不建议太大,打印日志也是有一定性能耗时的,堆栈信息足够排查问题即可
并且:在 Go 的标准库和社区实践中,
1<<16是常见的默认值(如net/http的调试日志)
关于 panic、recover 的具体使用,请移步文章:
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/go-recover-stack-log/
备用原文链接: https://blog.fiveyoboy.com/articles/go-recover-stack-log/