欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot項(xiàng)目注入?traceId?追蹤整個請求的日志鏈路(過程詳解)

 更新時間:2025年02月27日 17:20:15   作者:灰色人生qwer  
本文介紹了如何在單體SpringBoot項(xiàng)目中通過手動實(shí)現(xiàn)過濾器或攔截器來注入traceId,以追蹤整個請求的日志鏈路,通過使用MDC和配置日志格式,可以在日志中包含traceId,便于問題排查,同時,還在返回的包裝類中注入traceId,以便用戶反饋問題,感興趣的朋友一起看看吧

SpringBoot項(xiàng)目注入 traceId 來追蹤整個請求的日志鏈路,有了 traceId, 我們在排查問題的時候,可以迅速根據(jù) traceId 查找到相關(guān)請求的日志,特別是在生產(chǎn)環(huán)境的時候,用戶可能只提供一個錯誤截圖,我們作為開發(fā)人員想要更詳細(xì)的日志,這時候我們就可以直接根據(jù)用戶提供的 traceId 來查找用戶這次請求的整個日志,會方便很多。

springboot 單體項(xiàng)目沒辦法做到有 traceId 一樣的效果嗎?

即使是在單體應(yīng)用中,為請求添加一個唯一的traceId以追蹤整個請求鏈路的日志也是完全可行的。雖然Spring Cloud Sleuth等工具主要用于分布式系統(tǒng)中的鏈路追蹤,但在單體Spring Boot應(yīng)用中你仍然可以通過一些方法來實(shí)現(xiàn)類似的功能。下面是一個基本的方法來手動實(shí)現(xiàn)這樣的功能:

手動實(shí)現(xiàn) traceId 注入

1. 創(chuàng)建一個過濾器或攔截器:你可以創(chuàng)建一個Servlet過濾器或者Spring的攔截器,用于在每個請求到達(dá)時生成一個唯一的traceId(如果不存在的話),并將其存儲到當(dāng)前線程的上下文中。

2. 使用MDC(Mapped Diagnostic Context):SLF4J提供了MDC工具,可以用來保存日志的上下文信息。你可以在過濾器或攔截器中將traceId放入MDC中,這樣所有的日志記錄器都可以自動包含這個ID。 示例代碼:

TraceIdFilter :

# 我這里用的是 jdk17, 所以 servlet 工具類被移動到了 jakarta 包下,如果你用的是比較老的 jdk, 可以刪除后重新導(dǎo)入 servlet 的類。
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.UUID;
@Compone
nt
public class TraceIdFilter extends OncePerRequestFilter {
    private static final String TRACE_ID = "traceId";
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String traceId = request.getHeader(TRACE_ID);
        if (traceId == null) {
            traceId = UUID.randomUUID().toString();
        }
        MDC.put(TRACE_ID, traceId);
        try {
            filterChain.doFilter(request, response);
        } finally {
            MDC.remove(TRACE_ID);
        }
    }
}

3. 配置日志格式:確保你的日志配置文件(如logback.xml、log4j2.xml等)中包含了輸出traceId的配置。例如,在logback中,你可以這樣做:

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} - [%thread] %-5level %logger{36} - [%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

我的項(xiàng)目使用的是 logback-spring.xml ,我的文件完整內(nèi)容如下:
logback-spring.xml:

<configuration debug="true">
    <!-- 引用Spring Boot全局配置文件中的日期格式配置項(xiàng) -->
    <springProperty scope="context" name="dateformat" source="logging.pattern.dateformat" defaultValue="yyyy-MM-dd HH:mm:ss.SSS"/>
    <springProperty scope="context" name="APP_NAME"  source="spring.application.name"/>
    <springProperty scope="context" name="LOG_FILE"  source="logging.file.path"/>
    <!-- 定義顏色編碼 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <!-- 定義日志輸出到控制臺的appender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%clr(%d{${dateformat}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%15.15t]){faint} [%-40.40logger{39}] [%X{traceId}] %clr(%msg%n){faint}%wEx</pattern>
        </encoder>
    </appender>
    <!-- 開發(fā)環(huán)境配置 -->
    <springProfile name="local | test">
        <root level="DEBUG">
            <appender-ref ref="STDOUT" />
        </root>
        <!-- 開發(fā)環(huán)境專屬的詳細(xì)日志 -->
        <logger name="com.tylerzhong" level="TRACE" additivity="false">
            <appender-ref ref="STDOUT" />
        </logger>
    </springProfile>
    <springProfile name="dev | prod">
        <!-- 文件日志:輸出全部日志到文件 -->
        <appender name="FILE_INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_FILE}/${APP_NAME}.log</file>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>ACCEPT</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_FILE}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <maxHistory>180</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>50MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{${dateformat}} [%thread] %-5level %logger{36} [%X{traceId}] - %msg%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!-- 錯誤日志:用于將錯誤日志輸出到獨(dú)立文件 -->
        <appender name="FILE_ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_FILE}/error-${APP_NAME}.log</file>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_FILE}/error-${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <maxHistory>180</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>50MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{${dateformat}} [%thread] %-5level %logger{36} [%X{traceId}] - %msg%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <root level="INFO">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE_INFO_LOG" />
            <appender-ref ref="FILE_ERROR_LOG" />
        </root>
    </springProfile>
</configuration>

關(guān)于更具體的日志輸出配置,可以參考我的這篇文章《SpringBoot配置log4j輸出日志的案例講解》。

通過這種方式,你就可以在單體Spring Boot項(xiàng)目中為每個請求生成一個唯一的traceId,并通過日志輸出它,從而實(shí)現(xiàn)在處理請求期間的所有日志條目都能關(guān)聯(lián)起來的效果。這種方法不僅適用于單體應(yīng)用,也可以作為理解更復(fù)雜的分布式追蹤概念的基礎(chǔ)。

這樣配置之后,你在代碼中打印日志的時候就會攜帶上 traceId 了。

 log.info("請求參數(shù): {}", arg);

輸出示例:

2025-02-26 19:25:02.187  INFO [nio-8070-exec-2] [com.tylerzhong.web.config.LoggingAspect       ] [ab85097a-6d31-44c3-bcfb-2bcc97b87ab9] 方法: TransferController.xxx(..)

當(dāng)然,我們不止要將 traceId 輸出到控制臺,還需要將 traceId 返回給前端用戶,這樣用戶找我們排查問題的時候,只需要給一個 traceId 給我們即可。

所以在返回的包裝類中注入 traceId 返回給前端。
我的代碼如下:

import lombok.Getter;
import lombok.NoArgsConstructor;
import org.slf4j.MDC;
@Getter
@NoArgsConstructor
public class Result<T> {
    private int code;
    private boolean flag;
    private String desc;
    private String cause;
    private String traceId;
    private T data;
    public Result(int code, boolean flag, String desc) {
        this.code = code;
        this.flag = flag;
        this.desc = desc;
    }
    public Result(int code, boolean flag, String desc, String traceId) {
        this.code = code;
        this.flag = flag;
        this.desc = desc;
        this.traceId = traceId;
    }
    public Result(int code, boolean flag, String desc, String cause, String traceId) {
        this.code = code;
        this.flag = flag;
        this.desc = desc;
        this.cause = cause;
        this.traceId = traceId;
    }
    public Result(int code, boolean flag, String desc, T data, String traceId) {
        this.code = code;
        this.flag = flag;
        this.desc = desc;
        this.data = data;
        this.traceId = traceId;
    }
    public static <T> Result<T> success() {
        return new Result<>(0, true, "成功", MDC.get("traceId"));
    }
    public static <T> Result<T> success(T data) {
        return new Result<>(0, true,"成功", data, MDC.get("traceId"));
    }
    public static <T> Result<T> fail(int code, String desc, String cause) {
        return new Result<>(code, false, desc, cause, MDC.get("traceId"));
    }
}

返回給前端的失敗示例:

{
    "code": 405,
    "flag": false,
    "desc": "請求方式不支持.",
    "cause": "Request method 'POST' is not supported",
    "traceId": "ebd77e99-361c-47b3-8569-2d321d011418",
    "data": null
}

返回給前端的成功示例:

{
    "code": 0,
    "flag": true,
    "desc": "成功",
    "cause": null,
    "traceId": "07a3b99c-8cf8-45dc-a758-6c7636472cab",
    "data": {
        "count": 100,
        "name": "張三"
    }
}

到此這篇關(guān)于SpringBoot項(xiàng)目注入 traceId 來追蹤整個請求的日志鏈路的文章就介紹到這了,更多相關(guān)SpringBoot traceId 日志鏈路內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java集合Iterator迭代的實(shí)現(xiàn)方法

    Java集合Iterator迭代的實(shí)現(xiàn)方法

    這篇文章主要介紹了Java集合Iterator迭代接口的實(shí)現(xiàn)方法,非常不錯,具有參考借鑒家,對Java 結(jié)合iterator知識感興趣的朋友一起看看吧
    2016-08-08
  • springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄(思路詳解)

    springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄(思路詳解)

    這篇文章主要介紹了springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • springboot整合cxf發(fā)布webservice以及調(diào)用的方法

    springboot整合cxf發(fā)布webservice以及調(diào)用的方法

    這篇文章主要介紹了springboot整合cxf發(fā)布webservice以及調(diào)用的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • 一篇文章帶你深入了解Java基礎(chǔ)(3)

    一篇文章帶你深入了解Java基礎(chǔ)(3)

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • Java并發(fā)教程之volatile關(guān)鍵字詳解

    Java并發(fā)教程之volatile關(guān)鍵字詳解

    這篇文章主要給大家介紹了關(guān)于Java并發(fā)教程之volatile關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Leetcode常見鏈表問題及代碼示例

    Leetcode常見鏈表問題及代碼示例

    這篇文章主要介紹了Leetcode常見鏈表問題及代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • 通過Java實(shí)現(xiàn)中文分詞與文本關(guān)鍵詞提取

    通過Java實(shí)現(xiàn)中文分詞與文本關(guān)鍵詞提取

    這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)中文分詞以及文本關(guān)鍵詞提取功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)
    2023-06-06
  • mybatis中映射文件include標(biāo)簽的應(yīng)用

    mybatis中映射文件include標(biāo)簽的應(yīng)用

    這篇文章主要介紹了mybatis中映射文件include標(biāo)簽的應(yīng)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringBoot集成MyBatis的分頁插件PageHelper實(shí)例代碼

    SpringBoot集成MyBatis的分頁插件PageHelper實(shí)例代碼

    這篇文章主要介紹了SpringBoot集成MyBatis的分頁插件PageHelper的相關(guān)操作,需要的朋友可以參考下
    2017-08-08
  • java正則表達(dá)式校驗(yàn)日期格式實(shí)例代碼

    java正則表達(dá)式校驗(yàn)日期格式實(shí)例代碼

    如果使用得當(dāng),正則表達(dá)式是匹配各種模式的強(qiáng)大工具,下面這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式校驗(yàn)日期格式的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05

最新評論