Donnie

机会是留给有准备的人

log4j MDC 工作原理

缘起

前几天接到一个任务,要分析日志,看是谁在线上乱操作。非常郁闷的是在关键请求url操作功能上没有记录到userId。 虽然在InitMDCFilter时有记录userId。但是InitMDCFilter 加载顺序稍后于PageFilter,所以userId没有输出。 经老大提醒,本应在InitMDCFilter 里remove掉的,改在PageFilter 先取到userId,然后remove,伪代码如下 InitMDCFilter :

  try {
        MDC.put("userId", userId);

        chain.doFilter(request, response);

    } finally {

    }

PageFilter :

 try {
        chain.doFilter(request, response);

    } finally {
        log.info(requestUrl+MDC.get("userId"));
        MDC.remove("userId");
    }

一开始不明白神马原理,经看了MDC的源码就明白了

原理

1.先在log4j.xml的ConversionPattern配置 %X{userId},PatternParser会去解析
2.当请求过来时先经过PageFilter(因用户未登录也必须输出请求url,而如果InitMDCFilter先的话,用户未通过登录校验就不执行PageFilter,最后请求url数据都会没有)
3.再经过InitMDCFilter,先验证用户是否登录,登录后取出userId,通过 MDC存储userId,MDC会将数据放入ThreadLocalMap存储
4.由于运行时InitMDCFilter 与PageFilter 是同一个Thread的,所以他们可以共享ThreadLocalMap数据,所以PageFilter 可以在finally里取出userId
5.log4j通过MDCPatternConverter又从MDC里取出数据并打印日志
6.最后在finally里remove数据