

新闻资讯
技术学院本文介绍如何在 go 中精确捕获 panic 时的堆栈信息(而非依赖 stderr 重定向),利用 `runtime.stack` 获取结构化、可编程处理的 panic 堆栈快照,并结合 `recover` 实现优雅错误捕获与日志增强。
Go 默认在 panic 发生时将完整的 goroutine 堆栈信息输出到 stderr 并终止程序,但这种行为难以定制——例如无法区分 panic 日志与其他错误日志,也无法在退出前做上报、采样或格式化。幸运的是,Go 提供了底层机制,让我们能主动捕获 panic 的原始堆栈数据,而非被动监听标准错误流。
核心方案是组合使用 recover() 和 runtime.Stack():
以下是一个完整示例,演示如何在 defer 中安全捕获 panic 并提取结构化堆栈:
package main
import (
"fmt"
"runtime"
"strings"
)
func main() {
defer func() {
if r := recover(); r != nil {
// 获取 panic 值
errMsg := fmt.Sprintf("%v", r)
// 获取所有 goroutine 的堆栈(注意:buf 需足够大)
buf := make([]byte, 1024*1024) // 1MB 缓冲区,避免截断
n := runtime.Stack(buf, true)
stack := string(buf[:n])
// ✅ 此时 errMsg 和 stack 均可自由处理:
// - 写入结构化日志(如 JSON)
// - 发送到监控系统(如 Sentry、Prometheus Alertmanager)
// - 过滤敏感信息后再落盘
fmt.Printf("PANIC CAUGHT:\n%s\nSTACK TRACE:\n%s\n", errMsg, stack)
}
}()
// 触发 panic
panic("something went wrong")
}⚠️ 注意事项:
大(遍历所有 goroutine),仅应在 panic 处理路径中使用,切勿在高频逻辑中调用。总结:通过 recover + runtime.Stack 组合,你完全掌控 panic 输出的生成与流向,摆脱对 stderr 重定向的依赖,实现日志隔离、错误归因、可观测性增强等生产级需求。这是构建健壮 Go 服务的关键实践之一。