Slf4j MDC机制及日志应用实战

参考:https://blog.csdn.net/xxcupid/article/details/51955356(这个作者写了一系列,挺容易上手看的)

下面是使用时须知

MDC 是日志的增强功能,如果配置了MDC,并添加了相应的key value,就会在打日志的时候把key对应的value打印出来。

如果不用MDC.clear()的话会有什么影响?
答:如果都是用new Thread方法建立的线程没有问题,因为之后线程会消亡。
但是如果用ThreadPool线程池的话,线程是可以重用的,如果之前的线程的MDC内容没有清除掉的话,再次重线程池中获取到这个线程,会取出之前的数据(脏数据),会导致一些不可预期的错误,所以当前线程结束后一定要清掉。可以用上一篇提到的的AbstractRunnable这个类,封装了clear操作,程序员只需关心业务即可,不要担心忘记clear了。

我们来使用吧

首先再明确一点是,MDC使用的get 和 put 都是由XXXAdapter 中ThreadLocal 进行把控的,所以每个线程都是数据独立的。
竟然他是用来做日志的log打印的,其实和其他的没什么多少区别,只是用他的话,解决了多线程情况下的问题

实战

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Logger {

    //注入MDC
    boolean log() default true;
}

@Aspect
@Component
public class AspectLogger {

    private final static char[] HEX_DIGITS_CAPITAL = {'0','1' ,'2','3','4','5','6','7','8','9',
            'A','B','C','D','E','F'};

    private final static char[] HEX_DIGITS_SMALL = {'0','1' ,'2','3','4','5','6','7','8','9',
            'a','b','c','d','e','f'};


    @Pointcut("@annotation(com.longchuang.ronghe.common.config.Logger)")
    public void pointcut() {
        // do nothing
    }

    @Before("pointcut()")
    public void doBefore(JoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        Logger annotation = method.getAnnotation(Logger.class);
        if(annotation.log()){
            JSONObject jsonObject = JSONObject.fromObject(point.getArgs()[0]);
            String traceLogId = (String)jsonObject.get("traceLogId");// 这里写死先
            if(StringUtils.isNotEmpty(traceLogId) && traceLogId.length() == 32){
                MDC.put("TRACE_LOG_ID",traceLogId);
            }else{
                createTraceLogId();
            }
        }
    }

    @After("pointcut()")
    public void doAfter(JoinPoint point){
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        Logger annotation = method.getAnnotation(Logger.class);
        if(annotation.log()){
            MDC.clear();
        }
    }

    private void createTraceLogId() {
        byte[] bytes = new byte[16];
        ThreadLocalRandom.current().nextBytes(bytes);
        MDC.put("TRACE_LOG_ID",byteArrayToHex(bytes,false));
    }

    /**
     * 将字节数组转换为16进制字符串
     * @param byteArray 字节数组
     * @param isCapital 是否输出为大写字母
     * @return
     */
    public static String byteArrayToHex(byte[] byteArray , boolean isCapital){
        char[] resultCharArray = new char[byteArray.length * 2];
        int index = 0;
        char[] hexDigits = isCapital ? HEX_DIGITS_CAPITAL : HEX_DIGITS_SMALL;
        for (byte b : byteArray){
            resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b & 0xf];
        }
        return new String(resultCharArray);
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值