必须在main()开头调用sentry.Init(),因其注册全局panic捕获器、初始化scope管理和transport;晚于gin.Default()或goroutine启动将导致崩溃漏报。

必须在 main() 开头调用 sentry.Init(),否则 panic、HTTP 中间件错误、goroutine 崩溃大概率漏报。
为什么 Init() 一定要放在 main 最前面
因为 sentry.Init() 注册了全局 panic 捕获器(recover() + signal.Notify),还初始化了 scope 管理和 transport。如果晚于 gin.Default() 或 goroutine 启动,那些提前崩溃的流程就完全绕过 Sentry。
- 常见现象:本地调试能上报,部署后 404 页面的 panic、后台定时任务的 panic 全部静默
- 绝对不要在
init()函数里调用sentry.Init()—— 包初始化阶段 panic 无法被捕获 - 日志库(如 zap)也得等
sentry.Init()之后再初始化,否则日志 panic 不会上报
HTTP 请求上下文怎么带路径和用户信息
默认 sentry-go 只记录 panic 堆栈,不自动提取 HTTP 请求字段。必须手动补全,否则所有错误都显示为 GET /,无法定位接口。
- 用
sentry.HTTPIntegration可自动附加 method、URL、status code,但不包括 header 或用户 ID - 在 Gin 中间件里调用
sentry.ConfigureScope(),例如:sentry.SetTag("user_id", c.GetString("user_id")) - 从
c.Request.Header.Get("X-Trace-ID")或 JWT token 解析出的字段写入 scope,别塞 password、token 这类敏感数据 - 避免在中间件里重复调用
sentry.Init()或新建 client,scope 是 goroutine 局部的,直接用全局 client 即可
panic 和 error 上报该用 Recover() 还是 CaptureException()
这不是二选一,而是分工明确:前者兜底未捕获的 panic,后者主动上报已 catch 的 error。
-
defer sentry.Recover()放在 handler 最外层,只用于 recover 未处理的 panic(比如模板渲染失败、JSON 序列化 panic) -
if err != nil { sentry.CaptureException(err) }用于业务错误,比如数据库超时、第三方 API 返回非 2xx - 别在
http.HandlerFunc里盲目加recover()—— Gin 自身已有 panic 处理,重复 recover 可能掩盖真实问题 -
CaptureException()不中断执行流,Recover()本身也不 panic,但你要自己决定是否 return 或 log
goroutine 崩溃为什么 Sentry 收不到
Go 的 goroutine panic 默认不传播到主线程,sentry-go 的全局 handler 对它无效。你只会看到日志一闪而过,Sentry 完全没记录。
- 所有显式启动的 goroutine(比如
go func() { ... }())必须手动包一层defer sentry.Recover() - 定时任务、消息队列消费者、长连接协程,只要脱离 HTTP 生命周期,就得自己负责 panic 捕获
- 别依赖 “全局 recover” —— Go 没有这种东西,每个 goroutine 是独立的执行单元
- 如果用
workerpool或ants这类库,得看它是否支持 panic hook;不支持就得在任务函数入口加defer sentry.Recover()
最难的不是把 Sentry 接进去,而是确保每个 goroutine、每个中间件、每个异步操作都在它的监控视野里 —— 这取决于你对 Go 并发模型的理解,而不是配置几行代码。


















