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

最后

記錄一個比較簡單的具體實用場景,后續會不定期更新更多的實用場景,歡迎關注公眾號【張少林同學】!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM