默认收不到sentry是因为sentry-go不自动捕获panic,需手动用sentry.recover或runtime.setpanichandler拦截并上报,否则进程退出导致事件丢失。

panic发生时为什么默认收不到Sentry?
Go的panic不会自动触发Sentry上报,因为Sentry Go SDK(sentry-go)默认只捕获显式调用sentry.CaptureException或sentry.Recover的错误。未被recover捕获的panic会直接终止goroutine,而主goroutine崩溃还会导致进程退出——此时Sentry甚至来不及把事件发出去。
常见现象:本地panic能打日志,但线上完全没出现在Sentry控制台;或者只看到Process exited with status 2这类模糊记录。
关键点:必须手动拦截panic,并确保在进程退出前完成上报。
用sentry.Recover捕获HTTP handler里的panic
Web服务中最常漏报的是HTTP handler内发生的panic。标准net/http不recover,所以要用中间件兜底。
func sentryRecovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
sentry.CurrentHub().Recover(err)
// 注意:这里不调用sentry.Flush,因为HTTP响应还没结束,后续还有机会
}
}()
next.ServeHTTP(w, r)
})
}
- 必须放在所有中间件最外层(比如放在
logging、auth之后),否则内部中间件panic会被提前捕获,丢失原始调用栈 -
sentry.Recover会自动提取err类型和堆栈,比sentry.CaptureException更简洁 - 不要在这里调用
sentry.Flush——HTTP handler还在执行中,强制flush可能阻塞响应
全局panic hook:捕获main goroutine崩溃
命令行工具、定时任务或gRPC server主goroutine的panic无法靠HTTP中间件覆盖,需要用signal.Notify + runtime.SetPanicHandler(Go 1.21+)或传统recover兜底。
Go 1.21+推荐方式:
func initSentryPanicHook() {
runtime.SetPanicHandler(func(p runtime.PanicEvent) {
// 构造一个error供sentry处理
err := fmt.Errorf("panic: %v", p.Value)
sentry.CurrentHub().CaptureException(err)
// 强制同步发送,避免进程立刻退出导致丢数据
sentry.Flush(5 * time.Second)
})
}
旧版本(Go os.Interrupt和syscall.SIGTERM,并在main末尾加defer sentry.Flush(2 * time.Second)——但注意这无法捕获未recover的panic,仅保底。
容易被忽略的三个坑
-
sentry.Init必须在main函数开头尽早调用,且Debug: true上线前一定要关掉,否则大量调试日志会拖慢panic路径
- goroutine泄漏场景:如果某个后台goroutine panic后未recover,又没被
SetPanicHandler捕获(比如它启动早于init),就会静默退出——建议所有go fn()都包一层defer sentry.Recover
- 自定义
panic值不是error类型(比如panic("xxx"))时,sentry.Recover仍能工作,但堆栈可能不完整;更稳妥是统一panic(fmt.Errorf("xxx"))
sentry.Init必须在main函数开头尽早调用,且Debug: true上线前一定要关掉,否则大量调试日志会拖慢panic路径SetPanicHandler捕获(比如它启动早于init),就会静默退出——建议所有go fn()都包一层defer sentry.Recover
panic值不是error类型(比如panic("xxx"))时,sentry.Recover仍能工作,但堆栈可能不完整;更稳妥是统一panic(fmt.Errorf("xxx"))
Sentry对Go的panic支持依赖你主动“接住”它,而不是等它自动上报。最简可行路径就是:HTTP用中间件Recover,主goroutine用SetPanicHandler,其他goroutine手动包defer——少一个环节,线上就少一条关键线索。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











