java - Spring Boot Filter 没有过滤我所有的日志

标签 java spring spring-boot log4j logback

我在我的 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,然后用 @Component 注册那个 bean FilterRegistrationBean 在我的主应用程序类中
  2. 使用 @WebFilter(urlPatterns = {"/*"}, description = "MDC Filter") 和/或 @ServletComponentScan

最佳答案

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

关于java - Spring Boot Filter 没有过滤我所有的日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54206589/

相关文章:

java - 多态性简介 101 java

java - 无法使用 Spring 创建 java.util.concurrent.ThreadPoolExecutor 的 bean

spring - hibernate 异常 : Use of DefaultSchemaNameResolver requires Dialect to provide the proper SQL statement/command

java - 这个 Spring Boot 项目中的 Spring Security 配置究竟是如何工作的?

java - 使用 Spring Boot 进行 Android 改造时出现错误 400、错误请求、Json 解析错误 : Unrecognized token 'agama' : was Expecting ('true' ,'false' , 或 'null' )

java - 如何为外部世界 REST 服务创建 REST 客户端

java - 如何扩展 FutureTask 并确保释放对 Callable 的引用?

java - JPA多对一: Deleting One to Many side

java - 如何在参数化查询中使用 spring MVC jdbcTempates 传递字符串以删除多行

java - MySQL 查询正确的语法在 JdbcTemplate 中不起作用