preface
Spring AOP + Custom Annotations Unified Logging of user behavior Logging documents the process of automatically logging user behavior through custom annotations in conjunction with Spring AOP in the Web layer. Can unified logging be implemented according to the Dubbo service layer invocation process in distributed architecture? Custom log interceptors can fulfill this requirement.
Demand scenarios
In a distributed project built with Dubbo, the service layer code call looks like this:
@GetMapping(value = "/info")
2 public BaseResult userInfo(a) {
3 // RPC calls the user service remotely
4 BaseResult result = mUserService.userInfo();
6 return result;
7 }
Copy the code
Here, the user service is located in another service process, which is exposed by the service provider and called remotely by the Web layer. The call process of the service result needs to be recorded for tracking and locating bugs.
Custom log interceptor
Take a look at Dubbo’s official documentation and you’ll see the following:
Brief description:
Dubbo
All interceptors in theorg.apache.dubbo.rpc.Filter
Interface, we can extend ourselves by inheriting the interface.- User defined
filter
Default is built infilter
After performing
The new DubboServiceFilter interceptor is as follows:
public class DubboServiceFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceFilter.class);
@Override
public Result invoke(Invoker
invoker, Invocation invocation) throws RpcException {
// External logging is disabled by default
String logSwitch = StringUtils.equals(RedisUtil.get(BaseConstants.CACHE_SERVICE_LOG_SWITCH), BaseConstants.YES) ? BaseConstants.YES : BaseConstants.NO;
if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
// Prints the entry log
DubboServiceRequest serviceRequest = new DubboServiceRequest();
serviceRequest.setInterfaceName(invocation.getInvoker().getInterface().getName());
serviceRequest.setMethodName(invocation.getMethodName());
serviceRequest.setArgs(invocation.getArguments());
LOGGER.info("Dubbo service interface input parameter: + JSON.toJSONString(serviceRequest));
}
// Start time
long startTime = System.currentTimeMillis();
// Execute the interface call logic
Result result = invoker.invoke(invocation);
// Call time
long elapsed = System.currentTimeMillis() - startTime;
// If an exception occurs, an exception log is printed
if(result.hasException() && invoker.getInterface() ! = GenericService.class) { LOGGER.error("Dubbo execution exception:", result.getException());
} else {
if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
// Prints response logs
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 service responded successfully, return data:"+ JSON.toJSONString(serviceResponse)); }}// Return the result
returnresult; }}Copy the code
The corresponding entity bean in the code is as follows:
Input entity:
/ * * *@program: easywits
* @description:Dubbo service request entry entity *@author: zhangshaolin
* @create: the 2019-01-08 before * * /
@Data
public class DubboServiceRequest implements Serializable{
private static final long serialVersionUID = 7127824956842786618L;
/** * Interface name */
private String interfaceName;
/** * method name */
private String methodName;
/** * parameter */
private Object[] args;
}
Copy the code
Response entity:
/ * * *@program: easywits
* @description: Dubbo service response result entity *@author: zhangshaolin
* @create: in 2019-01-08 he joined * * /
@Data
public class DubboServiceResponse implements Serializable{
private static final long serialVersionUID = -2531169660859647737L;
/** * Interface name */
private String interfaceName;
/** * method name */
private String methodName;
/** * parameter */
private Object[] args;
/** * returns the result */
private Object result;
/** * Invocation time (ms) */
private long spendTime;
}
Copy the code
In/SRC/main/resources/meta-inf/dubbo new plain text file directory org. Apache. Dubbo. RPC. Filter the content as follows:
dubboServiceFilter=com.easywits.common.filter.DubboServiceFilter
Copy the code
- Key-value pairs, whatever the key is
- A value of
DubboServiceFilter
The full package name of the interceptor.
Finally add the configuration to the service provider profile to make the interceptor work:
<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" ... "> <! Dubbo :application name="easywits-upms-rpc-service"/> <! --> <dubbo:protocol name="dubbo" port="20881" payload="52428800"/> <! -- Customize the service layer filter. The value is the key in the text file in the preceding steps --> <dubbo: Provider filter="dubboServiceFilter"/>.... Omit partial service configuration </beans>Copy the code
The verification results
Take a look at some of the log information in our business to see the effect, as shown below:
You can clearly see the request parameter information of the Dubbo service interface invocation and the final response result information to locate online problems.
Reference: http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html
The last
Record a relatively simple specific practical scene, the follow-up will be updated from time to time more practical scene, welcome to pay attention to the public number [Zhang Shaolin students]!