【问题标题】:Append correlation id to every log java将相关 id 附加到每个日志 java
【发布时间】:2020-10-05 17:38:52
【问题描述】:

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

这是我的过滤器。在我进入像 runAsync() 这样的异步块之前,它运行良好。

我了解了 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>

【问题讨论】:

  • 在过滤器中执行的操作相同 - 在提交任务进行处理时应该执行此操作。该任务将从创建它的 MDC 捕获信息,并在启动时对其进行设置,然后在完成时将其删除。
  • @M.Prokhorov 我有点不明白,你在说什么任务。我调用我的控制器方法,然后转到使用runAsync() 的服务方法。而且我不会在任何地方传递相关 ID(您可以用俄语回答)
  • 这不是俄罗斯人所以就是这样 - 所以我不能。一般来说,无论runAsync 是什么,都应该将MDC 上下文(或其中的一部分)传递给工作线程。这里的任务是工作池执行的任何CallableRunnable。没有看到runAsync 是什么,我真的不能再说什么了。
  • runAsync(new DelegatingSecurityContextRunnable(() -&gt; { method1(); method2(); }, SecurityContextHolder.getContext()));
  • 嗯。因此,在这种情况下,DelegatingSecurityContextRunnable(我假设它来自 Spring?他们喜欢这类名称)已经完成了我所说的,但使用了 Spring 的安全上下文。看看here,看看它是如何将事物设置为SecurityContextHolder 的?该持有人也是一个本地线程的房子,类似于 MDC。您将需要另一个将传递 MDC 值的包装器(或子类 Runnable)。

标签: java multithreading slf4j mdc


【解决方案1】:

这是我最终得到的解决方案。感谢@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();
}}

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

之前: runAsync(() -&gt; someMethod());

之后: runAsync(wrap(() -&gt; someMethod()));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多