
spring 默认的 commonsrequestloggingfilter 固定使用 debug 级别输出请求日志,无法通过配置直接修改。本文介绍通过继承并重写该过滤器,结合自定义 logger 与 filterregistrationbean,实现将请求日志统一降级为 info 级别的标准方案。
spring 默认的 commonsrequestloggingfilter 固定使用 debug 级别输出请求日志,无法通过配置直接修改。本文介绍通过继承并重写该过滤器,结合自定义 logger 与 filterregistrationbean,实现将请求日志统一降级为 info 级别的标准方案。
在 Spring Boot 应用中,启用 CommonsRequestLoggingFilter 是记录 HTTP 请求详情(如方法、URI、参数等)的常用方式。但其日志级别由内部硬编码决定——例如,org.springframework.web.filter.CommonsRequestLoggingFilter 的默认日志语句始终使用 logger.debug(...),因此即使配置 logging.level.xxx=INFO,也无法改变实际输出级别。
要真正将请求日志从 DEBUG 提升(语义上实为“降级显示”)至 INFO,最可靠的方式是自定义过滤器:继承 CommonsRequestLoggingFilter,复写核心逻辑,使用 logger.info() 显式输出,并确保其在过滤器链中优先执行,避免请求被后续过滤器(如字符编码过滤器、安全过滤器)修改后导致日志失真。
以下是一个完整可运行的实现方案:
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomRequestLoggingFilter extends CommonsRequestLoggingFilter {
private static final Logger logger = LoggerFactory.getLogger(CustomRequestLoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 在请求处理前记录 INFO 级别日志(可按需扩展:添加 query string、client IP、content length 等)
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String clientIP = getClientIP(request);
String logMessage = String.format("HTTP %s %s%s | Client: %s",
method, uri, queryString != null ? "?" + queryString : "", clientIP);
logger.info(logMessage);
super.doFilterInternal(request, response, filterChain);
}
private String getClientIP(HttpServletRequest request) {
String xff = request.getHeader("X-Forwarded-For");
if (xff != null && !xff.isEmpty() && !"unknown".equalsIgnoreCase(xff)) {
return xff.split(",")[0].trim();
}
return request.getRemoteAddr();
}
}
接着,通过 FilterRegistrationBean 将其注册为 Spring Bean,并显式指定执行顺序(HIGHEST_PRECEDENCE),确保它最先拦截请求:
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<customrequestloggingfilter> customRequestLoggingFilter() {
FilterRegistrationBean<customrequestloggingfilter> registrationBean
= new FilterRegistrationBean();
registrationBean.setFilter(new CustomRequestLoggingFilter());
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
// 可选:限制路径匹配(如仅 /api/**)
// registrationBean.addUrlPatterns("/api/*");
return registrationBean;
}
}</customrequestloggingfilter></customrequestloggingfilter>
⚠️ 注意事项:
-
禁用原生过滤器:务必移除
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG配置,否则原始 DEBUG 日志仍会输出,造成重复; -
线程安全:
doFilterInternal中的日志操作是线程安全的,无需额外同步; -
性能考量:INFO 级别日志在生产环境通常默认开启,若需进一步控制(如仅在特定 profile 下启用),可结合
@ConditionalOnProperty或@Profile注解; -
日志结构化建议:如使用 Logback 或 Log4j2,推荐搭配
logstash-logback-encoder或json-template-layout输出 JSON 格式日志,便于 ELK/Splunk 解析。
通过该方案,你完全掌控了请求日志的内容、格式与级别,既符合 Spring 的扩展规范,又具备良好的可维护性与可观测性。










