将相关ID附加到每个日志Java

问题描述

我需要将相关ID附加到我收到的每个请求的日志中。

这是我的过滤器。直到我进入runAsync()之类的异步块之前,它都很好用。

logs

我阅读了有关MDC及其如何使用ThreadLocal的信息,但由于它使用了ForkJoinPool,因此无法理解如何在异步中使用它。

@Component
public class Slf4jFilter extends OncePerRequestFilter {

private static final String CORRELATION_ID_HEADER_NAME = "correlation-id";
private static final String CORRELATION_ID_LOG_VAR_NAME = "correlationId";

@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)
throws servletexception,IOException {
    try {
        ofNullable(request.getHeader(CORRELATION_ID_HEADER_NAME)).ifPresent(correlationId -> MDC
            .put(CORRELATION_ID_LOG_VAR_NAME,correlationId));
        chain.doFilter(request,response);
    }finally {
        removeCorrelationId();
    }
}

protected void removeCorrelationId() {
    MDC.remove(CORRELATION_ID_LOG_VAR_NAME);
}
}

logback.xml

<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread %X{correlationId}] %-5level %logger{36} - %msg %n</pattern>
    </encoder>
</appender>
<root level="INFO">
    <appender-ref ref="stdout" />
</root>

解决方法

这是我最终的解决方案。感谢@ M.Prokhorov

在项目内部创建一个名为MdcRetention的类。

public final class MdcRetention {

public static Runnable wrap(final Runnable delegate) {
    return new MdcRetainingRunnable() {
        @Override
        protected void runInContext() {
            delegate.run();
        }
    };
}

private static abstract class MdcRetentionSupport {
    protected final Map<String,String> originalMdc;

    protected MdcRetentionSupport() {
        Map<String,String> originalMdc = MDC.getCopyOfContextMap();
        this.originalMdc = originalMdc == null ? Collections.emptyMap() : originalMdc;
    }
}

public static abstract class MdcRetainingRunnable extends MdcRetentionSupport implements Runnable {

    @Override
    public final void run() {
        Map<String,String> currentMdc = MDC.getCopyOfContextMap();
        MDC.setContextMap(originalMdc);
        try {
            runInContext();
        } finally {
            MDC.setContextMap(currentMdc);
        }
    }

    abstract protected void runInContext();
}}

然后使用静态方法runAsync()将您的Runnable包装在MdcRetention.wrap()

之前: runAsync(() -> someMethod());

之后: runAsync(wrap(() -> someMethod()));

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...