logback与MDC
<h2>1 MDC</h2>
<p>logback内置的日志字段还是比较少,如果我们需要打印有关业务的更多的内容,包括自定义的一些数据,需要借
助logback MDC机制,MDC为“Mapped Diagnostic Context”(映射诊断上下文),即将一些运行时的上下文数据
通过logback打印出来;此时我们需要借助org.sl4j.MDC类。</p>
<p>MDC类基本原理其实非常简单,其内部持有一个InheritableThreadLocal实例,用于保存context数据,MDC提供了
put/get/clear等几个核心接口,用于操作ThreadLocal中的数据;ThreadLocal中的K-V,可以在logback.xml中
声明,最终将会打印在日志中。</p>
<p>在代码中通过<code>MDC.put("userId",1000);</code>设置一个属性的信息,那么在logback.xml中,即可在layout中通过声
明“%X{userId}”来打印此信息。</p>
<p>MDC中管理的数据(简称MDC数据)是以单个线程为单位进行访问的,即对MDC数据的操作(如put, get)只对当前
线程有效,所以也永远是线程安全的。
在服务端,为每个请求分配一个线程进行处理,所以每个服务端线程处理的请求,都具有唯一的MDC上下文数据。</p>
<p>在使用MDC时需要注意一些问题,这些问题通常也是ThreadLocal引起的,比如我们需要在线程退出之前清除MDC中
的数据;在线程池中使用MDC时,那么需要在子线程退出之前清除数据;可以调用MDC.clear()方法。</p>
<p>在JAVA WEB项目中,为了更好的跟踪请求,我们可能希望在日志中打印比如HTTP header信息、运行时的一些
token、code等,那么我们借助MDC即可非常便捷的实现。我们开发一个Filter,此Filter用于解析Http请求中的
一些参数,并将这些参数添加到MDC中,并在logback.xml中声明我们关注的字段。</p>
<h2>2 layout描述</h2>
<ul>
<li>%logger{length}、%lo{length}:在日志事件的源点输出logger的名称。
<pre><code class="language-text">{length}为可选项,length值为数字类型(>=0),在不丢失含义的情况下来限定logger名字的长度(缩短);
在指定length情况下,将会直接返回“.”字符最右端的子字符串。</code></pre></li>
<li>%C{length}、%class{length}:输出发生日志事件的调用类的全限定名。</li>
<li>%d{pattern}、%date{pattern}、%d{pattern,timezone}、%date{pattern,timezone}:输出日志事件的时间。
<pre><code class="language-text">{pattern}为可选项,用于声明时间的格式,比如%d{yyyy-MM-dd HH:mm:ss},pattern必须为
“java.text.SimpleDateFormat”类可兼容的格式。</code></pre></li>
<li>%F、%file:输出发生日志请求的java源文件名,产生文件名信息不是特别的快,有一定的性能损耗,除非对
执行速度不敏感否则应该避免使用此选项。(异常栈中已经包含了全部的追踪栈)</li>
<li>%caller{depth}、%caller{depthStart..depthEnd}:输出产生日志事件的调用者位置信息。
<pre><code class="language-text">{depth}为可选项;位置信息依赖于JVM实现,不过通常会包含调用方法的全限定名、文件名和行号。</code></pre></li>
<li>%L、%line:输出发生日志请求的源文件行号,产生行号信息不是非常的快速,有一定的性能损耗,除非对执行
速度不敏感否则应该避免使用此选项。(默认异常栈中会输出行号)。</li>
<li>%m、%msg、%message:在日志中输出应用提供的message。</li>
<li>%M、%method:输出发出日志记录请求的方法名称,产生方法名不是特别快速。</li>
<li>%p、%le、%level:输出日志事件的level。</li>
<li>%t、%thread:输出产生日志事件的线程名称。</li>
<li>%ex{depth}、%exception{depth}:输出日志事件相关的异常栈,默认会输出异常的全跟踪栈。(%m会包含此部分)</li>
</ul>