一、介绍
在前面介绍在微服务项目中使用skywalking进行全链路追踪时,我们发现当一次请求链路中某个服务出现异常时,在skywalking中会将该链路用红色标记为ERROR
,在异常链路详情中也可以看出是哪个服务出现了异常并可以查看响应的异常信息。如下图所示。
那么有没有办法忽略某个指定的异常呢?就是说如果一个请求链路中某个服务抛出了该异常,skywalking仍然认为该异常属于正常现象,并不会认为它是ERROR
。
答案是肯定的。我们往下看。
二、演示项目介绍
项目结构依然参考skywalking安装教程中的演示项目,业务流程就是商品服务暴露接口给客户端,当客户端调用商品服务接口时,商品服务调用订单服务,订单服务调用支付服务,形成一个包含三个服务的调用链。如下图所示。
1. 支付服务
现在我们定义两个异常:SixException
和 SevenException
,其中SixException
继承 SevenException
, SevenException
继承RuntimeException
,也就是说我们自定义的两个异常都是运行时异常。结构如下。
当接口接收的参数goodsId
为6的倍数时,抛出SixException
;当参数goodsId
为7的倍数时则抛出SevenException
。如下所示
SevenException
@Slf4j public class SixException extends SevenException{ public SixException(String message) { super(message); } }
SixException
@Slf4j public class SevenException extends RuntimeException{ public SevenException(String message) { super(message); } }
修改接口
@GetMapping("/pay") public Integer pay(@RequestParam("goodsId") Integer goodsId) { log.info("支付服务feign接口,服务端口号:{}", port); log.info("商品id:{}", goodsId); if (goodsId % 6 == 0) { log.error("商品id不允许为6的倍数"); throw new SixException("商品id不允许为6的倍数"); } if (goodsId % 7 == 0) { log.error("商品id不允许为7的倍数"); throw new SevenException("商品id不允许为7的倍数"); } return 0; }
添加全局异常处理器
我们将抛出
SevenException
这个异常的情况定义为正常情况,当接口抛出SevenException
时,通过全局异常处理器捕获该异常,然后将接口响应设置为失败即可。@RestControllerAdvice public class GlobalExceptionHandlers { @ExceptionHandler(SixException.class) public Integer sixException(SixException e) { return 1; } @ExceptionHandler(SevenException.class) public Integer sevenException(SevenException e) { return 1; } }
2. 订单服务
在原本的订单服务的接口中,有个判断条件为如果商品id为2的倍数,则返回。该条件影响我们支付服务中对SixException
的测试,所以该判断条件删除,如下所示
三、项目演示
下面我们按部就班启动微服务项目和skywalking服务,并调用商品服务接口,分别传入商品id为6和7的参数。
商品id为6
请求如图
日志如图
商品id为7
请求如图
日志如图
![商品id为7的日志.png](https://ucc.alicdn.com/pic/developer-ecology/een7m2naevh4a_11ef736d049b4e8bb4068b20159af40f.png)
1. 未忽略异常
在未忽略异常的情况下,skywalking将出现异常的链路以及出现异常的服务均使用红色标记为ERROR
。
请求参数商品id分别为6和7的调用链路如下
商品id为6的请求链路
商品id为7的请求链路
2. 忽略异常
有时候抛出异常是控制代码运行的重要方式,因此我们需要对这类异常进行忽略。skywalking提供了两种方式:修改配置、使用注解。
修改配置
在agent.config
配置文件中找到statuscheck.ignored_exceptions
对其进行配置,当然了配置方式有多种:修改配置文件、jvm启动参数、javaagent选项、操作系统环境变量,这四种配置方式我们在[skywalking安装教程]中已经详细介绍过了。这里以修改jvm启动参数为例,当需要忽略多个异常时,使用逗号“,”分隔。如下所示。
修改完成后重新启动支付服务,然后再分别调用商品id为6和商品id为7两个请求,得到的调用链路如下
- 商品id为6的请求链路
商品id为7的请求链路
从截图可以发现,当我们在某个服务中忽略指定的异常时,skywalking会将出现该异常的服务标记为成功。而且,我们忽略的异常明明是SevenException
,但是当出现SixException
时,skywalking也会对其进行忽略。
所以得出结论:当忽略一个指定的父异常时,skywalking会忽略该父异常和它的子异常。
使用注解
skywalking也提供了通过注解的方式来指定一个忽略的异常。
添加依赖
<dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-trace</artifactId> <version>8.9.0</version> </dependency>
在要忽略的异常上添加注解
@IgnoredException
,等同于添加配置statuscheck.ignored_exceptions
。@IgnoredException public class SevenException extends RuntimeException{ public SevenException(String message) { super(message); } }
四、结论
- 通过给微服务添加
statuscheck.ignored_exceptions=异常类的限定路径
,实现在调用链路中忽略指定异常。 - 通过注解
@IgnoredException
指定要忽略的异常,但需要添加依赖apm-toolkit-trace
。 - 当忽略一个指定的父异常时,skywalking会忽略该父异常和它的子异常。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————