Kratos 中 panic 不上报 Sentry 的根本原因是 recover 机制冲突且初始化顺序错误:sentry.Init() 必须置于 main() 开头,HTTP/gRPC 需手动注入 sentry.Recover() 中间件,后台 goroutine 需各自 defer,错误须用 CaptureException 而非 CaptureMessage。

Kratos 框架里 panic 不上报 Sentry?根本不是 SDK 没装,而是 Kratos 的 recover 机制和 Sentry 的 sentry.Recover() 冲突了——Kratos 默认用 recover() 捕获 panic 并转成 HTTP 500,但这个过程绕过了 Sentry 的堆栈捕获逻辑。
kratos.Server 启动前必须完成 sentry.Init()
Kratos 的 app.Run() 会并发启动多个组件(HTTP、gRPC、定时任务等),一旦 panic 发生在这些 goroutine 里,而 sentry.Init() 还没执行,就彻底丢失。
-
sentry.Init()必须放在main()函数最开头,早于kratos.NewApp()和任何app.Run()调用 - 不能塞进
init()函数——init()阶段的 panic 无法被sentry.Recover()捕获 - 必须启用
AttachStacktrace: true,否则 panic 堆栈只显示在recover()处,不是真实出错行
HTTP/gRPC Server 需要手动注入 sentry.Recover()
Kratos 的 http.Server 和 grpc.Server 内部已自带 recover(),不会触发全局 defer;不显式加中间件,Sentry 就收不到任何 panic。
- HTTP 中间件示例:
func SentryRecovery() http.Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer sentry.Recover() next.ServeHTTP(w, r) }) } }注册时:r.Use(SentryRecovery()) - gRPC 拦截器类似,用
grpc.UnaryInterceptor()包一层defer sentry.Recover() - 注意:Kratos v2.7+ 的
http.ServerOption支持http.WithMiddleware(),别写在 handler 里漏掉
非 HTTP/gRPC 的 goroutine(如 job、consumer)必须单独 defer
Kratos 常用 app.Run() 启动后台任务(比如 job.NewWorker() 或消息队列 consumer),这些 goroutine 独立于主服务生命周期,不加 defer sentry.Recover() 就等于裸奔。
- 每个长期运行的 goroutine 入口处都得加:
go func() { defer sentry.Recover() for range ticker.C { // job logic } }() - 如果用了 Kratos 的
job模块,要在job.JobFunc内部手动包一层defer sentry.Recover(),它不自动透传 - 第三方库(如 kafka-go consumer)同理,panic 发生在回调函数里,必须在回调入口加 defer
业务 error 不该用 CaptureMessage,必须用 CaptureException
很多同学在 Kratos 的 service 层写 sentry.CaptureMessage("user not found"),结果 Sentry 控制台里全是孤立事件,没法按错误类型聚合、看不到堆栈、查不到调用链。
- 所有明确的
error实例(比如errors.New()、fmt.Errorf())必须走sentry.CaptureException(err) - 想补上下文?用
sentry.ConfigureScope(),比如在 HTTP middleware 里塞user_id:sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetTag("user_id", userID) }) -
CaptureMessage()只适合纯日志类提示(如 “cache warmup finished”),千万别用来上报错误
最容易被忽略的一点:Kratos 的 http.Server 默认把 panic 转成 500 响应并吞掉,你看到 HTTP 返回码异常,却在 Sentry 里搜不到对应事件——因为 panic 被 Kratos 自己 recover 了,根本没传给 Sentry。必须用中间件抢在 Kratos 之前做 defer sentry.Recover(),顺序错了就白搭。


















