Dubbo自定義日誌攔截器

前言

上一篇文章 Spring aop+自定義註解統一記錄用戶行爲日誌 記錄了 web層中經過自定義註解配合Spring aop自動記錄用戶行爲日誌的過程。那麼按照分佈式架構中Dubbo服務層的調用過程是否也能夠實現統一記錄日誌?自定義日誌攔截器能夠實現這個需求。html

需求場景

在使用Dubbo搭建的分佈式項目中,服務層代碼調用是這樣的:java

@GetMapping(value = "/info")
2    public BaseResult userInfo() {
3        //rpc遠程調用用戶服務
4        BaseResult result = mUserService.userInfo();
6        return result;
7    }

這裏的用戶服務位於另一個服務進程,由服務提供者暴露出來,讓web層遠程調用,須要記錄服務結果的調用過程,便於跟蹤定位bug.web

自定義日誌攔截器

翻看下Dubbo官方文檔,能夠看到以下內容:spring

簡要說明:apache

  • Dubbo 中全部的攔截器所有繼承自org.apache.dubbo.rpc.Filter接口,咱們本身也能夠自行擴展,只要繼承該接口便可.
  • 用戶自定義 filter 默認在內置 filter 以後執行

新增 DubboServiceFilter 攔截器以下:架構

public class DubboServiceFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        //外部日誌開關默認關閉
        String logSwitch = StringUtils.equals(RedisUtil.get(BaseConstants.CACHE_SERVICE_LOG_SWITCH), BaseConstants.YES) ? BaseConstants.YES : BaseConstants.NO;
        if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
            //打印入參日誌
            DubboServiceRequest serviceRequest = new DubboServiceRequest();
            serviceRequest.setInterfaceName(invocation.getInvoker().getInterface().getName());
            serviceRequest.setMethodName(invocation.getMethodName());
            serviceRequest.setArgs(invocation.getArguments());
            LOGGER.info("dubbo服務接口入參: " + JSON.toJSONString(serviceRequest));
        }
        //開始時間
        long startTime = System.currentTimeMillis();
        //執行接口調用邏輯
        Result result = invoker.invoke(invocation);
        //調用耗時
        long elapsed = System.currentTimeMillis() - startTime;
        //若是發生異常 則打印異常日誌
        if (result.hasException() && invoker.getInterface() != GenericService.class) {
            LOGGER.error("dubbo執行異常: ", result.getException());
        } else {
            if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
                //打印響應日誌
                DubboServiceResponse serviceResponse = new DubboServiceResponse();
                serviceResponse.setMethodName(invocation.getMethodName());
                serviceResponse.setInterfaceName(invocation.getInvoker().getInterface().getName());
                serviceResponse.setArgs(invocation.getArguments());
                serviceResponse.setResult(new Object[]{result.getValue()});
                serviceResponse.setSpendTime(elapsed);
                LOGGER.info("dubbo服務響應成功,返回數據: " + JSON.toJSONString(serviceResponse));
            }
        }
        //返回結果響應結果
        return result;
    }
}

代碼中對應的實體bean以下:app

入參實體:分佈式

/**
 * @program: easywits
 * @description:Dubbo服務請求入參實體
 * @author: zhangshaolin
 * @create: 2019-01-08 20:35
 **/
@Data
public class DubboServiceRequest implements Serializable{
    private static final long serialVersionUID = 7127824956842786618L;

    /**
     * 接口名
     */
    private String interfaceName;

    /**
     * 方法名
     */
    private String methodName;

    /**
     * 參數
     */
    private Object[] args;
}

響應實體:ide

/**
 * @program: easywits
 * @description: Dubbo服務響應結果實體
 * @author: zhangshaolin
 * @create: 2019-01-08 20:36
 **/
@Data
public class DubboServiceResponse implements Serializable{
    private static final long serialVersionUID = -2531169660859647737L;

    /**
     * 接口名
     */
    private String interfaceName;

    /**
     * 方法名
     */
    private String methodName;

    /**
     * 參數
     */
    private Object[] args;

    /**
     * 返回結果
     */
    private Object result;

    /**
     * 調用耗時(毫秒)
     */
    private long spendTime;
}

/src/main/resources/META-INF/dubbo目錄下新增純文本文件org.apache.dubbo.rpc.Filter 內容爲:spa

dubboServiceFilter=com.easywits.common.filter.DubboServiceFilter
  • 鍵值對形式,鍵隨便起個名字
  • 值爲DubboServiceFilter攔截器的完整包名.

最後在服務提供者配置文件中添加配置使攔截器生效:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      ...省略部分代碼">

    <!--服務提供方應用信息,用於計算依賴關係-->
    <dubbo:application name="easywits-upms-rpc-service"/>

    <!--用dubbo協議在20881端口暴露服務-->
    <dubbo:protocol name="dubbo" port="20881" payload="52428800"/>

    <!--自定義服務層過濾器,值爲上述步驟文本文件中的鍵-->
    <dubbo:provider filter="dubboServiceFilter"/>
    
    ....省略部分服務配置
</beans>

驗證結果

抓一下咱們業務中的部分日誌信息看下效果,以下圖:

能夠清楚地看到Dubbo服務接口調用的請求參數信息,以及最終的響應結果信息,便於定位線上問題。

參考文檔:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html

最後

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

相關文章
相關標籤/搜索