我将键值对设置为MDC.put("txnId", UUID.randomUUID().toString());
,而log4j.properties设置为
log4j.appender.R.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%m] [%M] [%L] [%p] [%c] [%X{txnId}] %n
这在记录非线程日志时绝对可以正常工作,但是implements Runnable
,txnId的类的日志为空。
下面是线程代码
public class ConsT implements Runnable{
public ConsT() {
}
@Override
public void run() {
log.info("Start thread"));
}
我尝试将自己的值同时放在org.apache.log4j.MDC
和org.slf4j.MDC
中,但没有用。
答案 0 :(得分:1)
此问题与Runnable
实例无关。 MDC必须基于每个线程设置,因为它在内部使用ThreadLocal来记住值。
如果直接使用Thread
或ExecutoService
,则必须确保在Runnable
运行之前直接设置MDC值。如果使用线程池,则在Runnable
完成后也必须清除它。
有很多方法可以实现它,但是一种可能的方法是定义一个包装器类:
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");
}
}
}
,然后将其用作:
Thread t = new Thread(new MDCWrapper(new DeviceEventWorker()));
t.start();
答案 1 :(得分:1)
在创建新的DeviceEventWorker时将当前txnId作为构造函数中的参数传递
new DeviceEventWorker(.... , MDC.get("txnId"));
然后在运行方法中再次设置
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"));
}
...
}