使用MDC为Logback slf4 日志记录线程ID,区分每次执行的会话日志

我们先回想这样一个场景: 
在Java开发中,因为业务需求肯定会输出很多日志。在出现问题时,根据输出的日志分析问题。 
对于一个访问量很大的网站来说,日志的输出速度是很快的,同样的代码方法被同时调用是很正常的。 
那么现在问题来了,我们如何从日志中来区分每一个会话的日志呢?就是我们发现了一个异常,如何知道在这个异常之前对应的一些列日志是什么呢?


我们都知道,不管是普通后台代码执行(定时任务这种)还是用户的HTTP请求,系统都会为开启每一个独立的线程来执行。 
意思就是:10个用户瞬间同时访问了同一个请求,那么Tomcat就会分配10个不同的线程来分别执行每个请求。


思路来了:我们只需要在输出日志的时候,将每个线程的ID同时输出出来即可。这样我们首先要保证每个线程的ID是唯一的。logback日志本身就支持输出线程名称,使用这个是不行的,因为现在都是线程池,同一个线程是会被不同时间的多次请求公用的。 
sl4j 提供的一个工具类MDC,支持 logback和log4j,其作用就是可以让你放入一些变量值到日志中并输出。


下面看一下片段代码: 

在线程执行第一行代码之前放入变量值

MDC.put("ThreadID", java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());

然后在 (以logback为例) 中使用通配符就可以输出这个值,配置片段如下: 
注意留意其中的 {ThreadID}

<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
          <pattern>
             %d|%thread|%X{ThreadID}|%-5level|%logger{65}|%msg%n
          </pattern>
        </encoder>

现在又有一个问题,如何让线程在执行第一行(相对)代码的时候使用 MDC.put 加入变量值呢? 
使用 Filter、MVC 拦截器(Interceptor)。 
特别注意:在开始的地方加入ID,同样需要在线程结束的时候删除该ID,因为线程在线程池里,如果不在执行完业务代码后删除ThreadID,那么该线程下次被使用的时候ThreadID还是存在的,就达不到我们预期的效果了。


不多说了,下面给出实例代码: 
我没有使用Filter,使用的是HandlerInterceptor,道理一样的。因为我嫌Filter 拦截范围太大,什么都拦截还要自己判断处理(这个根据自己实际需求选择吧)。

		 
		 /**
		  * 日志拦截器
		  */
		 public class LogInterceptor implements HandlerInterceptor {

		     /**
		      * 会话ID
		      */
		     private final static String SESSION_TOKEN_KEY = "sessionTokenId";

		     private static final transient Logger logger = LoggerFactory.getLogger(LogInterceptor.class);

		     @Override
		     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		         // 放SessionId
		         String token = java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
		         MDC. put(SESSION_TOKEN_KEY, token);

		         return true;
		     }

		     @Override
		     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
		             throws Exception {
		     }

		     @Override
		     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
		             throws Exception {
		         // 其他逻辑代码

		         // 最后执行MDC删除
		         MDC. remove(SESSION_TOKEN_KEY);
		     }
		 }
	 

logback.xml 配置文件中的部分代码,仅供参考。

		  <appender name="front"
			        class="ch.qos.logback.core.rolling.RollingFileAppender">
			        <file>${logger.basedir}/front.log</file>
			        <rollingPolicy
			            class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			            <fileNamePattern>${logger.basedir}/front.%d{yyyy-MM-dd}.%i.log
			            </fileNamePattern>
			            <maxFileSize>100MB</maxFileSize>
			        </rollingPolicy>

			        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			            <pattern>
			                %d|%thread|%X{sessionTokenId}|%-5level|%logger{65}|%msg%n
			            </pattern>
			        </encoder>

			        <filter class="ch.qos.logback.classic.filter.LevelFilter">
			            <level>ERROR</level>
			            <onMatch>DENY</onMatch>
			            <onMismatch>ACCEPT</onMismatch>
			        </filter>
			    </appender>
	 

ogback 还内置了过滤器,比如 MDCInsertingServletFilter,说了这么多都不如直接看官网资料,官网地址:https://logback.qos.ch/manual/mdc.html#autoMDC


原文地址:http://m.blog.csdn.net/catoop/article/details/71713232

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值