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:

  • DubboAll interceptors in theorg.apache.dubbo.rpc.FilterInterface, we can extend ourselves by inheriting the interface.
  • User definedfilterDefault is built infilterAfter 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 ofDubboServiceFilterThe 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]!