Java日志追踪唯一id如何实现?

SpringBoot 2.3+
Java 1.8+

Slf4j记录日志,每条打印的日志都会有不同的ID,不方便追踪当前请求日志记录,给当前请求添加唯一ID,
网上找到一些比较老的文章,说的是过滤器AOP实现,
现在主流是啥方式啊,大佬们

方案1

https://tlog.yomahub.com/pages/eea781/
找到个开源的轻量级包,适用于小项目

方案2,根据回答zxdposter的思路

1.TraceInterceptor拦截器

@Component

public class TraceInterceptor implements HandlerInterceptor {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

MDC.put("TID", UUID.randomUUID().toString());

return true;

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {

MDC.clear();

}

}

2.TraceInterceptor注册

@Configuration

public class TraceConfig implements WebMvcConfigurer {

@Autowired

private TraceInterceptor traceInterceptor;

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(traceInterceptor)

.addPathPatterns("/**")//指定该类拦截的url

.excludePathPatterns("/static/**");//过滤静态资源

}

@Override

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**")

.allowedOrigins("*")

.allowCredentials(true)

.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD")

.allowedHeaders("*")

.maxAge(3600);

}

}

3.application.properties 文件路径

logging.file.path=/home/logs/baba

4.logback-spring.xml 配置文件

<configuration scan="true" scanPeriod="10 seconds">

<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<include resource="org/springframework/boot/logging/logback/console-appender.xml" />

<springProperty scope="context" name="fileActive" source="spring.profiles.active"/>

<property name="LOG_PATH" value="${LOG_PATH:-.}"/>

<property name="CONSOLE_LOG_PATTERN" value="%X{TID}|--${CONSOLE_LOG_PATTERN}"/>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>${CONSOLE_LOG_PATTERN}</pattern>

</encoder>

</appender>

<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

<File>${LOG_PATH}/info.log</File>

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}.log.%i</fileNamePattern>

<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>16MB</maxFileSize>

</timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>10</maxHistory>

</rollingPolicy>

<layout class="ch.qos.logback.classic.PatternLayout">

<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} -[%X{TID}]- [%thread] %-5level %logger{36} -%msg%n

</Pattern>

</layout>

</appender>

<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">

<level>ERROR</level>

</filter>

<File>${LOG_PATH}/error.log</File>

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}.log.%i

</fileNamePattern>

<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>16MB</maxFileSize>

</timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>10</maxHistory>

</rollingPolicy>

<layout class="ch.qos.logback.classic.PatternLayout">

<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</Pattern>

</layout>

</appender>

<!-- hibernate日志输入 -->

<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="INFO"/>

<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="INFO"/>

<logger name="org.hibernate.SQL" level="TRACE"/>

<root level="INFO">

<appender-ref ref="INFO_FILE"/>

<appender-ref ref="ERROR_FILE"/>

<appender-ref ref="CONSOLE" />

</root>

</configuration>


回答:

我的方案

我认为最好的方案是用拦截器 + LogFormat + MDC

利用日志框架自身提供的特性解决问题。

第一步

首先配置日志格式,下面的格式是我从 springboot 中拷贝的,可以直接使用,之后增加一个 %X{REQUEST_ID} 标志占位。

logging:

pattern:

console: '%clr(%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(${PID: }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint}%clr(%X{REQUEST_ID}){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}'

file: '%d{${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:%5p} ${PID: } --- [%t] %-40.40logger{39} :%X{REQUEST_ID} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}'

第二步

增加一个 http 请求拦截器,我用的是 spring boot 2.7,实现方式是增加 WebMvcConfigurer 类型的 bean,再实现 addInterceptors 方法,增加自定义的 HandlerInterceptor 类。

第三步

实现自定义 HandlerInterceptor 类中的方法 preHandle
在每次请求前,生成一个唯一 ID,调用 MDC 的静态方法 put

示例(kotlin)

class MvcLoggingConfigurer : WebMvcConfigurer {

override fun addInterceptors(registry: InterceptorRegistry) {

registry.addInterceptor(LoggingHandlerInterceptor())

}

internal class LoggingHandlerInterceptor : HandlerInterceptor {

override fun preHandle(

httpServletRequest: HttpServletRequest,

httpServletResponse: HttpServletResponse,

o: Any

): Boolean {

val requestId = httpServletRequest.getHeader(SystemConstant.REQUEST_ID)

if (CharSequenceUtil.isNotBlank(requestId)) {

MDC.put(SystemConstant.LOGGING_PATTERN_REQUEST_ID, "[$requestId]")

}

return true

}

}

}


回答:

主流方式还是过滤器 + MDC,因为整体逻辑还是比较简单的,所以可能也就没啥变化


回答:

用spring-cloud-starter-sleuth的链路追踪; 支持新线程,线程池等场景;过滤器/拦截器+MDC,在新线程中就追踪不到了

以上是 Java日志追踪唯一id如何实现? 的全部内容, 来源链接: utcz.com/p/944821.html

回到顶部