本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net
在现代 Web 开发中,日志记录是必不可少的。通过记录日志,开发者可以追踪请求的流程、定位问题并进行性能调优。本文将介绍如何在 Spring Boot 项目中使用自定义过滤器结合 MDC(Mapped Diagnostic Context)技术,实现高级日志记录功能。
什么是 MDC?
MDC(Mapped Diagnostic Context)是 SLF4J 和 Logback 提供的功能,用于在同一线程中存储和获取诊断上下文信息。这些上下文信息可以是用户 ID、请求 ID 等动态数据,能够帮助我们在日志中添加有用的调试信息。
代码示例
下面的代码展示了如何配置和使用自定义过滤器来实现日志记录。
package com.xiaoyu.bootcustomfilters;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.GenericFilter;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.slf4j.MDC;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<Filter> loggingFilter() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TraceIdLoggingFilter());
registrationBean.addUrlPatterns("/users/*");
registrationBean.setOrder(2);
return registrationBean;
}
private static class TraceIdLoggingFilter extends GenericFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
try (MDC.MDCCloseable ignored = MDC.putCloseable("traceId", generateTraceId())) {
chain.doFilter(request, response);
}
}
private String generateTraceId() {
return java.util.UUID.randomUUID().toString();
}
}
}
配置 Logback
要使上述 MDC 数据在日志中显示,我们需要配置 Logback。在项目的资源目录中创建或修改 logback.xml 文件,添加如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender >
<encoder>
<pattern>%X{traceId} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
代码解析
- FilterConfig 类:这是一个配置类,使用 @Configuration 注解标记,表示这是一个 Spring 配置类。
- loggingFilter 方法:该方法返回一个 FilterRegistrationBean,用来注册自定义过滤器。这里注册的是 TraceIdLoggingFilter,并指定了过滤路径为 / users/*
- TraceIdLoggingFilter 内部类:这是实际的过滤器类,继承自 GenericFilter。在 doFilter 方法中,我们使用 MDC 将一个唯一的 traceId(追踪 ID)添加到日志上下文中。在请求处理完毕后,MDC 会自动清理这个 traceId
- generateTraceId 方法:生成一个唯一的 UUID 作为 traceId
- logback.xml 文件:配置了一个控制台日志输出,并且日志格式中包含了 traceId,从而每条日志都会打印出对应的追踪 ID。
使用说明
当 Spring Boot 应用启动并且有请求到达 / users/* 路径时,TraceIdLoggingFilter 会自动为每个请求生成一个唯一的 traceId,并将其放入 MDC。这样,所有在该请求处理过程中生成的日志都会包含这个 traceId,便于追踪和调试。
结果展示
在本地 curl 这个 endpoint 的时候可以收到回复
curl http://localhost:8080/users
[{"id":"4d194d1f-187c-40a0-b0df-466d1561248f","name":"User1","email":"user1@test.com"},{"id":"0ad8c605-84fa-472f-a7c4-d5c58c10495e","name":"User2","email":"user2@test.com"},{"id":"bdb6e551-4e6c-44bb-b665-44f4d943975f","name":"User3","email":"user3@test.com"}]%
因为这个 call 里调用了users/, 所以会在 log 里输出如下
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.5)
val
如果多次 call 这个 endpoint 会多次打印 val
另外我已经把整个 package 上传到了 github,欢迎查看源码 github 源码