1. 参考文章:https://segmentfault.com/a/1190000022721682,https://blog.csdn.net/millery22/article/details/86672354
2. 开始使用了TreadLocal和拦截器增加标识,但是发现想中消费mq消息的日志,无法打印唯一标识。文章:https://blog.csdn.net/whxwkb/article/details/111594712。查询到MDC可以。
3. 拦截器:
public class LogInterceptor implements HandlerInterceptor {
public final static String REQUEST_ID = "requestId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try{
String uuid = UUID.randomUUID().toString().replace("-", "");
MDC.put(REQUEST_ID, uuid);
} catch (Exception e) {
// 捕捉异常,不可阻断流程,无需做任何处理
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//移除id
MDC.remove(REQUEST_ID);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
拦截器配置:
@Configuration
public class WebInterceptorConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/login")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//解决拦截器导致swagger被拦截
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
// 解决 SWAGGER 404报错
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
MDC的AOP配置:
@Configuration
@Aspect
public class LogMDCAspectConfig {
@Pointcut("execution(public * com.cnpc.cmp.ws.amqp..*.*(..))")
public void webLog(){}
@Before("webLog()")
public void before(JoinPoint joinPoint){
String uuid = UUID.randomUUID().toString().replace("-", "");
MDC.put(LogInterceptor.REQUEST_ID, uuid);
}
/**
* 对于涉及到ThreadLocal相关使用的接口,都需要去考虑在使用完上下文对象时,
* 清除掉对应的数据,以避免内存泄露问题
* @param ret
*/
@AfterReturning(pointcut = "webLog()", returning = "ret")
public void afterReturning(Object ret){
MDC.remove(LogInterceptor.REQUEST_ID);
}
}
logback.xml中配置日志打印格式,其中注意配置的变量和mdc中put的变量一致:MDC.put(REQUEST_ID, uuid);
如:[%X{requestId}]
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</pattern>
xml文件:
<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<configuration scan="true" scanPeriod="10 seconds">
<include resource="org/springframework/boot/logging/logback/base.xml" />
<jmxConfigurator/>
<!-- <property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}" />-->
<!-- 配置相当路径会在本地生成日志文件-->
<property name="LOG_PATH" value="wslog" />
<!--控制台输出 需要在root标签中引入才生效 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,[%X{requestId}]为MDC设置的值跟踪日志的traceId,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</pattern>
</encoder>
</appender>
<appender name="DEBUG_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}/debug.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/debug-%d{yyyyMMdd}.log.%i
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留的天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</Pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印ERROR日志 -->
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</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>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留的天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</Pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印ERROR日志 -->
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="WARN_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<File>${LOG_PATH}/warn.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/warn-%d{yyyyMMdd}.log.%i
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</Pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印ERROR日志 -->
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</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>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{36}-%msg%n</Pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印ERROR日志 -->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--<root level=""> 最基础的日志输出级别默认是debug-->
<root >
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</configuration>
本文介绍了如何结合MDC(Mapped Diagnostic Context)、AOP切面和拦截器来为日志添加跟踪标识。在解决MQ消息日志跟踪问题中,发现TreadLocal和拦截器无法满足需求,转而使用MDC。文中提到了参考文章,并详细说明了拦截器的配置、AOP的设置以及logback.xml的日志格式配置,确保跟踪ID能正确打印。
622





