【问题标题】:Spring Boot Filter not filtering all my logsSpring Boot Filter 没有过滤我所有的日志
【发布时间】:2019-06-09 22:06:52
【问题描述】:

我在我的 Spring Boot 应用程序中设置了一个过滤器,用于向 MDC 添加一些信息:

@Component
public class LogFilter implements Filter {

    @Override
    public void init(FilterConfig var1) throws ServletException {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        try {
            MDC.put("tag", "Some information);
            chain.doFilter(request, response);
        } finally {
            MDC.clear();
        }
    }
    @Override
    public void destroy() { }
}

这适用于我的大多数应用程序,但对于产生线程的某些操作,此过滤器不会拾取这些消息。

例如,在下面的块中,回调方法发生在一个单独的线程中,所以第一个 log.info 调用被我的 LogFilter 接听,但我的回调中的 log.infolog.error 是不。

private void publishMessage(String message) {
    log.info("Message received. Sending to Kafka topic");
    CompletableFuture<ListenableFuture<SendResult<String, String>>> future = CompletableFuture.supplyAsync(() -> kafkaTemplate.send("myTopic", message));

    try {
        future.get().addCallback(new ListenableFutureCallback<SendResult<String, String>>() {

            @Override
            public void onSuccess(SendResult<String, String> result) {
                log.info("Kafka topic " + myTopic + " published to successfully");
            }

            @Override
            public void onFailure(Throwable ex) {
                log.error("Kafka error: " + ex.getMessage());
            }
        });
        } catch (Exception e) {
            log.error("Kafka has failed you for the last time");
        }
    }

一般来说,似乎任何未在http-nio-8080-exec-X 线程之一中发生的日志事件都会绕过LogFilter。我做错了什么?

我尝试过但没有奏效的方法:

  1. LogFilter 扩展GenericFilterBean,使用@Bean 而不是@Component,然后在我的主应用程序类中使用FilterRegistrationBean 注册该bean
  2. 使用@WebFilter(urlPatterns = {"/*"}, description = "MDC Filter") 和/或@ServletComponentScan

【问题讨论】:

    标签: java spring spring-boot log4j logback


    【解决方案1】:

    MDC 上下文仅适用于当前正在运行的线程,但您的回调将在不同的线程中调用。

    处理它的一种方法是实现ListenableFutureCallback

    private static class MyListenableFutureCallback
                  implements ListenableFutureCallback<SendResult<String, String>> {
    
                private Map<String,String> contextMap = MDC.getCopyOfContextMap();
    
                @Override
                public void onSuccess(SendResult<String, String> result) {
                    MDC.setContextMap(contextMap); //add MDC context here
                    log.info("Kafka topic " + myTopic + " published to successfully");
                }
    
                @Override
                public void onFailure(Throwable ex) {
                    MDC.setContextMap(contextMap); //add MDC context here
                    log.error("Kafka error: " + ex.getMessage());
                }
        }
    

    最后:

    future.get().addCallback(new MyListenableFutureCallback()).
    

    描述了一种更一致的方法Here

    【讨论】:

    • 这肯定会修复我的线程,但是有没有办法让 MDC 被库生成的线程拾取?例如,kafkaTemplate.send() 将产生线程,这些日志事件也不会包含 tag
    • 我不确定其他解决方案是否能解决我的问题,因为我没有使用 ThreadPoolExecutor,我也不了解如何在 Spring Boot 应用程序中连接它
    • 不知道只声明你的taskExecutor为@Bean就够了,你用的是spring kafka吗?
    • 是的,我们使用的是 spring-kafka。无论如何,鉴于我试图发送的信息是静态的,修改 MDC 似乎有点过头了。我认为在 logback 中修改我们的 GELF appender 应该就足够了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-11
    • 2018-06-05
    • 2021-03-05
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多