跨线程(线程池)日志链路追踪
不跨线程的业务日志链路我们可以通过日志框架如Logback 使用MDC对象放入一个traceId,再在日志配置文件配置即可 但如跨线程的话traceid无法传递(MDC 底层使用的 TreadLocal)
对于线上业务存在大量的跨线程业务操作,实际线上日志输出海量且相当复杂,故研究跨线程的日志链路追踪,形成业务日志链路记录,方便高效的排查线上问题
在此有一种方案为重写线程池,将线程池重新封装,在线程执行将前一个线程的日志traceId传递给将要执行的线程日志MDC
对于直接new创建线程的情况不考略【实际应用中应该避免这种用法】
在此基础上我们可以通过复写线程池ThreadPoolExecutor 来实现traceid的传递
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
public class ThreadMdcUtil {
public static void setTraceIdIfAbsent() {
if (MDC.get(MDCGenerator.REQUEST_ID_HEADER_NAME) == null) {
MDC.put(MDCGenerator.REQUEST_ID_HEADER_NAME, UUID.randomUUID().toString());
}
}
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();
}
};
}
}
jdk线程池
/** * @author lyh */ public class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor { public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } @Override public void execute(Runnable task) { super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap())); } @Override public <T> Future<T> submit(Runnable task, T result) { return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), result); } @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())); } }
spring ThreadPoolExecutor
public class ThreadPoolTaskExecutorMdcWrapper 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())); } }

浙公网安备 33010602011771号