簡介
系統中使用log4j2作為日志系統,然而在高並發的情況下,多次請求的日志參雜在一起,要跟蹤某個用戶一次的請求操作所有日志是很麻煩的。幸運的是log4j中有相應的解決方案。
NDC和MDC
NDC(Nested Diagnostic Context)和MDC(Mapped Diagnostic Context)是log4j種非常有用的兩個類,它們用於存儲應用程序的上下文信息(context infomation),從而便於在log中使用這些上下文信息。NDC采用了一個類似棧的機制來push和pop上下文信息,每一個線程都獨立地儲存上下文信息。比如說一個servlet就可以針對每一個request創建對應的NDC,儲存客戶端地址等等信息。MDC和NDC非常相似,所不同的是MDC內部使用了類似map的機制來存儲信息,上下文信息也是每個線程獨立地儲存,所不同的是信息都是以它們的key值存儲在”map”中。
NDC和MDC的原理是用了java的ThreadLocal類。可以針對不同線程存儲信息。但是今天在log4j2上使用時發現沒有找到NDC和MDC。查找官方文檔,原來是換成了ThreadContext。操作也挺簡單:
X占位符
在官方文檔的Pattern Layout章節的Patterns子章節下,可以看到對於%X占位符的描述。
描述中提到,存入ThreadContext的映射關系,能夠輸出到對應的X占位符中,這正好是顯示登錄者信息的理想實現方式。
官方文檔地址:Log4j 2 API Thread Context
Demo實現
- 修改log4j2配置文件的
PatternLayout.pattern
格式,追加[%X{userName}]
占位符
<PatternLayout pattern="%d %-5p [%t][%X{userName}] %C{2} (%F:%L) - %m%n"/>
2.追加Java代碼,登錄時,往ThreadContext存入映射關系,這里為了方便演示,存了固定值
ThreadContext.put("userName","kevin");
3.追加Java代碼,在退出登錄后,清除ThreadContext的映射關系
ThreadContext.clear();
至此,實現完畢。
效果
2019-10-31 10:01:37,932 INFO [http-nio-8082-exec-4][kevin] aspect.LogAspect (WareLogAspect.java:56)
參考:
-【https://www.wangzhengzhen.com】
-【https://spldeolin.com/posts/log4j2-mdc/?tdsourcetag=s_pctim_aiomsg】