Home  >  Article  >  Java  >  How to implement logging in CompletableFuture in Java

How to implement logging in CompletableFuture in Java

王林
王林forward
2023-05-18 15:22:06753browse

1. First use aop to add requestId to all request entries.

@Aspect
@Component
public class LoggingAspect {

    /**
     * AOP注解的Controller类方法必须为 public 或 protect ,千万不能用private!!!!!!!!否则会@Autowired注入的service会报空指针异常。
     * 私有方法和字段不属于Spring上下文中的bean属性。
     */
    @Around("@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PutMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 在logback-spring.xml里对应%X{requestId}
        MDC.put("requestId", UUID.randomUUID().toString().substring(0, 13));  // Add request ID to MDC
        try {
            return joinPoint.proceed(); // Execute method
        } finally {
            MDC.remove("requestId");  // Remove request ID from MDC
        }
    }
}

2. Define logback-spring.xml and introduce requestId for link recording. The key code is %X{requestId}



    
    
    
    
    
    
    
    
        
            
                debug
            
            
            ${CONSOLE_LOG_PATTERN}
            
            UTF-8
        
    


    
    
    
    
    
        ${LOG_FILE_PATH}/debug.log 
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} %X{requestId} [%thread] %-5level %logger{50} - %msg%n
            UTF-8
        
        
        
            
            ${LOG_FILE_PATH}/debug-%d{yyyy-MM-dd}.%i.log
            
            
                100MB
            
            
            15
            
            1GB
        
        
        
            debug
            ACCEPT
            DENY
        
    

    
    
        ${LOG_FILE_PATH}/info.log
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} %X{requestId} [%thread] %-5level %logger{50} - %msg%n
            UTF-8
        
        
            ${LOG_FILE_PATH}/info-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            15
        
        
        
            info
            ACCEPT
            DENY
        
    

    
    
        ${LOG_FILE_PATH}/warn.log
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} %X{requestId} [%thread] %-5level %logger{50} - %msg%n
            UTF-8 
        
        
            ${LOG_FILE_PATH}/warn-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            15
        
        
        
            warn
            ACCEPT
            DENY
        
    

    
    
        ${LOG_FILE_PATH}/error.log
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} %X{requestId} [%thread] %-5level %logger{50} - %msg%n
            UTF-8
        
        
            ${LOG_FILE_PATH}/error-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            15
        
        
        
            ERROR
            ACCEPT
            DENY
        
    

    
    
        
    
    
        
    
    
        
    
    
        
    

    
    
        
        
        
        
        
    


2. Define a `complex` business process, Let’s take a look at the strength of the log

private final ExecutorService executorService = Executors.newFixedThreadPool(4);

@GetMapping("saveUser")
    public String saveUser() {
    log.info("进入了saveUser");
    // 异步
    CompletableFuture.runAsync(()-> b(), executorService);
    log.info("退出了saveUser");
    return "Ok";
}

private void b() {
    log.info("进入了b");
}

The log is as follows. You can see that the requestId of the asynchronous thread is lost. 21dbaad3-3158 This is the requestId. In this case, we need to customize the thread class to save the MDC context

2023-04-19 11:51:59.309 21dbaad3-3158 INFO 23044 --- [p-nio-80-exec-1] c.h.m.api.CompletableFutureApi : Entered saveUser
2023-04 -19 11: 51: 59.312 21DBAAD3-3158 Info 23044 --- [P-Nio-80-EXEC-1] C.H.M.API.COMPLETABLEFUTUREAPI: Exit Saveuser
2023-04-19 11: 51: 59.312 Info 23044- -- [pool-1-thread-1] c.h.m.api.CompletableFutureApi : Enter b

3. Define the thread implementation class and store the MDC context in the constructor

public static class MdcTaskWrapper implements Runnable {
    private final Runnable task;
    private final Map contextMap;

    public MdcTaskWrapper(Runnable task) {
        this.task = task;
        this.contextMap = MDC.getCopyOfContextMap();
    }

    @Override
    public void run() {
        if (contextMap != null) {
            MDC.setContextMap(contextMap);
        }
        try {
            task.run();
        } finally {
            MDC.clear();
        }
    }
}

4. Next, rewrite how to use runAsync. We use MdcTaskWrapper to perform thread operations. This thread class contains the mdc context

@GetMapping("saveUser")
public String saveUser() {
    log.info("进入了saveUser");
    // 异步
    CompletableFuture.runAsync(this::b, command -> executorService.execute(new MdcTaskWrapper(command)));
    log.info("退出了saveUser");
    return "Ok";
}

private void b() {
    log.info("进入了b");
}

. As you can see, requestId: 4ab037ab-92cb, the asynchronous thread can get it. MDC context, and the link log is successfully recorded

2023-04-19 11:58:27.581 4ab037ab-92cb INFO 6816 --- [p-nio-80-exec-5] c.h.m.api .CompletableFutureApi : Entered saveUser
2023-04-19 11:58:27.582 4ab037ab-92cb INFO 6816 --- [p-nio-80-exec-5] c.h.m.api.CompletableFutureApi : Exited saveUser
2023 -04-19 11:58:27.582 4ab037ab-92cb INFO 6816 --- [pool-1-thread-1] c.h.m.api.CompletableFutureApi

The above is the detailed content of How to implement logging in CompletableFuture in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete