sentry 在 go 微服务中报错失败的主因是 panic 未捕获、error 未用 captureexception 上报、上下文缺失;init 必须在 main 开头执行,全局需设 attachstacktrace:true,每个 goroutine 和框架中间件要单独配置 recover,业务错误须用 captureexception 而非 capturemessage,并通过 configurescope 补充 user_id 等关键 tag。

Go 微服务里 Sentry 报不上错误?大概率不是 SDK 没装上,而是 panic 没捕获、error 没上报、或者上下文全丢了——Sentry 不会自动猜你用的是 gin 还是 echo,也不会帮你从 request 里抠出 user_id。
为什么 sentry.Init() 放错位置就等于没接
Init 必须在 main() 最开头执行,早于任何 goroutine 启动、HTTP server.ListenAndServe()、甚至日志初始化。否则:
- 提前启动的 worker goroutine panic 后石沉大海
- gin 中间件注册前 panic,
sentry.Recover()根本没注册上 -
init()函数里调用 Init 会导致包初始化卡住,且 init 阶段的 panic 无法被捕获
正确姿势:
func main() {
err := sentry.Init(sentry.ClientOptions{
Dsn: os.Getenv("SENTRY_DSN"),
Environment: os.Getenv("ENV"),
Release: os.Getenv("APP_VERSION"),
Debug: true, // 上线前关掉
})
if err != nil {
log.Fatalf("sentry init failed: %v", err)
}
// 后续才是 log 初始化、server 启动等
}
panic 能捕到,但堆栈却是错的?检查 AttachStacktrace
默认 sentry.Recover() 只记录 recover 发生点的堆栈,不是 panic 真正发生的位置。尤其 HTTP handler 里 panic,不设 AttachStacktrace: true 就只剩 panic: interface conversion 这种无行号信息。
- 全局 panic 捕获必须配
AttachStacktrace: true - 每个独立 goroutine(如定时任务、消息消费者)都要单独加
defer sentry.Recover() - gin/echo 等框架需注册中间件,不能只靠 main goroutine 的 defer
示例(gin):
func SentryRecovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer sentry.Recover()
c.Next()
}
}
// 使用:r.Use(SentryRecovery())
业务 error 用 CaptureMessage() 就废了聚合
sentry.CaptureMessage("db timeout") 只发字符串,Sentry 无法识别错误类型、没有堆栈、不能按 error 类型聚类——100 个不同地方的 io.EOF 全算成 100 条孤立事件。
- 所有
if err != nil场景,统一用sentry.CaptureException(err) - 确保 error 实现了
Unwrap()或嵌套了 cause(如 pkg/errors.Wrap),Sentry 才能展开 root cause - 别在 defer 里对普通 error 调用
Recover(),那是给 panic 预留的
错误示范:
if err != nil {
sentry.CaptureMessage(err.Error()) // ❌ 丢堆栈、无法聚类
}
正确写法:
if err != nil {
sentry.CaptureException(err) // ✅ 自动带类型 + 堆栈 + cause 链
}
错误来了,却找不到是哪个用户、哪个接口?补 scope
Sentry 默认不读 HTTP 请求头或路由参数。不手动塞,所有错误都显示为 GET /,根本没法定位问题接口或复现路径。
- 用
sentry.HTTPIntegration可自动填 method、url、status_code,但 header 和用户身份要自己加 - 在中间件里调用
sentry.ConfigureScope(),把r.Header.Get("X-User-ID")或 JWT 解析结果写进 tag - 绝对避免往 scope 写敏感字段(token、密码、身份证号),Sentry 控制台默认可公开访问
示例:
func SentryContext() gin.HandlerFunc {
return func(c *gin.Context) {
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("user_id", c.Request.Header.Get("X-User-ID"))
scope.SetTag("path", c.Request.URL.Path)
})
c.Next()
}
}
最常被忽略的其实是 goroutine 独立性——主 goroutine 的 Recover() 对子 goroutine 完全无效,而微服务里大量逻辑跑在 go func 里。没给每个关键 worker 单独加 defer,等于主动放弃一半错误可见性。











