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<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3 ...省略部分代码">
4
5 <!--服务提供方应用信息,用于计算依赖关系-->
6 <dubbo:application name="easywits-upms-rpc-service"/>
7
8 <!--用dubbo协议在20881端口暴露服务-->
9 <dubbo:protocol name="dubbo" port="20881" payload="52428800"/>
10
11 <!--自定义服务层过滤器,值为上述步骤文本文件中的键-->
12 <dubbo:provider filter="dubboServiceFilter"/>
13
14 ....省略部分服务配置
15</beans>
16
验证结果
抓一下我们业务中的部分日志信息看下效果,如下图:
可以清楚地看到Dubbo服务接口调用的请求参数信息,以及最终的响应结果信息,便于定位线上问题。
参考文档:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html
最后
记录一个比较简单的具体实用场景,后续会不定期更新更多的实用场景,欢迎关注公众号【张少林同学】!
Dubbo自定义日志拦截器的更多相关文章
- SpringMVC 自定义一个拦截器
自定义一个拦截器方法,实现HandlerInterceptor方法 public class FirstInterceptor implements HandlerInterceptor{ /** * ...
- springmvc自定义的拦截器以及拦截器的配置
一.自定义拦截器 Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口. 二.HandlerIn ...
- Spring自定义一个拦截器类SomeInterceptor,实现HandlerInterceptor接口及其方法的实例
利用Spring的拦截器可以在处理器Controller方法执行前和后增加逻辑代码,了解拦截器中preHandle.postHandle和afterCompletion方法执行时机. 自定义一个拦截器 ...
- struts2-权限拦截器、日志拦截器、execAndWait(进度条)拦截器配置
1.权限拦截器 package login; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.Serv ...
- Mybatis自定义SQL拦截器
本博客介绍的是继承Mybatis提供的Interface接口,自定义拦截器,然后将项目中的sql拦截一下,打印到控制台. 先自定义一个拦截器 package com.muses.taoshop.com ...
- .net core Blazor+自定义日志提供器实现实时日志查看器
场景 我们经常远程连接服务器去查看日志,比较麻烦,如果直接访问项目的某个页面就能实时查看日志就比较奈斯了,花了1天研究了下.net core 日志的原理,结合blazor实现了基本效果. 实现原理 自 ...
- .net core系列之《对AOP思想的理解及使用AspectCore实现自定义日志拦截》
对于AOP这个名词,相信对于搞过MVC开发的人来说,都很熟悉,里面各种各样的Filter简直是将AOP体现到了极致. 那么什么是AOP呢? AOP(Aspect Oriented Programmin ...
- spring自定义注解拦截器的配置
1.创建注解文件 (文件格式为注解) 这里面什么都不需要写 文件名就是注解名称 如下 是@anno package com.ABC123.anno; import java.lang.annotati ...
- struts2自定义Interceptor拦截器
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
随机推荐
- solr dismax与edismax的参数列表
dismax q.alt qf (Query Fields) mm (Minimum 'Should' Match) pf (Phrase Fields) ps (Phrase Slop) qs (Q ...
- 【poj2411】Mondriaan's Dream 状态压缩dp
AC传送门:http://vjudge.net/problem/POJ-2411 [题目大意] 有一个W行H列的广场,需要用1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法? [题解] 对于 ...
- Error while trying to retrieve text for error ORA-12154
问题描述:vs中调试运行没有任何错误,但是发布到IIS中访问,就会报以上错误.IIS不会调试,所以一头雾水,不止错误在哪里. 分析:看到网上有人分析了Web.config模拟验证的问题恍然大悟: 原文 ...
- Java程序设计11——GUI设计与事件处理B
4 Java事件模型的流程 为了使图形界面能够接收用户的操作,必须给各个组件加上事件处理机制. 在事件处理的过程中,主要涉及3类对象: 1.Event Source(事件源):事件发生的场所,通常就是 ...
- TableLayout 中不显示动态添加的tableRow
下面的代码不显示: TableRow lay = new TableRow(layIndex.getContext()); lay.setLayoutParams(lpRow); //layIndex ...
- serialVersionUID的作用以及IDEA、Eclipse如何自动生成serialVersionUID
说到serialVersionUID,首先要讲讲序列化. 序列化: 序列化可以将一个java对象以二进制流的方式在网络中传输并且可以被持久化到数据库.文件系统中,反序列化则是可以把之前持久化在数据库或 ...
- io.fabric8.kubernetes对pv和pvc的增删查改
1.新建maven项目k8stest,pom.xml如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns: ...
- UVa 11419 SAM I AM (最小覆盖数)
题意:给定一个 n * m 的矩阵,有一些格子有目标,每次可以消灭一行或者一列,问你最少要几次才能完成. 析:把 行看成 X,把列看成是 Y,每个目标都连一条线,那么就是一个二分图的最小覆盖数,这个答 ...
- SpringMVC源码解析 - HandlerAdater - ModelAndViewContainer上下文容器
HandlerAdapter在处理请求时上下文数据的传递工作是由ModelAndViewContainer负责的. 源码注释是这样描述的: Records model and view related ...
- Linux umask权限
文件基本权限 Linux中文件权限由三部分组成: rw-r--r-- 前三位:表示用户所拥有的权限 中三位:表示用户所在组的权限 后三们:表示其他用户的权限 权限 八进制 十进制 - - - 000 ...