The general idea is: add custom annotation (@oplog) to the interface that needs log statistics, and obtain parameter information and caller information of interface invocation through section. At the same time, in order not to affect the service, use MQ message queue to perform log entry operation

0. Define entity classes

@Table(name = "op_log")
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
public class OpLogEntity extends BaseEntity {
    /**
     * 接口名称
     */
    private String opApiName;
    /** * method signature */
    private String opMethodSignature;
    /** * the method enters the parameter */
    private String opMethodArgs;
    / * * * the HTTP method is POST/GET/HEAD/FETCH/DELETE * /
    private String opHttpMethod;
    /** * HTTP path from controller requestMapping to method requestMapping */
    private String opHttpPath;
    /** * url */
    private String opHttpUrl;
    /** * Log time (interface call time) */
    private Date opStartTime;
    /** * Total interface execution time (ms) */
    private Long opExecuteDuration;
    /** * interface caller id */
    private String opCallerId;
    /** * interface caller name */
    private String opCallerName;
    /** * interface caller token */
    private String opCallerToken;
    /** * Phone number of the interface caller */
    private String opCallerPhone;
    /** * interface caller IP */
    private String opCallerIp;
    /** * Interface execution result: 1- Normal return, 0- throw exception */
    private String opResultFlag;
    /** * Service execution result */
    private String opBusinessFlag;
    /** * Stack information when the interface executes an exception */
    private String opResultThrow;
}
Copy the code

1. Define annotations

// OpLog.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface OpLog {
    String apiName(a);
}
Copy the code

2. Aspect section processing classes

// Oplogaspect.java has been simplified
@Aspect
@Component
public class OpLogAspect {
    private static Logger logger = LoggerFactory.getLogger(OpLogAspect.class);
    
    @Autowired
    private RabbitMqSender rabbitMqSender;
    
    private volatile JoinPoint joinPoint;
    private long startTime;
    private OpLogVO opLogVO;
    
    @Pointcut(value = "@annotation(com.example.aop.OpLog)")
    public void opLogPointCut(a) {}// Get interface information from attributes, signature and other objects before and save it in opLogVO
    @Before(value = "opLogPointCut()")
    public void logBefore(JoinPoint joinPoint) {
        try {
            this.joinPoint = joinPoint;
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            DateTime now = DateUtil.date();
            startTime = now.toTimestamp().getTime();
            opLogVO = new OpLogVO();
            opLogVO.setOpStartTime(now.toJdkDate());
            Signature signature = joinPoint.getSignature();
            if (signature instanceof MethodSignature) {
                String apiName = ((MethodSignature) signature).getMethod().getAnnotation(OpLog.class).apiName();
                opLogVO.setOpApiName(apiName);
                setMethodAndPath(joinPoint, (MethodSignature) signature);
                setMethodArgs(joinPoint, (MethodSignature) signature);
            }
            opLogVO.setOpMethodSignature(signature.toString());
            if (attributes instanceofServletRequestAttributes) { HttpServletRequest servletRequest = ((ServletRequestAttributes) attributes).getRequest(); opLogVO.setOpHttpUrl(servletRequest.getRequestURL().toString()); opLogVO.setOpCallerIp(getIpAddress(servletRequest)); }}catch (Exception e) {
            logger.error("Section processing operation log exception! logBefore-", e); }}AfterReturning An OpLogVO object with information is sent to the MQ queue
    @AfterReturning(value = "opLogPointCut()", returning = "returnValue")
    public void logAfterReturning(JoinPoint joinPoint, Object returnValue) {
        if (this.joinPoint == joinPoint) {
            try {
                long executeDuration = System.currentTimeMillis() - startTime;
                opLogVO.setOpExecuteDuration(executeDuration);
                opLogVO.setOpResultFlag("1");
                / / rabbitMqSender is simple encapsulation of the RabbitMQ, eventually call RabbitTemplate. ConvertAndSend (String routingKey, Object Object) method
                rabbitMqSender.send(RabbitConfigCommon.OP_LOG_MQ, JSONUtil.toJsonStr(opLogVO));
            } catch (Exception e) {
                logger.error("Section processing operation log exception! logAfterReturning-", e); }}}// AfterThrowing indicates that an exception occurs on the interface and the exception stack is saved to an OpLogVO object and sent to the MQ queue
    @AfterThrowing(value = "opLogPointCut()", throwing = "throwValue")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable throwValue) {
        if (this.joinPoint == joinPoint) {
            try {
                long executeDuration = System.currentTimeMillis() - startTime;
                opLogVO.setOpExecuteDuration(executeDuration);
                opLogVO.setOpResultFlag("0");
                // import cn.hutool.core.exceptions.ExceptionUtil;
                String stacktrace = ExceptionUtil.stacktraceToString(throwValue);
                opLogVO.setOpResultThrow(StrUtil.sub(stacktrace, 0.450));
                rabbitMqSender.send(RabbitConfigCommon.OP_LOG_MQ, JSONUtil.toJsonStr(opLogVO));
            } catch (Exception e) {
                logger.error("Section processing operation log exception! logAfterThrowing-", e); }}}}Copy the code

3. RabbitMQ consumers

// RabbitMqReceiver.java
@Component
public class RabbitMqReceiver {
    // OpLogBusi is the Business that saves opLogVO to the database
    @Autowired
    private OpLogBusi opLogBusi;
    
     @RabbitListener(bindings = @QueueBinding(value = @Queue(value = RabbitConfigCommon.OP_LOG_MQ, durable = "true"), exchange = @Exchange(value = "ALL"), key = RabbitConfigCommon.OP_LOG_MQ))
    public void consumeSaveOpLogMessage(String opLogVO) {
    	// opLogBusi.saveOpLog() --> opLogService.save() --> opLogDao.save()opLogBusi.saveOpLog(JSONUtil.toBean(opLogVO, OpLogVO.class)); }}Copy the code

Use 4.

	// PersonController.javaYou just add it to the method@OpLogAnnotations can be@oplog (apiName = "query personal information ")
    @RequestMapping(value = "/getPersonInfo",method = RequestMethod.POST)
    public ResultBean<StaticData> getPersonInfo(@RequestBody QueryPersonInfo queryPersonInfo) {}Copy the code

5. To summarize

@oplog () → Aspect section → Analyze to get interface call information → send to MQ queue → receive and consume messages → save to database