【发布时间】: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 上下文(或其中的一部分)传递给工作线程。这里的任务是工作池执行的任何Callable或Runnable。没有看到runAsync是什么,我真的不能再说什么了。 -
runAsync(new DelegatingSecurityContextRunnable(() -> { method1(); method2(); }, SecurityContextHolder.getContext())); -
嗯。因此,在这种情况下,
DelegatingSecurityContextRunnable(我假设它来自 Spring?他们喜欢这类名称)已经完成了我所说的,但使用了 Spring 的安全上下文。看看here,看看它是如何将事物设置为SecurityContextHolder的?该持有人也是一个本地线程的房子,类似于 MDC。您将需要另一个将传递 MDC 值的包装器(或子类Runnable)。
标签: java multithreading slf4j mdc