Gin的panic未进Sentry,因sentry-go的Recover()仅捕获当前goroutine panic,而Gin handler运行在独立goroutine中;须在中间件中显式defer sentry.Recover()并启用AttachStacktrace:true。

为什么 Gin 的 panic 没进 Sentry?
因为 sentry-go 的 Recover() 只捕获当前 goroutine 的 panic,而 Gin 启动后所有 HTTP handler 都在独立 goroutine 中运行——如果你只在 main() 里 defer sentry.Recover(),它根本捕获不到路由里的 panic。
- 必须在每个 HTTP handler 或中间件中显式加
defer sentry.Recover() - 推荐用中间件统一包裹,而不是手动往每个 handler 里塞
- 别漏掉
AttachStacktrace: true,否则堆栈只显示到中间件入口,看不到真实出错行号 - 如果用了
gin.Recovery(),要把它删掉或禁用,否则两个 recover 冲突,Sentry 可能收不到原始 panic
如何写一个可靠的 Sentry 中间件
中间件不是简单套个 defer sentry.Recover() 就完事。Gin 的 c.Next() 执行完才走到 defer,但 panic 发生在 c.Next() 期间,所以必须确保 recover 在 panic 发生时立即生效。
- 中间件函数体第一行就写
defer sentry.Recover(),位置不能错 - 配合
sentry.ConfigureScope()补充请求上下文:路径、method、用户 ID(从 header 或 JWT 解析) - 避免在 scope 里写敏感字段,比如
Authorizationheader 值 - 示例代码里
sentry.HTTPIntegration对 Gin 无效,它只适配 net/http,Gin 需手动 set tag
func SentryRecovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer sentry.Recover()
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("http.method", c.Request.Method)
scope.SetTag("http.path", c.Request.URL.Path)
scope.SetTag("user_id", c.GetString("user_id")) // 假设你已解析并存入 context
})
c.Next()
}
}
业务 error 为什么不上报?
你写了 if err != nil { reportError(err) },但 Sentry 控制台空空如也——大概率你用了 sentry.CaptureMessage() 而不是 sentry.CaptureException()。前者只传字符串,不带堆栈、无法聚类;后者才能让 Sentry 按 error 类型 + 堆栈指纹自动归组。
- 所有
if err != nil分支,一律用sentry.CaptureException(err) - 不要在 defer 里对 error 调用
Recover(),那是给 panic 准备的 - 如果 error 来自第三方库(比如
json.Unmarshal),它本身没实现Unwrap(),Sentry 仍能提取基础堆栈,够用 - 若需补充上下文(如请求 ID、参数快照),用
sentry.WithScope()包一层再上报
Init() 放错位置导致静默失败
sentry.Init() 返回 error,但默认不 panic,也不 log——你根本不知道它失败了。常见原因是 DSN 格式错误、环境变量没读到、或初始化太晚。
- 必须放在
main()最开头,早于gin.Default()和任何 goroutine 启动 - 检查
os.Getenv("SENTRY_DSN")是否为空,空值会导致 SDK 降级为 noop 模式 - 务必设置
Environment和Release,否则所有错误都挤在production下,没法按版本或环境筛选 - 开发期打开
Debug: true,能看到 SDK 内部日志,比如 “event dropped due to filter” 这类关键提示


















