SpringBoot+slf4j線程池全鏈路調(diào)用日志跟蹤問題及解決思路(二)
本項目源碼已在多個項目中實踐
接著上一篇文章,項目中使用了線程池,那么子線程中日志就會丟失traceId,下面講解如何實現(xiàn)子線程中的traceId日志跟蹤。
解決思路
子線程在打印日志的過程中traceId將丟失,解決方式為重寫線程池,將主線程的traceId繼續(xù)傳遞到子線程中。當然,對于直接new創(chuàng)建線程的情況不考略【實際應(yīng)用中應(yīng)該避免這種用法】。
繼承ThreadPoolExecutor,重寫執(zhí)行任務(wù)的方法
public final class OverrideThreadPoolExecutor extends ThreadPoolExecutor { @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())); } }
封裝ThreadMdcUtil工具類
以封裝Callable為例:
- 判斷當前線程對應(yīng)MDC的Map是否存在,如果存在則設(shè)置子線程的ContextMap為當前線程的;
- 如果不存在,則重新生成traceId;
- 執(zhí)行run方法
public final class ThreadMdcUtil { public static void setTraceIdIfAbsent() { if (MDC.get(TraceConstant.MDC_TRACE) == null || MDC.get(TraceConstant.MDC_TRACE).length() == 0) { String tid = UUID.randomUUID().toString().replace("-", ""); MDC.put(TraceConstant.MDC_TRACE, tid); } } 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(); } }; } }
測試子線程中traceId的傳遞,本項目中ExecutorService已經(jīng)重寫了線程池
@RestController @RequestMapping("trace") @Slf4j @AllArgsConstructor public class TestTraceController { private final ExecutorService executorService; @GetMapping("traceLog") public String traceLog() { log.info("---接口調(diào)用了---"); traceService(); asyncTrace(); return "success"; } private void traceService(){ log.error("## 執(zhí)行traceService方法"); } private void asyncTrace(){ CompletableFuture.runAsync(()->{ log.info("執(zhí)行線程池中的方法asyncTrace,未重寫了線程池"); }, executorService); } }
未重寫ThreadPoolExecutor效果如下:
重寫ThreadPoolExecutor效果如下:
到此這篇關(guān)于SpringBoot+slf4j線程池全鏈路調(diào)用日志跟蹤的文章就介紹到這了,更多相關(guān)SpringBoot全鏈路調(diào)用日志跟蹤內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
對數(shù)據(jù)進行分頁顯示到table中的實現(xiàn)方法
這篇文章主要介紹了對數(shù)據(jù)進行分頁顯示到table中的實現(xiàn)方法的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-05-05Java使用抽象工廠模式實現(xiàn)的肯德基消費案例詳解
這篇文章主要介紹了Java使用抽象工廠模式實現(xiàn)的肯德基消費案例,較為詳細的分析了抽象工廠模式的定義、原理并結(jié)合實例形式分析了Java使用抽象工廠模式實現(xiàn)肯德基消費案例的步驟與相關(guān)操作技巧,需要的朋友可以參考下2018-05-05基于RecyclerChart的KLine繪制Volume實現(xiàn)詳解
這篇文章主要為大家介紹了基于RecyclerChart的KLine繪制Volume實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03MyBatis-Plus+達夢數(shù)據(jù)庫實現(xiàn)高效數(shù)據(jù)持久化的示例
這篇文章主要介紹了MyBatis-Plus和達夢數(shù)據(jù)庫實現(xiàn)高效數(shù)據(jù)持久化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-08-08詳解jdbc實現(xiàn)對CLOB和BLOB數(shù)據(jù)類型的操作
這篇文章主要介紹了詳解jdbc實現(xiàn)對CLOB和BLOB數(shù)據(jù)類型的操作的相關(guān)資料,這里實現(xiàn)寫入操作與讀寫操作,需要的朋友可以參考下2017-08-08