如何在Spring+Log4j项目中配置仅记录超阈值请求日志?
实现请求超时日志记录(Spring + Log4j)
可以实现,但单纯靠Log4j配置无法直接完成——因为Log4j本身没法获取请求处理的耗时数据,得先通过Spring的机制统计耗时,再结合Log4j的条件过滤功能实现需求。
下面是具体的落地方案:
1. 通过Spring拦截器统计请求耗时
先写一个拦截器,在请求进入时记录开始时间,处理完成后计算耗时,把耗时存入Log4j的**MDC(线程上下文存储)**里,这样Log4j就能拿到这个数值做判断。
public class RequestTimingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.setAttribute("startTime", System.currentTimeMillis()); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { long startTime = (long) request.getAttribute("startTime"); long duration = System.currentTimeMillis() - startTime; // 将耗时存入MDC,键名requestDuration MDC.put("requestDuration", String.valueOf(duration)); // 线程池环境下记得清理MDC,避免数据污染 MDC.remove("requestDuration"); } }
然后把拦截器注册到Spring的Web配置中:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestTimingInterceptor()).addPathPatterns("/**"); } }
2. 配置Log4j实现条件日志
现在MDC里有了请求耗时数据,就可以配置Log4j只打印耗时超过阈值的日志。
Log4j 2.x 配置(推荐,功能更强大)
用ScriptFilter直接判断耗时数值,示例log4j2.xml:
<Appenders> <Console name="SlowRequestConsole" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - 请求耗时:%X{requestDuration}ms,%msg%n"/> <!-- 仅当耗时>=10000ms(10秒)时打印 --> <ScriptFilter onMatch="ACCEPT" onMismatch="DENY"> <Script language="JavaScript"> const duration = parseInt(mdc.get("requestDuration")); return duration >= 10000; </Script> </ScriptFilter> </Console> </Appenders> <Loggers> <!-- 专门给慢请求开一个Logger,或者加到Root里 --> <Logger name="com.yourpackage.controller" level="info" additivity="false"> <AppenderRef ref="SlowRequestConsole"/> </Logger> <Root level="info"> <!-- 其他正常日志的Appender --> </Root> </Loggers>
Log4j 1.x 配置(兼容旧项目)
Log4j 1.x没有内置数值过滤,需要自定义Filter:
public class SlowRequestFilter extends Filter { private long threshold = 10000; // 默认10秒 @Override public void activateOptions() {} @Override public int decide(LoggingEvent event) { Object durationObj = event.getMDC("requestDuration"); if (durationObj != null) { long duration = Long.parseLong(durationObj.toString()); return duration >= threshold ? ACCEPT : DENY; } return NEUTRAL; } // 允许通过配置文件修改阈值 public void setThreshold(long threshold) { this.threshold = threshold; } }
然后在log4j.properties中配置:
# 慢请求专属Appender log4j.appender.SlowRequest=org.apache.log4j.ConsoleAppender log4j.appender.SlowRequest.layout=org.apache.log4j.PatternLayout log4j.appender.SlowRequest.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - 请求耗时:%X{requestDuration}ms,%msg%n # 添加自定义过滤器 log4j.appender.SlowRequest.filter=com.yourpackage.SlowRequestFilter log4j.appender.SlowRequest.filter.threshold=10000 # 给Controller包配置慢请求日志 log4j.logger.com.yourpackage.controller=info, SlowRequest log4j.additivity.com.yourpackage.controller=false
额外提示
- 如果用Spring Boot,拦截器可以直接加
@Component注解,不用手动注册到WebConfig - MDC的清理很重要,线程池复用线程时会残留旧数据,必须在请求结束时移除
- 可以把阈值抽到配置文件(比如
application.properties),通过@Value注入到拦截器或Filter中,更灵活
内容的提问来源于stack exchange,提问作者visc
相关产品推荐
相关产品推荐

