gin 的 panic 默认不上报 sentry,因其内置 recovery 中间件会提前捕获并终止 panic,导致 sentry-go 的全局 recover 无法触发;必须手动注册 sentry 中间件、启用 httpintegration、在 main 开头调用 init 并正确配置上下文。

能自动推送,但默认不生效——Gin 的 panic 不会自动进 Sentry,必须手动加中间件和正确初始化。
为什么 Gin 的 panic 默认不上报到 Sentry
Gin 自身有 recover 机制,会吞掉 panic 并返回 500,导致 sentry-go 的全局 recover() 根本收不到;即使你调了 sentry.Init(),没配中间件,HTTP 层的崩溃就卡在 Gin 里出不来。
-
sentry.Recover()只对当前 goroutine 有效,Gin handler 是独立 goroutine,得显式在每个请求生命周期里 defer 它 - 没启用
HTTPIntegration时,上报的事件里只有错误类型,没有method、url、status_code,排查时只能看到 “panic interface{}”,不知道发生在哪个接口 - 如果
sentry.Init()放在gin.Default()之后,部分早期路由 handler(比如注册了但还没 run 的)panic 就漏报
必须写的 Gin 中间件:sentry.Recover() + HTTPIntegration
中间件不是可选插件,是强制入口。只写 defer sentry.Recover() 不够,得配合 sentry.HTTPIntegration 补全上下文,否则所有错误都挤在 GET / 下。
- 初始化时要显式传入
HTTPIntegration:sentry.ClientOptions{Integrations: func() []sentry.Integration { return []sentry.Integration{&sentry.HTTPIntegration{}} }} - 中间件里必须先
sentry.ConfigureScope(),再c.Next(),否则 scope 拿不到当前请求对象 - 别在中间件里直接
sentry.CaptureException()——sentry.Recover()内部已经做了,重复调用会导致同一 panic 上报两次
func SentryMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("path", c.Request.URL.Path)
scope.SetTag("method", c.Request.Method)
if userID := c.Request.Header.Get("X-User-ID"); userID != "" {
scope.SetTag("user_id", userID)
}
})
defer sentry.Recover()
c.Next()
}
}
Init() 调用时机和常见静默失败点
sentry.Init() 返回 error 但默认不 panic,很多团队上线后发现没报警,查日志才发现 DSN 解析失败或环境变量为空——错误被吞了。
- 必须在
main()最开头调用,早于gin.Default()和任何 goroutine 启动 -
DSN必须是完整格式:https://xxx@o123.ingest.sentry.io/456,不能只填 public key 或去掉协议头 -
Environment和Release必须设,否则所有环境事件混在一起,无法过滤staging的误报 - 开发期打开
Debug: true,能看到 SDK 是否成功连接、事件是否发出、有没有被丢弃(比如 rate limit)
业务 error 怎么上报?别用 CaptureMessage()
CaptureMessage("db timeout") 只发字符串,Sentry 无法聚类、看不到堆栈、分不出是哪个 SQL 超时;而 CaptureException(err) 会自动提取 error 类型、cause 链、完整堆栈,才能真正归组。
- 所有
if err != nil分支,统一走sentry.CaptureException(err) - 不要给
CaptureException()传fmt.Errorf("xxx: %w", err)包装过的 error——Sentry 能自己解析 cause 链,多包一层反而干扰聚类 - 需要额外上下文时,用
sentry.WithScope()临时加 tag 或 extra,而不是改全局 scope
最难的不是写那几行中间件,而是确保每个 goroutine、每个 handler、每个 error 分支都在 Sentry 视野里——漏掉任意一环,生产问题就可能悄无声息地发生。











