2016-04-02 229 views
1

我想使用log4j2異步日誌記錄將線程ID作爲日誌消息的一部分進行記錄。在log4j2中傳遞threadId的最佳方法AsyncLogger

With log4j2 2.4.1這可以通過覆蓋logMessage方法的自定義AsyncLogger來實現。

public class ThreadIdAsyncLogger extends AsyncLogger { 
    private static final long serialVersionUID = 1L; 

    private static final ThreadLocal<Boolean> THREAD_CONTEXT_SETUP = new ThreadLocal<Boolean>() { 
     @Override 
     protected Boolean initialValue() { 
      return false; 
     } 
    }; 

    public ThreadIdAsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory) { 
     super(context, name, messageFactory); 
    } 

    @Override 
    public void logMessage(final String fqcn, 
          final Level level, 
          final Marker marker, 
          final Message message, 
          final Throwable thrown) { 
     if (!THREAD_CONTEXT_SETUP.get()) { 
      // it is enough to set it once per thread 
      ThreadContext.put(Constants.ContextMapKeys.THREAD_ID, String.valueOf(Thread.currentThread().getId())); 
      THREAD_CONTEXT_SETUP.set(true); 
     } 

     super.logMessage(fqcn, level, marker, message, thrown); 
    } 
} 

我只是想更新到2.5.0版本,現在我不似乎能夠創建自己的AsyncLogger了,因爲AsyncLoggerDisruptor是包專用。 我知道我可以使用反射,但我想有一個更好的方法。

實現相同功能的最佳實踐(設計和性能明智)是什麼?

回答

2

有工作進展情況本:https://issues.apache.org/jira/browse/LOG4J2-1270

同時可以使用ThreadLocal的地圖或堆疊的方法來做到這一點。性能方面,ThreadLocal堆棧比我想象的地圖稍便宜。

+0

在代碼中的哪個位置應該將threadId壓入堆棧?我想在記錄器中一次性完成此操作,而不是在應用程序代碼中的每個記錄器調用之前執行此操作。你在這裏建議什麼?我應該等待(保持在2.4.1),直到你提到的門票被解除了嗎? – leozilla

+0

通常只有一個入口點,您的應用程序從提供線程模型的框架接收回調。如果您的應用程序是線程池中的某些任務,那將是Runnable的run()方法或Callable的call()方法。對於Servlet,它是service()或doXxx()方法之一。其他框架還有其他回調函數,但通常這些入口點將是推送線程ID的理想候選者(並且在代碼完成後將其彈出)。 –

+0

好吧,我明白了。不幸的是,我只能爲我控制的代碼而不是一些「中間件」線程執行此操作。看着log4j異步記錄器代碼,無論如何,我看到你已經需要獲得threadid,如果你有它,也許可以將它與LogEvent一起傳遞。 – leozilla

相關問題