Reputation: 261
I am setting key-value pair as MDC.put("txnId", UUID.randomUUID().toString());
with log4j.properties as
log4j.appender.R.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%m] [%M] [%L] [%p] [%c] [%X{txnId}] %n
This works absolutely fine while logging the non-threaded logs, but the logs of classes which implements Runnable
, txnId is coming as empty.
Below is the thread code
public class ConsT implements Runnable{
public ConsT() {
}
@Override
public void run() {
log.info("Start thread"));
}
I have tried putting my values in both org.apache.log4j.MDC
and org.slf4j.MDC
but none works.
Upvotes: 1
Views: 1785
Reputation: 781
pass the current txnId as parameter in constructor when you create a new DeviceEventWorker
new DeviceEventWorker(.... , MDC.get("txnId"));
and set again in run method
public class DeviceEventWorker implements Runnable{
private String txnId;
public DeviceEventWorker(String tenantId, DeviceResource device, String eventName, LighthouseDevice lighthouseDevice, String txnId) {
this.tenantId = tenantId;
this.device = device;
this.eventName = eventName;
this.lighthouseDevice = lighthouseDevice;
this.txnId = txnId;
}
@Override
public void run() {
MDC.put("txnId", this.txnId);
log.info("Start thread"));
}
...
}
Upvotes: 1
Reputation: 44952
This problem nothing to do with the Runnable
instance. MDC must be set per-thread basis as it uses a ThreadLocal internally to remember the values.
If you are using Thread
directly or ExecutoService
you must ensure that MDC value is set directly before your Runnable
runs. If you use a thread pool it also must be cleared after the Runnable
finishes.
There are many ways to achieve it but one possible way is to define a wrapper class:
class MDCWrapper implements Runnable {
private final Runnable target;
@Override
public void run() {
MDC.put("txnId", UUID.randomUUID().toString());
try {
target.run();
} finally {
MDC.remove("txnId");
}
}
}
and then use it as:
Thread t = new Thread(new MDCWrapper(new DeviceEventWorker()));
t.start();
Upvotes: 2