MDC实现线程池tranceId全链路传递

Posted 百里东君~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MDC实现线程池tranceId全链路传递相关的知识,希望对你有一定的参考价值。

1、首先定义一个自定义线程池类继承ThreadPoolTaskExecutor

public class ThreadPoolExecutorMdcWrapper extends ThreadPoolTaskExecutor 

    @Override
    public void execute(Runnable task) 
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    


    @Override
    public <T> Future<T> submit(Callable<T> task) 
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    

    @Override
    public Future<?> submit(Runnable task) 
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    


2、编写tranceid包装工具类
判断当前线程对应MDC的上下文是否存在,存在则是子线程,设置MDC中的traceId值,不存在则生成新的tranceid,再执行run方法,执行结束之后清除线程tranceId

public class ThreadMdcUtil 
    public static void setTraceIdIfAbsent() 
        if (MDC.get(LtLogFormat.MDC_TRACEID) == null) 
            MDC.put(LtLogFormat.MDC_TRACEID, UUID.randomUUID().toString().replaceAll("-",""));
        
    

    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) 
        return () -> 
            if (context == null) 
                MDC.clear();
             else 
                MDC.setContextMap(context);
            
            setTraceIdIfAbsent();
            try 
                return callable.call();
             finally 
                MDC.clear();
            
        ;
    

    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) 
        return () -> 
            if (context == null) 
                MDC.clear();
             else 
                MDC.setContextMap(context);
            
            setTraceIdIfAbsent();
            try 
                runnable.run();
             finally 
                MDC.clear();
            
        ;
    


3、初始化自定义线程池

@Configuration
@Component
public class TaskThreadPoolConfig 

	@Bean(name = "optimizeTaskExecutor", destroyMethod = "shutdown")
	public Executor optimizeTaskExecutor() 
		ThreadPoolExecutorMdcWrapper executor = new ThreadPoolExecutorMdcWrapper();
		executor.setCorePoolSize(50);
		executor.setMaxPoolSize(500);
		executor.setQueueCapacity(500);
		executor.setKeepAliveSeconds(60);
		executor.setAllowCoreThreadTimeOut(true);
		executor.setThreadNamePrefix("Feh_Optimize_");
		// 设置等待所有任务执行结束再关闭线程池
		executor.setWaitForTasksToCompleteOnShutdown(true);
		// 该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,
		// 以确保应用最后能够被关闭,而不是阻塞住
		executor.setAwaitTerminationSeconds(60);
		// rejection-policy:当pool已经达到max size的时候,如何处理新任务
		// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	

4、接下来进入实战环节
编写一个测试类

    @Autowired
    private Executor optimizeTaskExecutor;

    @GetMapping("/testMdcTranceId")
    public Response testMdcTranceId() 
        //    public static final String MDC_TRACEID = "X-B3-TraceId";
        log.info("标记0,tranceId = ", MDC.get(LtLogFormat.MDC_TRACEID));
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> 
            test01();
        , optimizeTaskExecutor);
        log.info("标记2,tranceId = ", MDC.get(LtLogFormat.MDC_TRACEID));
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> 
            test02();
        , optimizeTaskExecutor);
        CompletableFuture.allOf(future1,future2).join();
        log.info("标记4,tranceId = ", MDC.get(LtLogFormat.MDC_TRACEID));
        return Response.buildSuccessResponse();
    

    private void test01()
        log.info("标记1,tranceId = ", MDC.get(LtLogFormat.MDC_TRACEID));
    
    private void test02()
        log.info("标记3,tranceId = ", MDC.get(LtLogFormat.MDC_TRACEID));
    

打印结果tranceid均一致,快动手试试吧

以上是关于MDC实现线程池tranceId全链路传递的主要内容,如果未能解决你的问题,请参考以下文章

MDC实现线程池tranceId全链路传递

Logback+Spring-Aop实现全面生态化的全链路日志追踪系统服务插件「Logback-MDC篇」

Spring Boot + MDC 实现全链路调用日志跟踪,这才叫优雅。。

LOG4J2-MDC-全链路跟踪等功能研究

LOG4J2-MDC-全链路跟踪等功能研究

SpringBoot+MDC实现全链路调用日志跟踪,这才叫优雅!