AbstractRequestLoggingFilter:记录请求日志的 Filter

713 阅读1分钟

Spring Web 中自带记录请求参数的轮子:AbstractRequestLoggingFilter,并提供了一个默认实现类:CommonsRequestLoggingFilter。

如果不想使用默认的 CommonsRequestLoggingFilter,可以新建一个类:HttpRequestLoggingFilter,继承 AbstractRequestLoggingFilter,重写其 beforeRequest() 和 afterRequest 抽象方法,并将该 Filter 注册为 Spring Bean 即可。

注意事项:

  • 将 includeQueryString 和 includePayload 配置设置为 true,这两个配置默认为 false,否则只会记录请求 URI,不会记录请求参数。
  • 使用 Ordered 接口或者 @Order 注解调整 HttpRequestLoggingFilter 在 FilterChain 中的顺序。不影响其他业务的前提下,可以将该 Filter 的顺序往前调。
  • 设置合适的 maxPayloadLength,单位为字节。如果设置得太大,每次请求都会开辟 maxPayloadLength 字节的内存;如果设置得太小,request payload (body) 会被截断。

扩展:在 Controller 执行代码报错后,可以在 HttpRequestLoggingFilter 中打印请求参数,方便后续排查问题。

@Slf4j
public class HttpRequestLoggingFilter extends AbstractRequestLoggingFilter implements Ordered {

    private int order;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        boolean isFirstRequest = !isAsyncDispatch(request);
        HttpServletRequest requestToUse = request;

        if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
            requestToUse = new ContentCachingRequestWrapper(request, getMaxPayloadLength());
        }

        boolean shouldLog = shouldLog(requestToUse);
        if (shouldLog && isFirstRequest) {
            beforeRequest(requestToUse, createMessage(requestToUse, "", ""));
        }
        try {
            filterChain.doFilter(requestToUse, response);
        } finally {
            Throwable exception = fetchException(request);
            shouldLog = shouldLog || exception != null;
            if (shouldLog && !isAsyncStarted(requestToUse)) {
                String message = createMessage(requestToUse, "", "");
                if (exception != null) {
                    log.info("Error request message: " + message);
                } else {
                    log.debug(message);
                }
            }
        }
    }

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        log.debug(message);
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
    }

    @Override
    protected boolean shouldLog(HttpServletRequest request) {
        return log.isDebugEnabled();
    }

    @Override
    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    private Throwable fetchException(HttpServletRequest request) {
        Throwable exception = (Throwable) request.getAttribute(ErrorAttributes.ERROR_ATTRIBUTE);
        if (exception == null) {
            exception = (Throwable) request.getAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE);
        }
        return exception;
    }

}