You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:42:52