Class TransferableMdc

java.lang.Object
stincmale.server.util.logging.TransferableMdc
All Implemented Interfaces:
Closeable, AutoCloseable, MDCAdapter

@NotThreadSafe
public final class TransferableMdc
extends Object
implements MDCAdapter, Closeable
A read-only MDCAdapter which allows to copy the state of MDC between threads.

This class is not thread-safe but correctly transfers MDC if used according to the provided idiom.

Usage examples.

Correct:


 TransferableMdc outerMdc = TransferableMdc.current();
 executor.submit(() -> {
  try (var transferredMdc = outerMdc.transfer()) {
      logger.info("This call can access contents of outerMdc via org.slf4j.MDC");
  }
  logger.info("This call cannot access contents of outerMdc via org.slf4j.MDC");
 });
 

Incorrect 1:


 executor.submit(() -> {
  try (var transferredMdc = TransferableMdc.current().transfer()) {
      //...
  }
 });
 
This is incorrect because we do not have access to the context data of the "outer" thread.

Incorrect 2:


 TransferableMdc outerMdc = TransferableMdc.current();
 executor.submit(() -> {//task1
  try (var transferredMdc = outerMdc.transfer()) {
      //...
  }
 });
 executor.submit(() -> {//task2
  try (var transferredMdc = outerMdc.transfer()) {
      //...
  }
 });
 
This is incorrect because task1 and task2 may be executed concurrently and hence methods transfer() and close() may be executed concurrently, and these methods are not thread-safe. In order to prevent such incorrect usages, close() throws IllegalStateException if detects that the method is called more than once. The correct usage idiom:

 TransferableMdc outerMdc1 = TransferableMdc.current();
 executor.submit(() -> {//task1
  try (var transferredMdc = outerMdc1.transfer()) {
      //...
  }
 });
 TransferableMdc outerMdc2 = TransferableMdc.current();
 executor.submit(() -> {//task2
  try (var transferredMdc = outerMdc2.transfer()) {
      //...
  }
 });