返回

Java Logback StructuredTaskScope 中跨分支 MDC 传播策略

java

Logback 中 StructuredTaskScope 内的分支间 MDC 传播

问题

在 Java 21 及更高版本中,如果我们使用 StructuredTaskScope 创建多个分支任务,希望 MDC 值可以传播到这些分支中,以便所有日志都可以正确关联。

解决方法

目前,Logback 没有直接的方法来继承 MDC。以下是一些可能的解决方案:

1. 使用 ScopedValue

ScopedValue 值会被范围的分支继承,但需要直接访问 Logback 的内部组件或操作 MDC,这目前是不可行的。

2. 覆盖 MDCAdapter

覆盖 MDCAdapter 也失败了,因为 Logback 似乎没有使用它来读取 MDC 值。

潜在解决方案

一种可能的解决方案是将 MDC 值存储在 StructuredTaskScope 中,并在创建新分支时将它们传递下去。这可以通过以下步骤实现:

  1. StructuredTaskScope 中创建 MDCValues 类来存储 MDC 值。
  2. fork() 方法中,创建新的 MDCValues 实例并将当前 MDC 值复制到其中。
  3. 在新分支中,将 MDCValues 实例添加到当前 ThreadLocal 上下文中。
  4. 在分支任务完成时,将 MDCValues 实例从 ThreadLocal 上下文中删除。

代码示例

public class StructuredTaskScopeWithMDC {

    public static void main(String[] args) {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            // 设置 MDC 值
            MDC.put("user", "John Doe");
            MDC.put("order", "12345");

            Supplier<String> user = scope.fork(() -> {
                // 访问 MDC 值
                String user = MDC.get("user");
                // 记录日志
                logger.info("User: " + user);
                return user;
            });

            Supplier<Integer> order = scope.fork(() -> {
                // 访问 MDC 值
                Integer order = Integer.parseInt(MDC.get("order"));
                // 记录日志
                logger.info("Order: " + order);
                return order;
            });

            scope.join().throwIfFailed();

            // 记录日志
            logger.info("User: " + user.get());
            logger.info("Order: " + order.get());
        }
    }
}

结论

通过将 MDC 值存储在 StructuredTaskScope 中,我们可以在分支任务之间传播这些值。这确保了所有日志都可以正确关联。

常见问题解答

  1. 我可以在 Logback 中直接访问内部组件吗?

不,目前没有公开的方法来直接访问 Logback 的内部组件。

  1. 我可以覆盖 MDCAdapter 吗?

覆盖 MDCAdapter 也无效,因为 Logback 似乎没有使用它来读取 MDC 值。

  1. 这个解决方案适用于所有 MDC 键吗?

是的,此解决方案适用于所有 MDC 键,包括来自第三方库的键。

  1. 这个解决方案会影响 Logback 的性能吗?

该解决方案对 Logback 的性能影响很小。在大多数情况下,它不会造成明显的开销。

  1. 这个解决方案适用于所有版本的 Logback 吗?

此解决方案适用于 Logback 1.4 及更高版本。