sentry-go 捕不到 panic 是因默认未启用 recovery 机制,需手动在 goroutine 入口 defer sentry.recover() 或结合 recover() + debug.stack() 上报完整堆栈,且 sentry.init() 必须早于可能 panic 的代码执行。

为什么 sentry-go 捕不到 panic?默认 Recovery 机制没开
Go 程序 panic 后默认会终止 goroutine 并打印堆栈到 stderr,sentry-go 不会自动拦截——它只捕获显式调用 Sentry.CaptureException() 或 Sentry.Recover() 的错误。不手动 hook recover(),Sentry 就永远看不到 panic。
常见表现:本地跑着程序突然崩溃,控制台输出 panic: xxx,但 Sentry 后台空空如也。
- 必须在 main goroutine 或关键 goroutine 入口加
defer Sentry.Recover() - 若使用
http.Server,应在每个 handler 内部或中间件里 defer recover,不能只在main()里加一次 -
Sentry.Init()必须早于任何可能 panic 的代码执行,否则初始化失败导致后续 capture 无效
VSCode 调试时 panic 显示不全?dlv 默认跳过 runtime 异常
VSCode 用 dlv 调试 Go,默认配置下 panic 触发时会被调试器吞掉或中断在 runtime.panic 底层,看不到你自己的源码位置和变量状态。
解决办法是改 .vscode/launch.json,强制 dlv 捕获 panic 事件:
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/main.go",
"env": {},
"args": [],
"dlvLoadConfig": {
"followPointers": true,
"maxVariableRecurse": 1,
"maxArrayValues": 64,
"maxStructFields": -1
},
"dlvDapConfig": {
"substitutePath": []
},
"dlvLoadSymbols": ["*"],
"stopOnEntry": false,
"showGlobalVariables": true,
"trace": "log",
"env": {}
}
]
}
关键点:
- 删掉或注释掉
"stopOnEntry": true(它会干扰 panic 中断) - 确保
"dlvLoadSymbols"包含"*",否则 panic 时无法解析你的源码行号 - 启动调试后,在 VSCode 的 “DEBUG CONSOLE” 里输入
continue手动继续,避免被 runtime 断住
如何让 Sentry 上报带源码上下文的 panic?别只传 err.Error()
直接 Sentry.CaptureException(errors.New("xxx")) 只能上报字符串,丢失堆栈帧、goroutine ID、局部变量等关键信息。要让 Sentry 显示可点击的源码行、函数名、甚至参数值,必须用 runtime/debug.Stack() 构造完整异常对象。
推荐写法(配合 defer recover):
func handlePanic() {
if r := recover(); r != nil {
stack := debug.Stack()
err := errors.New(fmt.Sprintf("panic: %v\n%s", r, stack))
Sentry.CaptureException(err)
}
}
更优方案是封装成中间件或全局 defer:
- HTTP handler 中:在最外层
func(w http.ResponseWriter, r *http.Request)里defer handlePanic() - CLI 命令中:在
cmd.Execute()前加defer handlePanic() - 注意:不要对
r做类型断言(如r.(error)),panic 的r可能是任意类型
本地开发时 Sentry 报警太多?关掉 environment 和 sampleRate
VSCode 本地调试期间频繁 panic 是常态,如果每条都打到 Sentry,不仅污染线上数据看板,还可能触发配额告警。
建议在 Sentry.Init() 里加条件判断:
if os.Getenv("ENV") != "production" {
Sentry.Init(Sentry.ClientOptions{
Dsn: "https://xxx@o123.ingest.sentry.io/xxx",
Environment: "development",
SampleRate: 0.0, // 关闭采样,完全不上报
Debug: true,
})
} else {
// 生产环境开启
}
或者更细粒度地只关闭 panic 上报:
- 用
Sentry.ConfigureScope()动态设置SetTag("skip-panic-report", "true"),再在BeforeSend回调里过滤 - VSCode 启动时加环境变量:
ENV=development go run main.go - 别依赖
os.Args判断是否调试——dlv 启动时参数不可靠
真正上线前务必检查 SampleRate 是否为 1.0,且 Environment 不是 development —— 这个配置项在 Sentry UI 里无法覆盖,只能靠代码控制。











