需求:
Spring web项目需要一个唯一id,追踪同一请求日志打印,提升运维效率。
接口请求日志可以单独记录到一个日志文件中,实现方案参考:记录web应用请求日志
1.使用MDC
MDC(Mapped Diagnostic Context)可以帮助你在日志中加入唯一的 traceId,从而在分布式系统中追踪请求
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;
@Component
public class TraceIdFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String traceId = UUID.randomUUID().toString();
MDC.put("traceId", traceId);
try {
chain.doFilter(request, response);
} finally {
MDC.clear(); // 清除 MDC 中的 traceId,避免影响后续请求
}
}
@Override
public void destroy() {
}
}
2.日志打印
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 从spring 资源文件读取属性 -->
<springProperty scope="context" name="log.path" source="log.path" defaultValue="logs"/>
<springProperty scope="context" name="log.env" source="env.name" defaultValue="dev"/>
<springProperty scope="context" name="log.service.name" source="spring.application.name" defaultValue="nanWeb"/>
<!-- appender是configuration的子节点,是负责写日志的组件。 -->
<!-- ConsoleAppender:把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- %d表示日期时间,默认是yyyy-MM-dd HH:mm:ss -->
<!-- %t 表示线程名称; %-5level表示日志级别; %X{traceId} 表示MDC中的traceID;-->
<!-- %logger{36} ; .%M表示记录方法名称; %file:%line 表示日志记录方法所在的文件名和行号; %msg:表示日志消息; %n 换行符 -->
<pattern>%d [%t] %-5level | %X{traceId} | %logger{36}.%M\(%file:%line\) - %msg%n</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是demo.log -->
<!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<File>${log.path}/${log.service.name}-${log.env}.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<!-- 定义归档文件名 -->
<fileNamePattern>${log.path}/arch/${log.service.name}-${log.env}.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件,该日志文件的保存期限为3天 -->
<maxHistory>3</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成1KB看效果 -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点,用来设置日志的输入格式 -->
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level | %X{traceId} | %logger{36}.%M\(%file:%line\) - %msg%n
</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 定义根日志级别为 INFO -->
<root level="INFO">
<!-- 将根日志连接到名为 STDOUT 的 appender -->
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>