不使用mdc的写法
代码:
logger.info("查询请求开始,uuid:{}",uuid);
但是这样写,每行日志都要拼接uuid,代码量大而且容易错。
而且,主流日志框架,无论是log4j,还是logback,本身都带有打印当前线程的功能,一般用%t就可以,t代表的意思是线程(thread)。
需要单独传uuid一般是在有新线程,或线程池调用时,当前线程名会替换为thread1或task-scheduled1等等,这样就不具备追踪功能了,这时就需要自定义uuid来进行追踪。
mdc
本质上是使用ThreadLocal保存变量,要用的时候可以取出来。
一般是和日志结合来使用。
日志中设置模板
log4j.properties 或 logback.xml 配置文件中的pattern模块进行配置:
通用写法:
%X{uuid}-%X{sonUuid}
这种写法也可以:
%X{uuid:-}-%X{sonUuid:-}
注: %X{} 是使用变量,大括号中填变量名(要和java中变量名保持一致)。
基础写法
代码:
String uuid= UUID.randomUUID().toString().replaceAll("-", "");
MDC.put("uuid",uuid);
logger.info("第1步");
logger.info("第2步");
MDC.clear();
线程的写法(重)
如果新启动了线程,那么线程中是获取不到mdc信息的,所以需要加工下。
要点:
1、将mdc通过变量的形式传给线程。
2、set动作要在run方法中(在构造中set实测无效)。
线程类代码:
private class MyRunnable implements Runnable{
private Map<String, String> mdcContextMap;
public MyRunnable(Map<String, String> mdcContextMap){
this.mdcContextMap=mdcContextMap;
// 错误写法:写在这里是抓不到的
// if(null != mdcContextMap){
// MDC.setContextMap(mdcContextMap);
// }
}
@Override
public void run() {
String sonUuid= UUID.randomUUID().toString().replaceAll("-", "");
if(null != mdcContextMap){
MDC.setContextMap(mdcContextMap);
MDC.put("sonUuid",sonUuid);
}
logger.info("第2步");
}
}
主代码:
String uuid= UUID.randomUUID().toString().replaceAll("-", "");
MDC.put("uuid",uuid);
logger.info("第1步");
Map<String, String> mdcContextMap = MDC.getCopyOfContextMap();
new Thread(new MyRunnable(mdcContextMap)).start();
MDC.clear();
for循环写法
这个没啥说的,就是for循环中加个uuid即可,代码:
String uuid= UUID.randomUUID().toString().replaceAll("-", "");
MDC.put("uuid",uuid);
logger.info("第1步");
for (int i = 0; i <3 ; i++) {
String sonUuid= UUID.randomUUID().toString().replaceAll("-", "");
MDC.put("sonUuid",sonUuid);
logger.info(""+i);
}
多循环的写法
和单个for循环差不多,唯一不同的是,内层循环不要用clear(),因为会把所有内容清空。内层循环用remove()即可,最外层才用clear()。 而且,如果最外层有try catch的话,单条记录不用加catch,这样太臃肿了,直接加finally就行(当然try还是是必须的)。
代码:
try{
}finally{
if(!ObjectUtils.isEmpty(MDC.get("forUuid"))){
MDC.remove("forUuid");
}
}
remove()和clear()的区别
remove()是删除一个
clear()是全部清除
为什么要clear()
单线程体现不出来,因为线程结束会自动销毁。如果用的线程池,可能会出现脏数据的问题。
代码示例,暂无。
但是有个以拙御巧的办法,就是不管怎样,永远记得加mdc.clear()。而且最好在finally{}里面加。