Spring項(xiàng)目如何實(shí)現(xiàn)帶請(qǐng)求鏈路id的日志記錄
我們?cè)谧鰆ava項(xiàng)目的時(shí)候通常需要通過(guò)請(qǐng)求日志來(lái)排查定位線(xiàn)上問(wèn)題,在日志比較多而我們又需要查找整個(gè)請(qǐng)求的全部日志的時(shí)候會(huì)比較困難。所以,就需要在日志記錄的時(shí)候講同一個(gè)請(qǐng)求的關(guān)鍵日志用同一個(gè)唯一標(biāo)識(shí)串聯(lián)起來(lái)。這樣查找的時(shí)候就會(huì)比較好查找。下面來(lái)用java aop實(shí)現(xiàn)請(qǐng)求id的日志記錄。(該支持子線(xiàn)程繼承主線(xiàn)程請(qǐng)求id)
一:首先我們需要一個(gè)日志請(qǐng)求鏈路id切面類(lèi)
注意:如果不考慮多線(xiàn)程則(第二步和第三步可以不要)
package com.iMagine.iMagine_pro.aop; import com.iMagine.iMagine_common.utils.UUIDUtil; import com.iMagine.iMagine_pro.utils.TokenUtil; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.MDC; import org.springframework.stereotype.Component; /** * @author 名一 * @ClassName TraceIdAspect * @description: 日志請(qǐng)求鏈路id切面處理 * @datetime 2024年 12月 16日 14:28 * @version: 1.0 */ @Slf4j @Aspect @Component public class TraceIdAspect { /** 鏈路追蹤id */ public final static String TRACE_ID = "TRACE_ID"; /** 用戶(hù) */ public final static String USER = "USER"; /** * 鏈路id切點(diǎn)定義 */ @Pointcut("execution(* com.iMagine.iMagine_pro.controller.*.*(..))") public void TraceIdCut() { } /** * 鏈路id添加 */ @Before("TraceIdCut()") public void cutProcessBefore() { MDC.put(TRACE_ID, UUIDUtil.getUUID()); //以下代碼為記錄用戶(hù)信息,方便更直觀(guān)的識(shí)別日志操作人信息。若不需要可以將下面部分刪除 String nickname = TokenUtil.getNicknameByToken(); if (null == nickname){ nickname = "游客訪(fǎng)問(wèn)"; } MDC.put(USER, nickname); } /** * 鏈路id清除 */ @After("TraceIdCut()") public void cutProcessAfter() { MDC.clear(); } }
package com.iMagine.iMagine_common.utils; import java.util.UUID; /** * @author 名一 * @ClassName UUIDUtil * @description: UUID工具類(lèi) * @datetime 2024年 04月 23日 11:49 * @version: 1.0 */ public class UUIDUtil { /** * 獲取UUID * * @return */ public static String getUUID() { //生產(chǎn)uuid并去掉uuid的短橫線(xiàn) return UUID.randomUUID().toString().replace("-", ""); } }
二:創(chuàng)建一個(gè)處理多線(xiàn)程鏈路追蹤的工具類(lèi)
package com.iMagine.iMagine_common.utils; import com.iMagine.iMagine_common.constant.SysConstant; import org.slf4j.MDC; import java.util.Map; /** * @author 名一 * @ClassName ThreadMdcUtil * @description: 多線(xiàn)程鏈路追蹤工具類(lèi) * @datetime 2024年 12月 16日 14:57 * @version: 1.0 */ public class ThreadMdcUtil { // 獲取唯一性標(biāo)識(shí) public static String generateTraceId() { return UUIDUtil.getUUID(); } public static void setTraceIdIfAbsent() { if (MDC.get(SysConstant.TRACE_ID) == null) { MDC.put(SysConstant.TRACE_ID, generateTraceId()); } } /** * 用于父線(xiàn)程向線(xiàn)程池中提交任務(wù)時(shí),將自身MDC中的數(shù)據(jù)復(fù)制給子線(xiàn)程 * * @param runnable 要執(zhí)行的線(xiàn)程 * @param context 父線(xiàn)程的mdc * @return 鏈路id傳遞后的任務(wù) */ 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(); } }; } }
三:在往線(xiàn)程池放任務(wù)的時(shí)候做請(qǐng)求鏈路id傳遞
/** * 線(xiàn)程池添加 [ai server 相關(guān)操作(psot)]任務(wù) * * @param task 添加的任務(wù) */ public static void addSendPostThreadToThreadPool(SendPostThread task) { log.info("addSendPostThreadToThreadPool pool:{}, task:{}", pool, task); try { pool.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap())); } catch (Exception e) { log.error("addSendPostThreadToThreadPool error pool:{}, task:{}, e:", pool, task, e); } }
四:在日志配置里將鏈路追蹤id加入日志輸出格式的配置里
<!-- 日志輸出格式 (其中%X{TRACE_ID}是mdc里邊鏈路請(qǐng)求id的key,user-%X{USER}是用戶(hù)信息的key)--> <property name="ENCODER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{TRACE_ID} user-%X{USER} %-5level %logger{32}-[%line] - %msg%n"/>
到此spring 項(xiàng)目實(shí)現(xiàn)帶請(qǐng)求鏈路id的日志記錄就完成了
到此這篇關(guān)于Spring項(xiàng)目如何實(shí)現(xiàn)帶請(qǐng)求鏈路id的日志記錄的文章就介紹到這了,更多相關(guān)Spring請(qǐng)求id日志記錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Swagger注解-@ApiModel和@ApiModelProperty的用法
這篇文章主要介紹了Swagger注解-@ApiModel和@ApiModelProperty的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06java?讀寫(xiě)鎖的使用及它的優(yōu)點(diǎn)
這篇文章主要介紹了java?讀寫(xiě)鎖的使用及它的優(yōu)點(diǎn),讀寫(xiě)鎖的特點(diǎn)就是是讀讀不互斥、讀寫(xiě)互斥、寫(xiě)寫(xiě)互斥,下面具體使用分享需要的小伙伴可以參考一下2022-05-05詳解 Java Maximum redirects (100) exceeded
這篇文章主要介紹了詳解 Java Maximum redirects (100) exceeded的相關(guān)資料,需要的朋友可以參考下2017-05-05從HelloWorld和文檔注釋開(kāi)始入門(mén)Java編程
這篇文章主要介紹了從HelloWorld和文檔注釋開(kāi)始入門(mén)Java編程,涉及到Javadoc工具的使用,需要的朋友可以參考下2015-10-10Java模板動(dòng)態(tài)生成word文件的方法步驟
最近項(xiàng)目中需要根據(jù)模板生成word文檔,模板文件也是word文檔。本文使用使用freemarker模板生成word文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07使用?EasyCode生成springboot+mybatis基礎(chǔ)程序的實(shí)現(xiàn)示例
本文主要介紹了使用?EasyCode生成springboot+mybatis基礎(chǔ)程序的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01RocketMQ實(shí)現(xiàn)隨緣分BUG小功能示例詳解
這篇文章主要為大家介紹了RocketMQ實(shí)現(xiàn)隨緣分BUG小功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08