Dubbo自定义日志拦截器
前言
上一篇文章 Spring aop+自定義注解統(tǒng)一記錄用戶行為日志 記錄了 web層中通過自定義注解配合Spring aop自動記錄用戶行為日志的過程。那么按照分布式架構(gòu)中Dubbo服務(wù)層的調(diào)用過程是否也可以實(shí)現(xiàn)統(tǒng)一記錄日志?自定義日志攔截器可以實(shí)現(xiàn)這個需求。
需求場景
在使用Dubbo搭建的分布式項目中,服務(wù)層代碼調(diào)用是這樣的:
@GetMapping(value = "/info") 2 public BaseResult userInfo() { 3 //rpc遠(yuǎn)程調(diào)用用戶服務(wù) 4 BaseResult result = mUserService.userInfo(); 6 return result; 7 }這里的用戶服務(wù)位于另外一個服務(wù)進(jìn)程,由服務(wù)提供者暴露出來,讓web層遠(yuǎn)程調(diào)用,需要記錄服務(wù)結(jié)果的調(diào)用過程,便于跟蹤定位bug.
自定義日志攔截器
翻看下Dubbo官方文檔,可以看到如下內(nèi)容:
簡要說明:
- Dubbo 中所有的攔截器全部繼承自org.apache.dubbo.rpc.Filter接口,我們自己也可以自行擴(kuò)展,只要繼承該接口即可.
- 用戶自定義 filter 默認(rèn)在內(nèi)置 filter 之后執(zhí)行
新增 DubboServiceFilter 攔截器如下:
public class DubboServiceFilter implements Filter {private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceFilter.class);@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {//外部日志開關(guān)默認(rèn)關(guān)閉String logSwitch = StringUtils.equals(RedisUtil.get(BaseConstants.CACHE_SERVICE_LOG_SWITCH), BaseConstants.YES) ? BaseConstants.YES : BaseConstants.NO;if (StringUtils.equals(BaseConstants.YES, logSwitch)) {//打印入?yún)⑷罩綝ubboServiceRequest serviceRequest = new DubboServiceRequest();serviceRequest.setInterfaceName(invocation.getInvoker().getInterface().getName());serviceRequest.setMethodName(invocation.getMethodName());serviceRequest.setArgs(invocation.getArguments());LOGGER.info("dubbo服務(wù)接口入?yún)? " + JSON.toJSONString(serviceRequest));}//開始時間long startTime = System.currentTimeMillis();//執(zhí)行接口調(diào)用邏輯Result result = invoker.invoke(invocation);//調(diào)用耗時long elapsed = System.currentTimeMillis() - startTime;//如果發(fā)生異常 則打印異常日志if (result.hasException() && invoker.getInterface() != GenericService.class) {LOGGER.error("dubbo執(zhí)行異常: ", result.getException());} else {if (StringUtils.equals(BaseConstants.YES, logSwitch)) {//打印響應(yīng)日志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服務(wù)響應(yīng)成功,返回數(shù)據(jù): " + JSON.toJSONString(serviceResponse));}}//返回結(jié)果響應(yīng)結(jié)果return result;} }代碼中對應(yīng)的實(shí)體bean如下:
入?yún)?shí)體:
/*** @program: easywits* @description:Dubbo服務(wù)請求入?yún)?shí)體* @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;/*** 參數(shù)*/private Object[] args; }響應(yīng)實(shí)體:
/*** @program: easywits* @description: Dubbo服務(wù)響應(yīng)結(jié)果實(shí)體* @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;/*** 參數(shù)*/private Object[] args;/*** 返回結(jié)果*/private Object result;/*** 調(diào)用耗時(毫秒)*/private long spendTime; }在/src/main/resources/META-INF/dubbo目錄下新增純文本文件org.apache.dubbo.rpc.Filter 內(nèi)容為:
dubboServiceFilter=com.easywits.common.filter.DubboServiceFilter- 鍵值對形式,鍵隨便起個名字
- 值為DubboServiceFilter攔截器的完整包名.
最后在服務(wù)提供者配置文件中添加配置使攔截器生效:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"...省略部分代碼"><!--服務(wù)提供方應(yīng)用信息,用于計算依賴關(guān)系--><dubbo:application name="easywits-upms-rpc-service"/><!--用dubbo協(xié)議在20881端口暴露服務(wù)--><dubbo:protocol name="dubbo" port="20881" payload="52428800"/><!--自定義服務(wù)層過濾器,值為上述步驟文本文件中的鍵--><dubbo:provider filter="dubboServiceFilter"/>....省略部分服務(wù)配置 </beans>驗證結(jié)果
抓一下我們業(yè)務(wù)中的部分日志信息看下效果,如下圖:
可以清楚地看到Dubbo服務(wù)接口調(diào)用的請求參數(shù)信息,以及最終的響應(yīng)結(jié)果信息,便于定位線上問題。
參考文檔:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html
最后
記錄一個比較簡單的具體實(shí)用場景,后續(xù)會不定期更新更多的實(shí)用場景,歡迎關(guān)注公眾號【張少林同學(xué)】!
總結(jié)
以上是生活随笔為你收集整理的Dubbo自定义日志拦截器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 控制反转(ioc)和 面向切面(AOP)
- 下一篇: js 克隆数组