Write a log request section, front and rear end thrown pot is more convenient

Recently project into the FBI stage, interfaces and protocol layers need to interact with the service layer, the protocol layer is necessary to reference [json String] json string assembly into a desired service layer, the assembly process is prone to error. Error leads into the reference interface debug failures occur many times in the FBI, and therefore wanted to write a request to log into the reference section to print information about the same time the protocol layer calls the service layer interface name is not on there a few times, by request logs section you can know whether there is no upper initiate calls, convenient front and rear end thrown pot can produce evidence

EDITORIAL

This article is actual combat, for the principles of section does not explain, only a brief section of knowledge

Introduction section

Oriented Programming is a programming paradigm, as a supplement to an object-oriented programming OOP for distributed processing system crosscutting concerns in each module, such as transaction management , access control , cache control , log printing and the like. AOP functionality to the software module is divided into two parts: the core concerns and crosscutting concerns. The main function of the core business processes of concern, rather than a core, needs to develop capabilities for crosscutting concerns. AOP is that the various concerns separation system, the core concerns and crosscutting concerns were separated using the section has the following advantages:

  • Focus on a concern / crosscutting logic
  • You can easily add / remove concerns
  • Less invasive, thus enhancing maintainability code readability and when you want to print section will readily occur to request log, intrusion control level code 0

Using annotation-based section of []

  • @Aspect => declare the class as a class comment

Cut-off point Notes:

  • @Pointcut => defines a cut point, the code can be simplified

Notice Note:

  • @Before => executed code before the tangent point
  • @After => code execution after the point of tangency
  • @AfterReturning => tangent point execution code returned content, the return value may be encapsulated tangent point
  • @AfterThrowing => thrown performed after the point of tangency
  • @Around => surrounds, the execution code before and after the point of tangency

Hands write a request log section

  • Cut point is defined using @Pointcut
    @Pointcut("execution(* your_package.controller..*(..))")
    public void requestServer() {
    }
    复制代码
    @Pointcut defines a tangent point, since the request for trimming the log, and therefore the tangent point is defined by a method in all classes in the package Controller. Defined cut-off point for future use requestServer method name in the notification directly comment on it
  • Before using @Before then cut point execution
    @Before("requestServer()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) 
    RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
    
        LOGGER.info("===============================Start========================");
        LOGGER.info("IP                 : {}", request.getRemoteAddr());
        LOGGER.info("URL                : {}", request.getRequestURL().toString());
        LOGGER.info("HTTP Method        : {}", request.getMethod());
        LOGGER.info("Class Method       : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
    }
    复制代码
    Before entering the Controller method, print out the caller IP, requested URL, HTTP request type, call the method name
  • Use @Around print parameters entered into the control layer
    @Around("requestServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        LOGGER.info("Request Params       : {}", getRequestParams(proceedingJoinPoint));
        LOGGER.info("Result               : {}", result);
        LOGGER.info("Time Cost            : {} ms", System.currentTimeMillis() - start);
    
        return result;
    }
    复制代码
    Print into the Senate, as well as the results of time-consuming
    • getRquestParams method
      private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
           Map<String, Object> requestParams = new HashMap<>();
      
            //参数名
           String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
           //参数值
           Object[] paramValues = proceedingJoinPoint.getArgs();
      
           for (int i = 0; i < paramNames.length; i++) {
               Object value = paramValues[i];
      
               //如果是文件对象
               if (value instanceof MultipartFile) {
                   MultipartFile file = (MultipartFile) value;
                   value = file.getOriginalFilename();  //获取文件名
               }
      
               requestParams.put(paramNames[i], value);
           }
      
           return requestParams;
       }
      复制代码
      By @PathVariable and annotation parameters @RequestParam passed parameter name can not be printed out, so you need to manually stitching at the parameter name, and a file object for a special treatment, just get the file name
  • After calling the execution method @After
    @After("requestServer()")
    public void doAfter(JoinPoint joinPoint) {
        LOGGER.info("===============================End========================");
    }
    复制代码

No business logic just print the End

  • Complete Code section
    @Component
    @Aspect
    public class RequestLogAspect {
        private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);
    
        @Pointcut("execution(* your_package.controller..*(..))")
        public void requestServer() {
        }
    
        @Before("requestServer()")
        public void doBefore(JoinPoint joinPoint) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) 
    RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    
            LOGGER.info("===============================Start========================");
            LOGGER.info("IP                 : {}", request.getRemoteAddr());
            LOGGER.info("URL                : {}", request.getRequestURL().toString());
            LOGGER.info("HTTP Method        : {}", request.getMethod());
            LOGGER.info("Class Method       : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), 
     joinPoint.getSignature().getName());
        }
    
    
        @Around("requestServer()")
        public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            long start = System.currentTimeMillis();
            Object result = proceedingJoinPoint.proceed();
            LOGGER.info("Request Params     : {}", getRequestParams(proceedingJoinPoint));
            LOGGER.info("Result               : {}", result);
            LOGGER.info("Time Cost            : {} ms", System.currentTimeMillis() - start);
    
            return result;
        }
    
        @After("requestServer()")
        public void doAfter(JoinPoint joinPoint) {
            LOGGER.info("===============================End========================");
        }
    
        /**
         * 获取入参
         * @param proceedingJoinPoint
         *
         * @return
         * */
        private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
            Map<String, Object> requestParams = new HashMap<>();
    
            //参数名
            String[] paramNames = 
    ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
            //参数值
            Object[] paramValues = proceedingJoinPoint.getArgs();
    
            for (int i = 0; i < paramNames.length; i++) {
                Object value = paramValues[i];
    
                //如果是文件对象
                if (value instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) value;
                    value = file.getOriginalFilename();  //获取文件名
                }
    
                requestParams.put(paramNames[i], value);
            }
    
            return requestParams;
        }
    }
    复制代码

Highly concurrent request log section

After writing very satisfied with their code, but think there may be the perfect place to share a moment with friends. emmmm

Sure enough, there continue to optimize where information is printed for each line, print the log is indeed a problem between the serial request will appear at high concurrent requests, request the testing phase because a smaller number of cases of serial no, it really was the production environment the first is the development of power, can meet more bug, write more robust code to solve the problem as long as the log of the serial multi-line print information as a single line on it, and therefore construct an object

  • RequestInfo.java

    @Data
    public class RequestInfo {
        private String ip;
        private String url;
        private String httpMethod;
        private String classMethod;
        private Object requestParams;
        private Object result;
        private Long timeCost;
    }
    复制代码
  • Around the notification method thereof

    @Around("requestServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object result = proceedingJoinPoint.proceed();
        RequestInfo requestInfo = new RequestInfo();
                requestInfo.setIp(request.getRemoteAddr());
        requestInfo.setUrl(request.getRequestURL().toString());
        requestInfo.setHttpMethod(request.getMethod());
        requestInfo.setClassMethod(String.format("%s.%s", proceedingJoinPoint.getSignature().getDeclaringTypeName(),
                proceedingJoinPoint.getSignature().getName()));
        requestInfo.setRequestParams(getRequestParamsByProceedingJoinPoint(proceedingJoinPoint));
        requestInfo.setResult(result);
        requestInfo.setTimeCost(System.currentTimeMillis() - start);
        LOGGER.info("Request Info      : {}", JSON.toJSONString(requestInfo));
    
        return result;
    }
    复制代码

    The url, http request information assembled into RequestInfo objects, then serialize objects print
    print serialized objects and not the result of direct printing of the target sequence is because there is more intuitive and clear, at the same time can make use of online analytical tools for parsing results

Is not bad
at the same time added to address the high concurrency problems on the serial request an exception request printed information , is processed by using the method throws an exception @AfterThrowing comment

  • RequestErrorInfo.java

    @Data
    public class RequestErrorInfo {
        private String ip;
        private String url;
        private String httpMethod;
        private String classMethod;
        private Object requestParams;
        private RuntimeException exception;
    }
    复制代码
  • Abnormal notice around the body

    @AfterThrowing(pointcut = "requestServer()", throwing = "e")
    public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
        requestErrorInfo.setIp(request.getRemoteAddr());
        requestErrorInfo.setUrl(request.getRequestURL().toString());
        requestErrorInfo.setHttpMethod(request.getMethod());
        requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName()));
        requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
        requestErrorInfo.setException(e);
        LOGGER.info("Error Request Info      : {}", JSON.toJSONString(requestErrorInfo));
    }
    复制代码

    For exceptions, no sense of time-consuming, and therefore does not count time-consuming, but added an exception print

Finally, put about a complete log of requests section of code:

@Component
@Aspect
public class RequestLogAspect {
    private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);

    @Pointcut("execution(* your_package.controller..*(..))")
    public void requestServer() {
    }

    @Around("requestServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object result = proceedingJoinPoint.proceed();
        RequestInfo requestInfo = new RequestInfo();
                requestInfo.setIp(request.getRemoteAddr());
        requestInfo.setUrl(request.getRequestURL().toString());
        requestInfo.setHttpMethod(request.getMethod());
        requestInfo.setClassMethod(String.format("%s.%s", proceedingJoinPoint.getSignature().getDeclaringTypeName(),
                proceedingJoinPoint.getSignature().getName()));
        requestInfo.setRequestParams(getRequestParamsByProceedingJoinPoint(proceedingJoinPoint));
        requestInfo.setResult(result);
        requestInfo.setTimeCost(System.currentTimeMillis() - start);
        LOGGER.info("Request Info      : {}", JSON.toJSONString(requestInfo));

        return result;
    }


    @AfterThrowing(pointcut = "requestServer()", throwing = "e")
    public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
        requestErrorInfo.setIp(request.getRemoteAddr());
        requestErrorInfo.setUrl(request.getRequestURL().toString());
        requestErrorInfo.setHttpMethod(request.getMethod());
        requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName()));
        requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
        requestErrorInfo.setException(e);
        LOGGER.info("Error Request Info      : {}", JSON.toJSONString(requestErrorInfo));
    }

    /**
     * 获取入参
     * @param proceedingJoinPoint
     *
     * @return
     * */
    private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
        //参数名
        String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
        //参数值
        Object[] paramValues = proceedingJoinPoint.getArgs();

        return buildRequestParam(paramNames, paramValues);
    }

    private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
        //参数名
        String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
        //参数值
        Object[] paramValues = joinPoint.getArgs();

        return buildRequestParam(paramNames, paramValues);
    }

    private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
        Map<String, Object> requestParams = new HashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            Object value = paramValues[i];

            //如果是文件对象
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                value = file.getOriginalFilename();  //获取文件名
            }

            requestParams.put(paramNames[i], value);
        }

        return requestParams;
    }

    @Data
    public class RequestInfo {
        private String ip;
        private String url;
        private String httpMethod;
        private String classMethod;
        private Object requestParams;
        private Object result;
        private Long timeCost;
    }

    @Data
    public class RequestErrorInfo {
        private String ip;
        private String url;
        private String httpMethod;
        private String classMethod;
        private Object requestParams;
        private RuntimeException exception;
    }
}
复制代码

Hastened to add your application if it did not add [then], no log, then always suspected upper mistake, but no evidence

Guess you like

Origin juejin.im/post/5e69d5b5e51d45183840b351