0

I use Executor.newSingleThreadScheduled Executor() to do a very simple repetitive task which works great.

But because it is in another thread, I lose the correlation_Id that is in my ThreadContext and the logs created by the child thread are incomplete...

How can I push my correlation_Id to the child thread?

0c7
  • 3
  • 5

2 Answers2

0

To propagate the correlation ID from the parent thread to the child thread and ensure that the logs created by the child thread contain the necessary information, you can make use of Java's InheritableThreadLocal class.

Here's an example of how you can push the correlation ID to the child thread:

import java.util.UUID;
import java.util.concurrent.*;

public class CorrelationIdExample {
    private static final InheritableThreadLocal<String> correlationId = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        // Set correlation ID in the parent thread
        correlationId.set(generateCorrelationId());

        ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.submit(() -> {
            // Get correlation ID from the parent thread
            String correlationIdValue = correlationId.get();
            
            // Perform the task in the child thread
            performTask(correlationIdValue);
        });

        // Shutdown the executor service
        executorService.shutdown();
    }

    private static void performTask(String correlationId) {
        // Log the correlation ID
        System.out.println("Correlation ID in the child thread: " + correlationId);
        
        // Perform the task and log other information
        // ...
    }

    private static String generateCorrelationId() {
        return UUID.randomUUID().toString();
    }
}

In the above code, we use an InheritableThreadLocal variable called correlationId to store the correlation ID. This class allows values to be inherited by child threads automatically.

When the main thread sets the correlation ID using correlationId.set(generateCorrelationId()), the value is automatically propagated to the child thread.

In the child thread, we retrieve the correlation ID using correlationId.get() and use it to perform the task or include it in the logs.

By using InheritableThreadLocal, the correlation ID will be accessible in the child thread, allowing you to maintain the necessary context and ensure complete logs.

Simonluca Landi
  • 931
  • 8
  • 21
0

If you were using new Thread(runnable).start(), you could just set:

log4j2.isThreadContextMapInheritable = true

in a log4j2.component.properties file (or on the command line). With this setting the ThreadContextMap is stored in an InheritableThreadLocal and is copied to all thread spawned by the current one.

An ExecutorService is however reusable by multiple calling threads, so you need to copy the ThreadContextMap each time submit() is called. To do this, wrap your callables and runnables before submission:

public static <T> Callable<T> wrap(final Callable<T> task) {
    final Map<String, String> contextMap = ThreadContext.getImmutableContext();
    final String contextStackTop = ThreadContext.peek();
    return () -> {
        ThreadContext.putAll(contextMap);
        ThreadContext.push(contextStackTop);
        try {
            return task.call();
        } finally {
            ThreadContext.pop();
            ThreadContext.clearMap();
        }
    };
}

and submit tasks as:

final Callable<...> task = ...;
executorService.submit(wrap(task));
Piotr P. Karwasz
  • 12,857
  • 3
  • 20
  • 43