MDC with Log4j2

MDC(Mapped Diagnostic Context)的使用情境,主要用來解決在多執行緒時,不容易區分不同請求的識別問題。舉例來說,使用者A與使用者B操作了你的系統,在不使用MDC的情況下,你可能會需要把sessionId或者是userName傳遞給所有你操作的程式碼,並在操作程式碼中確實的進行log。本篇文章分享MDC怎麼解決這個問題。

在你接收request的程式碼中,你必定可以獲得sessionId或者是userName,這時候可以直接使用:

ThreadContext.put("sessionId", sessionId);
// invoke sub operations
ThreadContext.clearMap();

設定檔的部分則需要使用%X{key}來宣告於layout.pattern,如下面的範例:

appender.console.layout.pattern = %d{yyyy/MM/dd HH:mm:ss.SSS} %5p[%t] %X{sessionId}(%F:%M:%L) - %m%n

輸出就會長這個樣子:

2022/04/10 12:58:26.738 DEBUG[thread_name] testSessionId(className.java:methodName:320) - this is test message

假如你的sub operations會發生在不同thread,這時候就需要使用到這個property去啟用sub-thread共享相同MDC變數的功能:

System.setProperty("log4j2.isThreadContextMapInheritable","true");

最後要再提醒各位,用完MDC要記得清除放進去的資料,否則是會造成memory leak的。

設定檔格式的部分沒有差別,可以沿用,source code部分則是用ThreadContext取代MDC,可以參考log4j2的source code做對應的替換。
另外一個選擇是直接使用slf4j的MDC: link,讓它由binding決定實做,避免了實做相依。