spring boot 用 handlerinterceptor 记录请求日志,核心是 prehandle 抓请求信息并生成 traceid 写入 mdc,aftercompletion 记响应状态与耗时,通过 webmvcconfigurer 注册拦截器并排除非业务路径,配合 logback 结构化输出含 traceid 的可检索日志。

Spring Boot 项目用拦截器记录请求日志,核心是利用 HandlerInterceptor 在请求进入 Controller 前后捕获关键信息,并配合日志框架(如 Logback)输出结构化日志。重点不是“能不能记”,而是“记什么、怎么记得清、怎么查得快”——尤其要带上 traceId 实现链路追踪。
一、定义拦截器:抓取请求入口和出口信息
创建一个类实现 HandlerInterceptor,重点关注三个方法:
-
preHandle:记录请求 URI、HTTP 方法、请求头(如 User-Agent)、查询参数、Body 内容(需包装 request)、生成并存入 MDC 的
traceId -
afterCompletion:记录响应状态码、耗时(用
System.currentTimeMillis()差值)、异常信息(如有) - 不建议在
postHandle中记录响应体,因为此时 ModelAndView 可能为空,且响应体尚未写入输出流;如需记录响应内容,应结合ContentCachingResponseWrapper或改用 Filter
二、注入 traceId 实现日志串联
单次请求的日志散落在不同线程或异步调用中,必须靠唯一标识串联。推荐做法:
- 在
preHandle中生成 UUID 或使用org.springframework.util.IdGenerator生成traceId - 通过
MDC.put("traceId", traceId)将其绑定到当前线程上下文(Logback 支持自动打印 MDC 字段) - 在
afterCompletion中调用MDC.clear()避免线程复用导致日志污染 - 若涉及异步(如
@Async),需手动将 MDC 内容传递至子线程(例如用ThreadLocal包装或借助Logback 的 AsyncAppender配置)
三、注册拦截器:让 Spring MVC 知道它该生效
不能只写类,必须显式注册。推荐方式是实现 WebMvcConfigurer 并重写 addInterceptors:
- 新建配置类,
@Configuration注解 - 重写
addInterceptors(InterceptorRegistry registry) - 用
registry.addInterceptor(你的拦截器实例).excludePathPatterns("/actuator/**", "/swagger-ui/**")排除监控、文档等非业务路径 - 注意:拦截器默认只作用于 Controller 层请求,静态资源、错误页、Actuator 端点等不会触发
四、日志格式适配:让输出可读又可查
在 logback-spring.xml 中配置 pattern,把 traceId、时间、级别、URI、耗时、状态码都打出来:
- 示例 pattern:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [traceId:%X{traceId}] %logger{36} - URI:%X{uri} | Cost:%X{cost}ms | Status:%X{status} - 配合
LoggingEventCompositeJsonEncoder输出 JSON 格式日志,方便 ELK(Elasticsearch + Logstash + Kibana)采集与检索 - 敏感字段(如密码、token)务必脱敏,不要直接打印原始 Body
不复杂但容易忽略。关键是 traceId 要早生成、早放入 MDC、早清理,日志字段要对齐排查场景——比如出问题时,你第一眼想看的是哪个字段?就把它固定打在每行开头。











