SpringBoot 프로젝트 에 MDC 로그 링크 추적 을 추가 하 는 실행 절차

로그 링크 추적 은 하나의 로 고 를 스 레 드 로 전달 하 는 것 을 의미 합 니 다.일반적인 작은 프로젝트 에서 스 레 드 를 새로 만 들 때 나 스 레 드 탱크 를 사용 하여 임 무 를 수행 할 때 사용 합 니 다.예 를 들 어 사용자 가 요청 한 전체 실행 절 차 를 추적 하 는 것 입 니 다.
여기에 사용MDCThreadLocal은 각각 아래 의 가방 에서 제공 합 니 다.

java.lang.ThreadLocal
org.slf4j.MDC
직접 코드 올 리 기:
1.스 레 드 탱크 설정
만약 에 수 동 으로 새 스 레 드 를 통 해 비동기 임 무 를 수행 하고 표지 전달 을 실현 하려 면 스스로 실현 해 야 합 니 다.사실은 스 레 드 탱크 와 마찬가지 로 호출MDC과 관련 된 방법 입 니 다.다음 과 같 습 니 다.

//      MDC
Map<String, String> context = MDC.getCopyOfContextMap();
//     MDC       
MDC.setContextMap(context);
우선 상수 제공:

package com.example.demo.common.constant;

/**
 *   
 *
 * @author wangbo
 * @date 2021/5/13
 */
public class Constants {
    public static final String LOG_MDC_ID = "trace_id";
}
다음은ThreadPoolTaskExecutor의 방법 을 다시 써 야 한다.

package com.example.demo.common.threadpool;

import com.example.demo.common.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * MDC   
 *       
 *
 * @author wangbo
 * @date 2021/5/13
 */
@Slf4j
public class MdcTaskExecutor extends ThreadPoolTaskExecutor {

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        log.info("mdc thread pool task executor submit");
        Map<String, String> context = MDC.getCopyOfContextMap();
        return super.submit(() -> {
            T result;
            if (context != null) {
                //     MDC       
                MDC.setContextMap(context);
            } else {
                //        MDC
                MDC.put(Constants.LOG_MDC_ID, UUID.randomUUID().toString().replace("-", ""));
            }
            try {
                //    
                result = task.call();
            } finally {
                try {
                    MDC.clear();
                } catch (Exception e) {
                    log.warn("MDC clear exception", e);
                }
            }
            return result;
        });
    }

    @Override
    public void execute(Runnable task) {
        log.info("mdc thread pool task executor execute");
        Map<String, String> context = MDC.getCopyOfContextMap();
        super.execute(() -> {
            if (context != null) {
                //     MDC       
                MDC.setContextMap(context);
            } else {
                //        MDC
                MDC.put(Constants.LOG_MDC_ID, UUID.randomUUID().toString().replace("-", ""));
            }
            try {
                //    
                task.run();
            } finally {
                try {
                    MDC.clear();
                } catch (Exception e) {
                    log.warn("MDC clear exception", e);
                }
            }
        });
    }
}
그 다음 에 사용자 정의 재 작성 서브 클래스MdcTaskExecutor를 사용 하여 스 레 드 풀 설정 을 실현 합 니 다.

package com.example.demo.common.threadpool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 *      
 *
 * @author wangbo
 * @date 2021/5/13
 */
@Slf4j
@Configuration
public class ThreadPoolConfig {
    /**
     *        
     *            ,       MDC  
     */
    @Bean
    public Executor commonThreadPool() {
        log.info("start init common thread pool");
        //ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        MdcTaskExecutor executor = new MdcTaskExecutor();
        //       
        executor.setCorePoolSize(10);
        //       
        executor.setMaxPoolSize(20);
        //      
        executor.setQueueCapacity(3000);
        //          
        executor.setKeepAliveSeconds(120);
        //              
        executor.setThreadNamePrefix("common-thread-pool-");
        //                  
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        //     
        executor.initialize();
        return executor;
    }

    /**
     *        
     *             ,      MDC  ,     ,      MDC
     *            ,      
     */
    @Bean
    public Executor scheduleThreadPool() {
        log.info("start init schedule thread pool");
        MdcTaskExecutor executor = new MdcTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(3000);
        executor.setKeepAliveSeconds(120);
        executor.setThreadNamePrefix("schedule-thread-pool-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        executor.initialize();
        return executor;
    }
}
2.차단기 설정

package com.example.demo.common.interceptor;

import com.example.demo.common.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

/**
 *      
 *
 * @author wangbo
 * @date 2021/5/13
 */
@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.info("   LogInterceptor");
        //  MDC 
        MDC.put(Constants.LOG_MDC_ID, UUID.randomUUID().toString().replace("-", ""));
        //        
        String method = request.getMethod();
        String uri = request.getRequestURI();
        log.info("[    ] : {} : {}", method, uri);
        //      
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //log.info("   LogInterceptor");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //log.info("   LogInterceptor");
        //      
        //  MDC 
        MDC.remove(Constants.LOG_MDC_ID);
    }
}
차단기 등록:

package com.example.demo.common.config;

import com.example.demo.common.interceptor.LogInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * MVC  
 *
 * @author wangbo
 * @date 2021/5/13
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private LogInterceptor logInterceptor;
    
    /**
     *      
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(logInterceptor);
    }
}
3.로그 파일 설정logback-spring.xml파일 의 로그 인쇄 형식 에 추가 해 야 합 니 다%X{trace_id}.다음 과 같 습 니 다.

<!--              -->
<appender name="console_out" class="ch.qos.logback.core.ConsoleAppender">
     <!--      -->
     <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{trace_id}] [%level] [%thread] [%class:%line] - %m%n</pattern>
         <charset>UTF-8</charset>
     </encoder>
 </appender>
4.사용 방법 예시
4.1 비동기 사용
여기 서 비동기 방법의 호출 은 현재 클래스 의 방법 을 직접 호출 할 수 없습니다.즉,호출 방법 과 비동기 방법 은 같은 클래스 에 있 을 수 없습니다.그렇지 않 으 면 동기 화 실행 으로 변 할 수 있 습 니 다.

 /**
     *     
     */
    //@Async//    ,         ,         ,       SimpleAsyncTaskExecutor
    @Async(value = "commonThreadPool")//        
    @Override
    public void async() {
        log.info("       ");
    }
4.2 정시 임무

package com.example.demo.generator.crontab;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 *     
 *
 * @author wangbo
 * @date 2021/5/14
 */
@Slf4j
@Component
public class TestTimeTask {
    //    @Scheduled      ,       ,                     。
    //       taskScheduler,  ID scheduling-x
    //  @Async       ,            (       )。

    /**
     *             2S
     *       ,       4S。         2S  ,               ,            
     *      ,     ,     2S
     */
    //@Async(value = "scheduleThreadPool")
    //@Scheduled(fixedRate = 2000)
    public void fixedRate() {
        log.info("       fixedRate = {}", LocalDateTime.now());
        try {
            Thread.sleep(4_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     *                        2S
     *          ,        ,       6S。
     *      ,         
     */
    //@Scheduled(fixedDelay = 2_000)
    public void fixedDelay() {
        log.info("         fixedDelay = {}", LocalDateTime.now());
        try {
            Thread.sleep(4_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     *     10S   fixedDelay      ,      fixedDelay      
     *                 
     * {@link # fixeddrate} or {@link #fixedDelay}
     */
    //@Scheduled(initialDelay = 10_000, fixedDelay = 1_000)
    public void initialDelay() {
        log.info("           initialDelay = {}", LocalDateTime.now());
    }

    /**
     *                           ,            
     */
    //@Async(value = "scheduleThreadPool")
    //@Scheduled(cron = "0/2 * * * * *")
    public void testCron() {
        log.info("          testCron = {}", LocalDateTime.now());
        try {
            Thread.sleep(4_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
SpringBoot 프로젝트 에 MDC 로그 링크 추적 을 추가 하 는 글 을 소개 합 니 다.더 많은 SpringBoot MDC 로그 링크 추적 내용 은 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기