log4j无法在线程中打印MDC键值对

时间:2019-02-18 17:11:23

标签: java logging log4j slf4j mdc

我将键值对设置为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.MDCorg.slf4j.MDC中,但没有用。

2 个答案:

答案 0 :(得分:1)

此问题与Runnable实例无关。 MDC必须基于每个线程设置,因为它在内部使用ThreadLocal来记住值。

如果直接使用ThreadExecutoService,则必须确保在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"));
    }
...
}