Why is AOP logging important?

When the System scale is large, it is very troublesome to use breakpoint check or system.out.println directly: when the project is large and divided into multiple services, for various reasons, the cost of local startup is high or the local environment cannot be started, so you have to go ahead (temporary online).

While remote breakpoint debugging is possible, it is limited to pre-dispatch, and breakpoint debugging is not possible in an online environment (forwarding requests locally). Online data is inconsistent with local data, and sometimes bugs do not recur

Even if you can debug locally, you need to pull the latest master code, start the project, construct the request data, breakpoint read, and a lot of other operations.

Proper solution: Log –> log. Log in to the server to see the log, set up a special ELK log system, you can choose the corresponding machine on the page and cooperate with Lucene statements to view the log.

AOP

AOP completes the steps required to complete the requirements:

  • The SpringBoot project needs to import the Spring-boot-starter-AOP dependency
  • Write the aspect class
  • Turn the aspect classes over to Spring

Write the section class steps

The @aspect annotation on the class indicates that it is a faceted class

We need to hand over the aspect class to Spring management. (The Controller/Service we are cutting is the Spring container, and the aspect must also be in the container to work on them.)

The PointCut class internally writes PointCut expressions such as @pointcut (” Execution (* com.jt.controller.. (..) ) “) represents facet enhancement for all methods under com.jt.controller.

The section class writes the enhancement logic inside, @before, @around, to indicate that this is an enhancement, and different annotations are enhanced in different ways. Interface request time AOP Demo

` @Aspect

@Slf4j

public class APITimeLogAspect {

// Write the @enabletimelog annotation to load the aspect class into the Spring container and put the annotation on the startup class // Step 2 write the pointcut expression /** * pointcut expression to indicate that all methods under com.jt.projects need to be enhanced (public) */  @Pointcut("execution(* com.jt.projects.aop.controllers.*.* (..) )") public void pointCut(){} @Around("pointCut()") public Object doAround(ProceedingJoinPoint joinPoint){ Long startTime  = System.currentTimeMillis(); Object proceed = null; try { proceed = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } the info (" -- -- -- -- -- -- -- time -- -- -- -- -- -- -- -- {} ", (System. CurrentTimeMillis () - startTime)); return proceed; }Copy the code

} “add the aspect class to the Spring container: You can add @Component directly to the aspect class. You can define a new annotation to load the aspect class into the @import annotation. The corresponding Bean is instantiated and loaded into the container. AOP prints request-related logs: Typically logs are printed in critical code, and when confronted with interfaces that do not print logs, we have a hard time locating the problem. This kind of log is local and special. So it is necessary to define global, generic logging. Interface URL: which interface class name to request Method: which class to locate which method request parameter: @aspect @slf4j public class ApiLogAspect {/** * All methods under com.jt.projects need to be enhanced (public) / @Pointcut(“execution( com.jt.projects.aop.controllers.. (..) )”) public void pointCut(){}

@Autowired HttpServletRequest request; @Autowired ObjectMapper objectMapper; @Around("pointCut()") public Object doAround(ProceedingJoinPoint joinPoint){ LogEntity logEntity = new LogEntity(); // Method Signature = joinPoint.getSignature(); String classSimpleName = signature.getDeclaringType().getSimpleName(); String className = signature.getDeclaringType().getName(); String methodName = signature.getName(); LogEntity. SetMethodName (String. Format (" Class name: Method called % s % s, methods, the full path for % s ", classSimpleName, methodName, (className + "#" + methodName))); LogEntity. SetUrl (" interface URL: "+ request.getrequesturi () +" Request type: "+ Request.getMethod ()); XFF = Request.getheader (" X-Forwarded-for "); // If this item is forwarded-to XFF, it is Forwarded to forwarded-to XFF. if (xff == null) { xff = request.getRemoteAddr(); } else { xff = xff.contains(",") ? xff.split(",")[0] : xff; } logEntity. SetRemoteAddress (" remote call interface: "+ XFF); String queryParam = ""; Object[] objects = Arrays.stream(joinPoint.getArgs()).filter(arg -> ! (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile)).toArray(); queryParam = objectMapper.valueToTree(objects).toPrettyString(); if ("GET".equals(request.getMethod())){ queryParam = request.getQueryString(); } logEntity.setRequestArgs(queryParam); Object proceed = null; try { Long startTime = System.currentTimeMillis(); proceed = joinPoint.proceed(); logEntity.setTimeConsuming(System.currentTimeMillis() - startTime); } catch (Throwable throwable) { throwable.printStackTrace(); Log.info (" exception message: {}", throwable.getMessage()); } log.info(" Log information: {}",logEntity); return proceed; }Copy the code

Interface methods calling private methods do not go AOP.

Optimization In general we use pointcut expressions to control which classes need to be enhanced. But sometimes it may not be fine-grained or flexible enough to work with annotations.

/ * *

  • On a pointcut expression class or method annotated by ApiLog and without Ignore

*/ @Pointcut(“( @annotation(com.jt.projects.aop.annations.ApiLog) ” + “|| @within(com.jt.projects.aop.annations.ApiLog) “+” &&! @annotation(com.jt.projects.aop.annations.IgnoreApiLog)”) public void pointCut(){}

@Aspect public class ApiUserLogAspect { @Autowired UserLogService userLogService; @Autowired ObjectMapper objectMapper; @Autowired HttpServletRequest request; / * * * set the point of tangency expression Only to use the @ UserLog * / the @pointcut (” @ the annotation (com. Jt. Projects. Aop. Annations. UserLog) “) public void Pointcut () {}

@AfterReturning("pointCut()") public void afterReturning(JoinPoint joinpoint){ saveSysUserLog((ProceedingJoinPoint) joinpoint); } private void saveSysUserLog(ProceedingJoinPoint joinpoint) { UserDTO userDTO = getUserDTO(); MethodSignature signature = (MethodSignature) joinpoint.getSignature(); Method method = signature.getMethod(); UserLog annotation = method.getAnnotation(UserLog.class); if (annotation == null){ return; } / / when methods have UserLog annotate records into the database Collect related information and save the UserLogDTO UserLogDTO = buildUserLogDTO (userDTO joinpoint, the annotation); // Save to the database userLogService.addsyslog (userLogDTO); } private UserLogDTO buildUserLogDTO(UserDTO userDTO, ProceedingJoinPoint joinpoint, UserLog annotation) { UserLogDTO userLogDTO = new UserLogDTO(); userLogDTO.setOperatorId(userDTO.getId()); userLogDTO.setType(annotation.operationType().getValue()); userLogDTO.setTitle(annotation.title()); userLogDTO.setModuleCode(annotation.module().getModuleCode()); userLogDTO.setContent(getContent(joinpoint)); userLogDTO.setOperateTime(new Date()); return userLogDTO; } private String getContent(ProceedingJoinPoint joinpoint) { if ("GET".equals(request.getMethod())){ return request.getQueryString(); } Object[] objects = Arrays.stream(joinpoint.getArgs()).filter(arg -> ! (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile)).toArray(); return objectMapper.valueToTree(objects).toPrettyString(); } private UserDTO getUserDTO() { UserDTO userDTO = (UserDTO)ThreadLocalUtilV4.get("userDTO"); return userDTO; }Copy the code

}

This article is part of the “Gold Nuggets For Free!” Activity, click to viewEvent details