SpringBoot2.x+Sentry实现跨线程的异常汇总
Sentry是一个日志平台, 它分为客户端和服务端,客户端(目前客户端有Python, PHP,C#, Ruby等多种语言)就嵌入在你的应用程序中间,程序出现异常就向服务端发送消息,服务端将消息记录到数据库中并提供一个web节目方便查看。Sentry由python编写,源码开放,性能卓越,易于扩展,目前著名的用户有Disqus, Path, mozilla, Pinterest等。
1. sentry工作原理
sentry客户端嵌入在应用程序中,通过显示调用API方法完成日志(异常)的上报,而sentry服务器则会对日志(异常)进行分组汇总并显示在页面上。
sentry上报日志的时候,会获取context对象中的request对象,通过request对象获取到例如请求URI、请求Method、请求header、ip:port等信息。但是当在子线程使用sentry的API时,无法在context对象中获取request对象,也就无法获取到以上信息。
sentry是通过SentrySpringRequestListener
监听器完成request的前缀处理。
客户端依赖版本:
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
2. 解决子线程中获取不到request的方案
2.1 方案一:修改源码
问题根源是:currentHub
属性为ThreadLocal,而ThreadLocal是无法跨线程传递的,可修改源码将ThreadLocal替换为阿里巴巴的TransmittableThreadLocal。
而重写源码的方式:只需要在业务代码中定义相同路径的相同文件,即可完成覆盖。
image.png方案的核心思想:将request对象传递下去,由sentry解析request对象,拼接上传信息。
2.2 方案二:使用Sentry api完成分组操作
-
Sentry.setTag:设置标签;
image.png
- Sentry.setExtra:设置扩展内容;
- Sentry.setTransaction:设置事务名称。同一个事务的日志或异常会聚合在一起。(可以设置URI和Method)
-
Sentry.setFingerprint:报警合并规则;
-
Sentry.captureMessage:详细信息;
-
Sentry.captureException:异常堆栈;
而具体的这些信息,父线程可通过TransmittableThreadLocal传递到子线程,有业务代码手动拼接上传信息。
推荐阅读
官网:https://getsentry.com/welcome/
github:https://github.com/getsentry/sentry
安装手册:https://docs.getsentry.com/hosted/quickstart/
在生产环境部署sentry进行错误收集和提醒