SpringBoot使用TraceId进行日志追踪的实现
作者:陪你翱翔直到世界尽头
查询日志的痛点:项目中每当我们查询日志的时候都是看前端请求什么接口,根据一些关键字进入服务器查询日志中是否有这个关键字,然而这个关键字在日志里面并不是唯一的,所以要生成一个唯一的标识,每一次请求都是唯一的一串字符,查询会过滤掉很多无用的信息,快捷查找到这次请求。为了解决这个痛点,就使用了TraceId。
一、TraceId 定义
用于标识某一次具体的请求ID。当用户的请求进入系统后,会在RPC调用网络的第一层生成一个全局唯一的traceId,并且会随着每一层的RPC调用,不断往后传递,这样的话通过traceId就可以把一次用户请求在系统中调用的路径串联起来。
在分布式系统中,一个请求可能会涉及多个服务和组件的调用,而traceId可以帮助我们追踪和查看整个请求的流程和调用链
二、TraceId的请求流程
在最开始请求系统时候生成一个全局唯一的traceId,放在http 请求header中,系统接收到请求后,从header中取出这个traceId,放入MDC中,这个traceId伴随着这整个请求的调用周期,即当一个服务调用另外一个服务的时候,需要将traceId往下传递,从而形成一条链路。
注意:这次的traceId主要是用UUID来生成的,前端生成traceId,后端拦截器拦截到了做一层判断,如果前端有,就不需要后端生成,而且只需要将前端的这个traceId发给后端人员,后端人员就能直接能定位到日志,不需要再让前端给请求的是什么接口,所以建议是前端来生成traceId。
三、SpringBoot整合TraceId
(一)添加一个logback.xml
logback.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="LOG_PATH" value="/xxx/log"/> <!-- 项目的日志路径 --> <property name="LOG_FILE" value="xxx"/> <property name="DATE_PATH" value="${LOG_PATH}/%d{yyyy-MM-dd}"/> <!-- 日志输出格式 --> <property name="log.pattern.console" value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) [traceId:%X{traceId}] %highlight(%-5level) %boldMagenta(%logger{10}) - %cyan(%msg%n)"/> <property name="log.pattern.file" value="%d{HH:mm:ss.SSS} [%thread] [traceId:%X{traceId}] %-5level %logger{20} - [%method,%line] - %msg%n"/> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <include resource="org/springframework/boot/logging/logback/console-appender.xml"/> <!-- 控制台输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${log.pattern.console}</pattern> <charset>utf8</charset> </encoder> </appender> <!-- 日志文件fzwyapi-admin.log --> <appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/${LOG_FILE}.log</file> <append>true</append> <encoder> <!-- <pattern>${CONSOLE_LOG_PATTERN}</pattern>--> <pattern>${log.pattern.file}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern> ${DATE_PATH}/%i.log </fileNamePattern> <maxHistory>15</maxHistory> <totalSizeCap>20GB</totalSizeCap> <maxFileSize>50MB</maxFileSize> </rollingPolicy> </appender> <appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <file>${LOG_PATH}/${LOG_FILE}.error.log</file> <append>true</append> <encoder> <!-- <pattern>${CONSOLE_LOG_PATTERN}</pattern>--> <pattern>${log.pattern.file}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern> ${DATE_PATH}/%i.error.log </fileNamePattern> <maxHistory>15</maxHistory> <totalSizeCap>20GB</totalSizeCap> <maxFileSize>50MB</maxFileSize> </rollingPolicy> </appender> <root level="info"> <appender-ref ref="fileAppender"/> <appender-ref ref="fileError"/> <appender-ref ref="STDOUT"/> </root> </configuration>
(二)添加TraceId工具类
TraceIdUtil.java
package xxx; import org.slf4j.MDC; import java.util.UUID; /** * @author lyc * @date 2024/10/17 * @funtion */ public class TraceIdUtil { public static final String TRACE_ID = "traceId"; public static String getTraceId() { String traceId = MDC.get(TRACE_ID); return traceId == null ? "" : traceId; } public static void setTraceId(String traceId) { MDC.put(TRACE_ID, traceId); } public static void remove() { MDC.remove(TRACE_ID); } public static void clear() { MDC.clear(); } public static String generateTraceId() { return UUID.randomUUID().toString().replace("-", ""); } }
(三)添加TraceId拦截器
SystemTraceIdInterceptor.java
package xxx; import xxx.TraceIdUtil; import org.slf4j.MDC; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author lyc * @date 2024/10/17 * @funtion */ @Component public class SystemTraceIdInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //如果有上层调用就用上层的ID String traceId = request.getHeader(TraceIdUtil.TRACE_ID); if (traceId == null) { traceId = TraceIdUtil.generateTraceId(); } MDC.put(TraceIdUtil.TRACE_ID, traceId); //配置traceId到响应header中 response.setHeader(TraceIdUtil.TRACE_ID, MDC.get(TraceIdUtil.TRACE_ID)); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //调用结束后删除 MDC.remove(TraceIdUtil.TRACE_ID); } }
(四)InterceptorConfig配置TraceId拦截器
TraceIdUtil.java
package xxx.config; import xxx.SystemTraceIdInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; /** * @author lyc * @updated: 2024/10/17 * @funtion */ @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Resource private SystemTraceIdInterceptor systemTraceIdInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { //配置链路追踪traceId拦截器 registry.addInterceptor(systemTraceIdInterceptor).addPathPatterns("/**"); } }
四、效果
到此这篇关于SpringBoot使用TraceId进行日志追踪的实现的文章就介绍到这了,更多相关SpringBoot TraceId日志追踪内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!