Log4j2之ThreadContext
系统中使用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”中
X占位符
在官方文档的Pattern Layout章节的Patterns子章节下,可以看到对于%X占位符的描述。
描述中提到,存入ThreadContext的映射关系,能够输出到对应的X占位符中,这正好是显示登录者信息的理想实现方式。
官方文档地址:Log4j 2 API Thread Context
具体实现
修改log4j2配置文件的PatternLayout.pattern格式,追加[%X{uuid}],占位符
1
| <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] [%X{uuid}] [%X{userId}] %-5level %logger{36} - %msg%n" />
|
追加Java代码,登录时,往ThreadContext存入映射关系,
1 2
| import org.slf4j.MDC; MDC.put("uuid", UUID.randomUUID().toString().replaceAll("\\-", ""));
|
或者
1
| ThreadContext.put("uuid",UUID.randomUUID().toString().replaceAll("\\-", ""));
|
追加Java代码,在退出登录后,清除ThreadContext的映射关系
实际案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| registry.addInterceptor(new HandlerInterceptorAdapter() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { MDC.put("uuid", UUID.randomUUID().toString().replaceAll("\\-", ""));
if (request.getAttribute("claims") != null) { Map<String, String> param = (Map<String, String>) request.getAttribute("claims"); MDC.put(CommonConstant.LOGIN_USER_ID, param.get(CommonConstant.LOGIN_USER_ID)); } if (request.getHeader("user-id") != null || request.getHeader("user_id") != null) { MDC.put(CommonConstant.LOGIN_USER_ID, StringUtils.isNotBlank(request.getHeader("user-id"))?request.getHeader("user-id"):request.getHeader("user_id")); } return true; }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { super.afterCompletion(request, response, handler, ex); MDC.remove("uuid"); MDC.remove(CommonConstant.LOGIN_USER_ID); } }).addPathPatterns("/**");
|
效果
1 2 3 4 5 6 7 8 9 10 11 12
| 22:07:59.828 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] DEBUG 22:07:59.829 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:07:59.959 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] DEBUG 22:07:59.962 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:00.554 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:01.141 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:05.275 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:05.565 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:06.211 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:06.272 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:07.301 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO 22:08:07.350 [http-nio-8012-exec-1] [bed8f0ea4df44273ba5a91e620287893] [302020072488120003] INFO
|
参考资料
Log4j2之ThreadContext