Dubbo自定义日志拦截器

前言 上一篇文章 Spring aop+自定义注解统一记录用户行为日志 记录了 web层中通过自定义注解配合Spring aop自动记录用户行为日志的过程。那么按照分布式架构中Dubbo服务层的调用过程是否也可以实现统一记录日志?自定义日志拦截器可以实现这个需求。 需求场景 在使用Dubbo搭建的分布式项目中,服务层代码调用是这样的: 1 @GetMapping(value = "/info") 22 public BaseResult userInfo() { 33 //rpc远程调用用户服务 44 BaseResult result = mUserService.userInfo(); 56 return result; 67 } 这里的用户服务位于另外一个服务进程,由服务提供者暴露出来,让web层远程调用,需要记录服务结果的调用过程,便于跟踪定位bug. 自定义日志拦截器 翻看下Dubbo官方文档,可以看到如下内容: 简要说明: Dubbo 中所有的拦截器全部继承自org.apache.dubbo.rpc.Filter接口,我们自己也可以自行扩展,只要继承该接口即可. 用户自定义 filter 默认在内置 filter 之后执行 新增 DubboServiceFilter 拦截器如下: 1public class DubboServiceFilter implements Filter { 2 3 private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceFilter.class); 4 5 @Override 6 public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { 7 //外部日志开关默认关闭 8 String logSwitch = StringUtils.equals(RedisUtil.get(BaseConstants.CACHE_SERVICE_LOG_SWITCH), BaseConstants.YES) ? BaseConstants.YES : BaseConstants.NO; 9 if (StringUtils.equals(BaseConstants.YES, logSwitch)) { 10 //打印入参日志 11 DubboServiceRequest serviceRequest = new DubboServiceRequest(); 12 serviceRequest.setInterfaceName(invocation.getInvoker().getInterface().getName()); 13 serviceRequest.setMethodName(invocation.getMethodName()); 14 serviceRequest.setArgs(invocation.getArguments()); 15 LOGGER.info("dubbo服务接口入参: " + JSON.toJSONString(serviceRequest)); 16 } 17 //开始时间 18 long startTime = System.currentTimeMillis(); 19 //执行接口调用逻辑 20 Result result = invoker.invoke(invocation); 21 //调用耗时 22 long elapsed = System.currentTimeMillis() - startTime; 23 //如果发生异常 则打印异常日志 24 if (result.hasException() && invoker.getInterface() != GenericService.class) { 25 LOGGER.error("dubbo执行异常: ", result.getException()); 26 } else { 27 if (StringUtils.equals(BaseConstants.YES, logSwitch)) { 28 //打印响应日志 29 DubboServiceResponse serviceResponse = new DubboServiceResponse(); 30 serviceResponse.setMethodName(invocation.getMethodName()); 31 serviceResponse.setInterfaceName(invocation.getInvoker().getInterface().getName()); 32 serviceResponse.setArgs(invocation.getArguments()); 33 serviceResponse.setResult(new Object[]{result.getValue()}); 34 serviceResponse.setSpendTime(elapsed); 35 LOGGER.info("dubbo服务响应成功,返回数据: " + JSON.toJSONString(serviceResponse)); 36 } 37 } 38 //返回结果响应结果 39 return result; 40 } 41} 代码中对应的实体bean如下: 入参实体: 1/** 2 * @program: easywits 3 * @description:Dubbo服务请求入参实体 4 * @author: zhangshaolin 5 * @create: 2019-01-08 20:35 6 **/ 7@Data 8public class DubboServiceRequest implements Serializable{ 9 private static final long serialVersionUID = 7127824956842786618L; 10 11 /** 12 * 接口名 13 */ 14 private String interfaceName; 15 16 /** 17 * 方法名 18 */ 19 private String methodName; 20 21 /** 22 * 参数 23 */ 24 private Object[] args; 25} 响应实体: 1/** 2 * @program: easywits 3 * @description: Dubbo服务响应结果实体 4 * @author: zhangshaolin 5 * @create: 2019-01-08 20:36 6 **/ 7@Data 8public class DubboServiceResponse implements Serializable{ 9 private static final long serialVersionUID = -2531169660859647737L; 10 11 /** 12 * 接口名 13 */ 14 private String interfaceName; 15 16 /** 17 * 方法名 18 */ 19 private String methodName; 20 21 /** 22 * 参数 23 */ 24 private Object[] args; 25 26 /** 27 * 返回结果 28 */ 29 private Object result; 30 31 /** 32 * 调用耗时(毫秒) 33 */ 34 private long spendTime; 35} 在/src/main/resources/META-INF/dubbo目录下新增纯文本文件org.apache.dubbo.rpc.Filter 内容为: 1dubboServiceFilter=com.easywits.common.filter.DubboServiceFilter 键值对形式,键随便起个名字 值为DubboServiceFilter拦截器的完整包名. 最后在服务提供者配置文件中添加配置使拦截器生效: 1 2 4 5 6 7 8 9 10 11 12 13 14 ....省略部分服务配置 15 16 验证结果 抓一下我们业务中的部分日志信息看下效果,如下图: 可以清楚地看到Dubbo服务接口调用的请求参数信息,以及最终的响应结果信息,便于定位线上问题。 参考文档:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html 最后 记录一个比较简单的具体实用场景,后续会不定期更新更多的实用场景,欢迎关注公众号【张少林同学】! https://www.cnblogs.com/zhangshaolin/p/10242848.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信