mdc追踪日志

不使用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{}里面加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值