关于全链路追踪traceId遇到线程池的问题,做过架构的估计都遇到过,现在以写个demo,总体思想就是获取父线程traceId,给子线程,子线程用完移除掉。
mac上的chrome时不时崩溃,写了一大半的博客没了,直接贴源码和注释吧
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ThreadPoolTracing { private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTracing.class); public static ThreadLocal<String> threadLocalTraceId = new ThreadLocal<>(); static class Task implements Runnable { @Override public void run() { String traceId=threadLocalTraceId.get(); logger.info("traceId={}",traceId); } } }
public class MyTest2 { private static final Logger loger = LoggerFactory.getLogger(MyTest2.class); //线程池大小设置为一,保证是同一个线程run之前获取traceId,run后删除,便于测试 private static ExecutorService executorService = Executors.newFixedThreadPool(1); @Test public void test1() { String traceId = UUID.randomUUID().toString().replace("-", ""); ThreadPoolTracing.threadLocalTraceId.set(traceId); loger.info("父线程={};traceId={}",Thread.currentThread().getName(),traceId); Runnable runnable=new Runnable() { @Override public void run() { //ThreadLocal 拿不到值;如果是InheritableThreadLocal,可以拿到值 String id0 = ThreadPoolTracing.threadLocalTraceId.get(); loger.info("子线程={},traceId={}",Thread.currentThread().getName(),id0); } }; executorService.execute(runnable);//结果为空 executorService.execute(new ThreadPoolTracing.Task());//结果为空 Runnable wrap= wrap( runnable); executorService.execute(wrap);//可以获取traceId try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } traceId = UUID.randomUUID().toString().replace("-", ""); //traceId 重新复制 ThreadPoolTracing.threadLocalTraceId.set(traceId); loger.info("父线程={};traceId={}",Thread.currentThread().getName(),traceId); //线程池中的traceId跟着变更 wrap= wrap( runnable); executorService.execute(wrap); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public Runnable wrap(Runnable task) { //获取父线程中的Trace String id0 = ThreadPoolTracing.threadLocalTraceId.get(); class CurrentTraceContextRunnable implements Runnable { @Override public void run() { //traceId 给子线程 ThreadPoolTracing.threadLocalTraceId.set(id0); task.run(); //子线程用完删除 ThreadPoolTracing.threadLocalTraceId.remove(); } } return new CurrentTraceContextRunnable(); } }