Spring項(xiàng)目如何實(shí)現(xiàn)帶請求鏈路id的日志記錄
我們在做java項(xiàng)目的時(shí)候通常需要通過請求日志來排查定位線上問題,在日志比較多而我們又需要查找整個(gè)請求的全部日志的時(shí)候會(huì)比較困難。所以,就需要在日志記錄的時(shí)候講同一個(gè)請求的關(guān)鍵日志用同一個(gè)唯一標(biāo)識(shí)串聯(lián)起來。這樣查找的時(shí)候就會(huì)比較好查找。下面來用java aop實(shí)現(xiàn)請求id的日志記錄。(該支持子線程繼承主線程請求id)
一:首先我們需要一個(gè)日志請求鏈路id切面類
注意:如果不考慮多線程則(第二步和第三步可以不要)
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: 日志請求鏈路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";
/** 用戶 */
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());
//以下代碼為記錄用戶信息,方便更直觀的識(shí)別日志操作人信息。若不需要可以將下面部分刪除
String nickname = TokenUtil.getNicknameByToken();
if (null == nickname){
nickname = "游客訪問";
}
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工具類
* @datetime 2024年 04月 23日 11:49
* @version: 1.0
*/
public class UUIDUtil {
/**
* 獲取UUID
*
* @return
*/
public static String getUUID() {
//生產(chǎn)uuid并去掉uuid的短橫線
return UUID.randomUUID().toString().replace("-", "");
}
}二:創(chuàng)建一個(gè)處理多線程鏈路追蹤的工具類
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: 多線程鏈路追蹤工具類
* @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());
}
}
/**
* 用于父線程向線程池中提交任務(wù)時(shí),將自身MDC中的數(shù)據(jù)復(fù)制給子線程
*
* @param runnable 要執(zhí)行的線程
* @param context 父線程的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();
}
};
}
}三:在往線程池放任務(wù)的時(shí)候做請求鏈路id傳遞
/**
* 線程池添加 [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里邊鏈路請求id的key,user-%X{USER}是用戶信息的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)帶請求鏈路id的日志記錄就完成了
到此這篇關(guān)于Spring項(xiàng)目如何實(shí)現(xiàn)帶請求鏈路id的日志記錄的文章就介紹到這了,更多相關(guān)Spring請求id日志記錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot創(chuàng)建JSP登錄頁面功能實(shí)例代碼
這篇文章主要介紹了SpringBoot創(chuàng)建JSP登錄頁面功能實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-04-04
SpringBoot項(xiàng)目發(fā)送釘釘消息功能實(shí)現(xiàn)
在工作中的一些告警需要發(fā)送釘釘通知,有的是發(fā)給個(gè)人,有的要發(fā)到群里,這時(shí)項(xiàng)目就需要接入釘釘,實(shí)現(xiàn)發(fā)消息的功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-02-02
Java將不同的List集合復(fù)制到另一個(gè)集合常見的方法
在Java中,有時(shí)候我們需要將一個(gè)List對象的屬性值復(fù)制到另一個(gè)List對象中,使得兩個(gè)對象的屬性值相同,這篇文章主要介紹了Java將不同的List集合復(fù)制到另一個(gè)集合常見的方法,需要的朋友可以參考下2024-09-09
java中對象和Map互相轉(zhuǎn)換的幾種常見方式舉例
Map在日常開發(fā)應(yīng)用中的頻率很高,最常用的實(shí)現(xiàn)類是HashMap和有序的TreeMap,下面這篇文章主要給大家介紹了關(guān)于java中對象和Map互相轉(zhuǎn)換的幾種常見方式舉例,需要的朋友可以參考下2024-01-01

