SpringBoot集成TraceId的方案詳解(追蹤ID)
更新時間:2025年12月03日 10:03:53 作者:Slow菜鳥
文章介紹了兩種在Java應用中實現(xiàn)TraceId(請求鏈路唯一標識)的方法,兩種方案都通過合理配置和代碼實現(xiàn),確保了TraceId在不同服務和異步線程中的傳遞,從而實現(xiàn)統(tǒng)一的日志跟蹤和問題排查,感興趣的朋友跟隨小編一起看看吧
一、TraceId 是什么?
- TraceId 就是給每一條請求鏈路分配的全局唯一 “身份證號” —— 不管是單體項目里的一次接口請求,還是分布式微服務里跨多個服務的調用流程,只要屬于同一條請求鏈路,全程共用同一個 TraceId。
- 你可以把它理解成:用戶在 APP 點了 “下單” 按鈕,這個請求從前端→網關→訂單服務→用戶服務→支付服務,整個流程會被分配一個唯一的 TraceId,所有環(huán)節(jié)的日志、調用記錄都帶上這個 ID。排查問題時,只要搜這個 TraceId,就能把整條鏈路的日志 / 調用記錄都揪出來,不用在海量日志里大海撈針。
場景一:無SkyWalking的最優(yōu)實現(xiàn)
核心方案
MDC(日志上下文) + Filter(入口生成/讀取TraceId) + TaskDecorator(異步線程傳遞) + Feign/RestTemplate攔截器(微服務跨服務傳遞)
適用場景
- 中小型單體/微服務項目;
- 無可視化鏈路分析需求,僅需日志攜帶TraceId定位問題;
- 不愿引入額外中間件(SkyWalking OAP)增加運維成本。
1. 依賴配置(拆分SpringBoot/SpringCloud)
1.1 SpringBoot單體項目依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version> <!-- 3.x可替換為3.2.0 -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>boot-traceid-no-skywalking</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- SpringBoot Web核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 工具類:判空/字符串處理 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<!-- 可選:Hutool(雪花ID生成) -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<!-- 測試依賴(非核心) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.15</version>
</plugin>
</plugins>
</build>
</project>1.2 SpringCloud微服務項目依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version> <!-- 對應Cloud 2021.0.x -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>cloud-traceid-no-skywalking</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 基礎依賴(同SpringBoot) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<!-- 微服務核心:OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 測試依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Cloud版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.15</version>
</plugin>
</plugins>
</build>
</project>2. 核心代碼實現(xiàn)(無SkyWalking專屬)
2.1 TraceId工具類(自定義生成/傳遞)
package com.example.traceid.util;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import java.util.UUID;
/**
* 無SkyWalking時:自定義TraceId生成/管理工具類
*/
public class TraceIdUtils {
// MDC中TraceId的Key(日志配置用%X{traceId}讀?。?
public static final String TRACE_ID_MDC_KEY = "traceId";
// HTTP頭傳遞TraceId的Key
public static final String TRACE_ID_HEADER_KEY = "X-Trace-Id";
// 雪花ID生成器(高并發(fā)用,單機/低并發(fā)可只用UUID)
private static final Snowflake SNOWFLAKE = IdUtil.createSnowflake(
NetUtil.ipv4ToLong(NetUtil.getLocalhostStr()) % 32, 1L
);
/**
* 生成TraceId:低并發(fā)用UUID,高并發(fā)用雪花ID
*/
public static String generateTraceId() {
// 方案1:UUID(默認,無需額外依賴)
return UUID.randomUUID().toString().replace("-", "");
// 方案2:雪花ID(高并發(fā)切換)
// return SNOWFLAKE.nextIdStr();
}
/**
* 從MDC獲取TraceId,兜底返回UNKNOWN
*/
public static String getTraceId() {
String traceId = MDC.get(TRACE_ID_MDC_KEY);
return StringUtils.isBlank(traceId) ? "UNKNOWN" : traceId;
}
/**
* 手動設置TraceId到MDC
*/
public static void setTraceIdToMdc(String traceId) {
if (StringUtils.isNotBlank(traceId)) {
MDC.put(TRACE_ID_MDC_KEY, traceId);
}
}
/**
* 清除MDC中的TraceId
*/
public static void clearTraceIdFromMdc() {
MDC.remove(TRACE_ID_MDC_KEY);
}
}2.2 TraceId過濾器(請求入口生成/讀取TraceId)
package com.example.traceid.filter;
import com.example.traceid.util.TraceIdUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 無SkyWalking時:請求入口生成/讀取TraceId,放入MDC
* 優(yōu)先級最高,保證所有邏輯執(zhí)行前已有TraceId
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TraceIdMdcFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 1. 優(yōu)先讀取上游傳遞的TraceId(網關/其他服務)
String traceId = httpRequest.getHeader(TraceIdUtils.TRACE_ID_HEADER_KEY);
// 2. 上游無則生成新的
if (StringUtils.isBlank(traceId)) {
traceId = TraceIdUtils.generateTraceId();
}
// 3. 放入MDC,供日志讀取
MDC.put(TraceIdUtils.TRACE_ID_MDC_KEY, traceId);
// 4. 執(zhí)行后續(xù)邏輯
chain.doFilter(request, response);
} finally {
// 核心:請求結束清除MDC,避免線程池復用導致TraceId錯亂
MDC.clear();
}
}
}2.3 異步線程池配置(解決異步TraceId丟失)
package com.example.traceid.config;
import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 無SkyWalking時:異步線程池配置,傳遞MDC上下文
*/
@Configuration
@EnableAsync
public class AsyncTraceConfig {
// 自定義TaskDecorator:復制父線程MDC到子線程
private static class MdcTraceDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
Map<String, String> parentMdc = MDC.getCopyOfContextMap();
return () -> {
try {
if (parentMdc != null) {
MDC.setContextMap(parentMdc);
}
runnable.run();
} finally {
MDC.clear(); // 子線程執(zhí)行完清除MDC
}
};
}
}
// 全局異步線程池
@Bean("asyncTraceExecutor")
public Executor asyncTraceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int core = Runtime.getRuntime().availableProcessors() * 2;
executor.setCorePoolSize(core);
executor.setMaxPoolSize(core * 2);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("async-trace-");
executor.setTaskDecorator(new MdcTraceDecorator()); // 綁定裝飾器
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);
executor.initialize();
return executor;
}
}2.4 微服務跨服務傳遞(Feign/RestTemplate攔截器)
2.4.1 Feign攔截器(微服務專屬)
package com.example.traceid.interceptor;
import com.example.traceid.util.TraceIdUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
/**
* 無SkyWalking時:Feign調用傳遞TraceId
*/
@Component
public class FeignTraceInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String traceId = TraceIdUtils.getTraceId();
if (!"UNKNOWN".equals(traceId)) {
template.header(TraceIdUtils.TRACE_ID_HEADER_KEY, traceId);
}
}
}2.4.2 RestTemplate攔截器(微服務專屬)
package com.example.traceid.config;
import com.example.traceid.util.TraceIdUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
/**
* 無SkyWalking時:RestTemplate傳遞TraceId
*/
@Configuration
public class RestTemplateTraceConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
String traceId = TraceIdUtils.getTraceId();
if (!"UNKNOWN".equals(traceId)) {
request.getHeaders().add(TraceIdUtils.TRACE_ID_HEADER_KEY, traceId);
}
return execution.execute(request, body);
}));
return restTemplate;
}
}2.5 日志配置(logback-spring.xml)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<contextName>traceid-no-skywalking</contextName>
<!-- 控制臺輸出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<!-- 核心:%X{traceId}讀取MDC中的TraceId -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件輸出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>3. 無SkyWalking的核心驗證
- 同步接口:日志中
[%X{traceId}]顯示自定義生成的TraceId; - 異步任務:子線程日志TraceId與父線程一致;
- 微服務調用:下游服務日志TraceId與上游一致;
- 無任何額外中間件依賴,僅依賴Spring原生能力。
場景二:有SkyWalking的最優(yōu)實現(xiàn)
核心方案
復用SkyWalking TraceId + MDC綁定 + 上下文傳遞(異步/跨服務)
核心差異
- 無需自定義生成TraceId,直接復用SkyWalking的全局TraceId;
- 日志中同時綁定SkyWalking TraceId,實現(xiàn)「日志TraceId=鏈路TraceId」;
- 異步/跨服務場景需傳遞SkyWalking上下文,保證鏈路不中斷。
1. 依賴配置(拆分SpringBoot/SpringCloud)
1.1 SpringBoot單體項目(新增SkyWalking依賴)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>boot-traceid-with-skywalking</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 基礎依賴(同無SkyWalking) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<!-- SkyWalking核心依賴 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-spring-boot-starter</artifactId>
<version>8.16.0</version> <!-- 與SkyWalking OAP版本一致 -->
</dependency>
<!-- SkyWalking日志增強:自動綁定TraceId到MDC -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.16.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.15</version>
</plugin>
</plugins>
</build>
</project>1.2 SpringCloud微服務項目(新增SkyWalking依賴)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>cloud-traceid-with-skywalking</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 基礎依賴(同無SkyWalking) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SkyWalking核心依賴 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-spring-boot-starter</artifactId>
<version>8.16.0</version>
</dependency>
<!-- SkyWalking Feign增強:跨服務鏈路追蹤 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-feign</artifactId>
<version>8.16.0</version>
</dependency>
<!-- SkyWalking日志增強 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.16.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.15</version>
</plugin>
</plugins>
</build>
</project>2. SkyWalking極簡部署(Docker,中小型項目首選)
# 1. 拉取OAP和UI鏡像(版本與項目依賴一致) docker pull apache/skywalking-oap-server:8.16.0 docker pull apache/skywalking-ui:8.16.0 # 2. 啟動OAP(單節(jié)點,H2存儲,無需額外數(shù)據庫) docker run -d \ --name skywalking-oap \ -p 11800:11800 \ # Agent上報端口 -p 12800:12800 \ # UI訪問OAP端口 -e SW_STORAGE=h2 \ apache/skywalking-oap-server:8.16.0 # 3. 啟動UI(可視化界面,訪問http://localhost:8080) docker run -d \ --name skywalking-ui \ -p 8080:8080 \ --link skywalking-oap:oap \ -e SW_OAP_ADDRESS=http://oap:12800 \ apache/skywalking-ui:8.16.0
3. 核心代碼實現(xiàn)(有SkyWalking專屬)
3.1 TraceId工具類(復用SkyWalking TraceId)
package com.example.traceid.util;
import org.apache.commons.lang3.StringUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
/**
* 有SkyWalking時:復用其TraceId,無需自定義生成
*/
public class TraceIdUtils {
// 復用SkyWalking的MDC Key(SW_TRACE_ID),也可自定義
public static final String TRACE_ID_MDC_KEY = "SW_TRACE_ID";
public static final String TRACE_ID_HEADER_KEY = "X-Trace-Id";
/**
* 獲取TraceId:優(yōu)先SkyWalking,兜底UNKNOWN
*/
public static String getTraceId() {
// SkyWalking原生TraceId
String skyWalkingTraceId = TraceContext.traceId();
if (StringUtils.isNotBlank(skyWalkingTraceId) && !"N/A".equals(skyWalkingTraceId)) {
return skyWalkingTraceId;
}
// 兜底讀取MDC
String mdcTraceId = MDC.get(TRACE_ID_MDC_KEY);
return StringUtils.isBlank(mdcTraceId) ? "UNKNOWN" : mdcTraceId;
}
/**
* 綁定SkyWalking TraceId到MDC(僅特殊場景用)
*/
public static void bindSkyWalkingTraceIdToMdc() {
String traceId = TraceContext.traceId();
if (StringUtils.isNotBlank(traceId) && !"N/A".equals(traceId)) {
MDC.put(TRACE_ID_MDC_KEY, traceId);
}
}
}3.2 TraceId過濾器(簡化:僅綁定SkyWalking TraceId到MDC)
package com.example.traceid.filter;
import com.example.traceid.util.TraceIdUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* 有SkyWalking時:過濾器僅綁定其TraceId到MDC,無需生成
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TraceIdMdcFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
// 綁定SkyWalking TraceId到MDC,供日志讀取
TraceIdUtils.bindSkyWalkingTraceIdToMdc();
chain.doFilter(request, response);
} finally {
MDC.clear();
// 釋放SkyWalking上下文(避免內存泄漏)
TraceContext.release();
}
}
}3.3 異步線程池配置(傳遞SkyWalking上下文)
package com.example.traceid.config;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 有SkyWalking時:異步線程池傳遞MDC+SkyWalking上下文
*/
@Configuration
@EnableAsync
public class AsyncTraceConfig {
private static class MdcTraceDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 復制父線程MDC和SkyWalking TraceId
Map<String, String> parentMdc = MDC.getCopyOfContextMap();
String parentSkyWalkingTraceId = TraceContext.traceId();
return () -> {
try {
// 子線程綁定MDC
if (parentMdc != null) {
MDC.setContextMap(parentMdc);
}
// 子線程綁定SkyWalking TraceId(核心:保證鏈路不中斷)
if (StringUtils.isNotBlank(parentSkyWalkingTraceId) && !"N/A".equals(parentSkyWalkingTraceId)) {
TraceContext.continueTrace(parentSkyWalkingTraceId);
}
runnable.run();
} finally {
MDC.clear();
TraceContext.release(); // 釋放SkyWalking上下文
}
};
}
}
@Bean("asyncTraceExecutor")
public Executor asyncTraceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int core = Runtime.getRuntime().availableProcessors() * 2;
executor.setCorePoolSize(core);
executor.setMaxPoolSize(core * 2);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("async-trace-");
executor.setTaskDecorator(new MdcTraceDecorator());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}3.4 日志配置(綁定SkyWalking TraceId)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<!-- 引入SkyWalking默認配置 -->
<include resource="org/apache/skywalking/apm/toolkit/log/logback/default.xml"/>
<contextName>traceid-with-skywalking</contextName>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<!-- %X{SW_TRACE_ID}:SkyWalking原生TraceId -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{SW_TRACE_ID}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{SW_TRACE_ID}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>3.5 項目掛載SkyWalking Agent(核心步驟)
啟動項目時添加JVM參數(shù)(本地/生產通用):
# 本地IDEA VM Options -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -DSW_AGENT_NAME=boot-traceid-demo # 服務名(UI中顯示) -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 # OAP地址 # 生產Jar啟動 java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \ -DSW_AGENT_NAME=cloud-traceid-demo \ -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.1.100:11800 \ -jar app.jar
4. 有SkyWalking的核心驗證
- 日志中
[%X{SW_TRACE_ID}]顯示SkyWalking的全局TraceId; - 異步任務:子線程TraceId與父線程一致,SkyWalking UI可看到異步鏈路;
- 微服務調用:上下游TraceId一致,SkyWalking UI可看到跨服務完整鏈路;
- 訪問SkyWalking UI(http://localhost:8080),可通過TraceId搜索整條鏈路。
核心差異總結
| 維度 | 無SkyWalking(純自研) | 有SkyWalking(復用TraceId) |
|---|---|---|
| TraceId生成 | 自定義(UUID/雪花ID) | 復用SkyWalking全局TraceId(無需自定義) |
| 核心目標 | 日志攜帶TraceId,定位問題 | 日志+可視化鏈路統(tǒng)一,支持跨服務/異步鏈路分析 |
| 運維成本 | 0(僅代碼) | 低(單節(jié)點Docker部署OAP+UI) |
| 異步/跨服務處理 | 僅傳遞MDC上下文 | 傳遞MDC+SkyWalking上下文(保證鏈路不中斷) |
| 日志配置 | 讀取自定義MDC Key(traceId) | 讀取SkyWalking MDC Key(SW_TRACE_ID) |
到此這篇關于SpringBoot集成TraceId的方案詳解(追蹤ID)的文章就介紹到這了,更多相關SpringBoot集成TraceId內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java集合PriorityQueue優(yōu)先級隊列方法實例
這篇文章主要為大家介紹了java集合PriorityQueue優(yōu)先級隊列方法實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
springboot調用支付寶第三方接口(沙箱環(huán)境)
這篇文章主要介紹了springboot+調用支付寶第三方接口(沙箱環(huán)境),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-10-10
Spring Boot @Scheduled定時任務代碼實例解析
這篇文章主要介紹了Spring Boot @Scheduled定時任務代碼實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06

