一.slf4j中MDC是什么
slf4j除了trace、debug、info、warn、error这几个日志接口外,还可以配合MDC将数据写入日志。换句话说MDC也是用来记录日志的,但它的使用方式与使用日志接口不同。
在使用日志接口时我们一般这么做
Logger LOG = LoggerFactory.getLogger("LOGNAME_OR_CLASS"); if(LOG.isDebugEnabled()) { LOG.debug("log debug"); }
MDC从使用方式上有些不同,我对它的理解是MDC可以将一个处理线程中你想体现在日志文件中的数据统一管理起来,根据你的日志文件配置决定是否输出。
比如以下但不限于以下场景可以考虑使用MDC来达到目的
1.我们想在日志中体现请求用户IP地址
2.用户使用http客户端的user-agent
3.记录一次处理线程的日志跟踪编号(这个编号目的是为了查询日志方便,结合grep命令能根据跟踪编号将本次的处理日志全部输出)
二.MDC的使用
org.slf4j.MDC我个人会用AOP或Filter或Interceptor这类工具配合使用,获得你希望输出到日志的变量并调用MDC.put(String key, String val),比如下面代码片段第5行:
@Around(value = "execution(* com.xx.xx.facade.impl.*.*(..))", argNames="pjp") public Object validator(ProceedingJoinPoint pjp) throws Throwable { try { String traceId = TraceUtils.begin(); MDC.put("mdc_trace_id", traceId); Object obj = pjp.proceed(args); return obj; } catch(Throwable e) { //TODO 处理错误 } finally { TraceUtils.endTrace(); } }
代码通过AOP记录了每次请求的traceId并使用变量"mdc_trace_id"记录,在日志配置文件里需要设置变量才能将"mdc_trace_id"输出到日志文件中。我以logback配置文件为例,看日志第10行%X{mdc_trace_id}:
<appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${CATALINA_BASE}/logs/all.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>${CATALINA_BASE}/logs/all.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- keep 30 days' worth of history --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId:[%X{mdc_trace_id}] - %msg%n</pattern> </encoder> </appender>
三.MDC带来的好处
1.如果你的系统已经上线,突然有一天老板说我们增加一些用户数据到日志里分析一下。如果没有MDC我猜此时此刻你应该处于雪崩状态。MDC恰到好处的让你能够实现在日志上突如其来的一些需求
2.如果你是个代码洁癖,封装了公司LOG的操作,并且将处理线程跟踪日志号也封装了进去,但只有使用了你封装日志工具的部分才能打印跟踪日志号,其他部分(比如hibernate、mybatis、httpclient等等)日志都不会体现跟踪号。当然我们可以通过linux命令来绕过这些困扰。
3.使代码简洁、日志风格统一
四.MDC实践
我们从《log4j2在SpringMVC工程中的运用》中下载SpringMVC.zip工程,导入到Eclipse中。
1.增加LogUtils.java
package com.bijian.study.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import java.lang.invoke.MethodHandles; public class LogUtils { private static Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); public static void putMDC(String traceId) { try { MDC.put("mdc_trace_id", traceId); } catch (Exception e) { log.error("MDCUtil.putMDC happen error", e); } } public static void removeMDC() { try { MDC.remove("mdc_trace_id"); } catch (Exception e) { log.error("MDCUtil.removeMDC happen error", e); } } }
2.修改HelloController.java,在请求的入口加上LogUtils.putMDC(uuid.toString()),在请求结束加上LogUtils.removeMDC();
@ResponseBody @RequestMapping("/greet") public Map<String, Object> greet(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "name", defaultValue = "World") String name) { UUID uuid = UUID.randomUUID(); LogUtils.putMDC(uuid.toString()); Map<String, Object> map = null; try { //由于浏览器会把中文直接换成ISO-8859-1编码格式,如果用户在地址打入中文,需要进行如下转换处理 String tempName = new String(name.getBytes("ISO-8859-1"), "utf-8"); logger.trace("tempName:" + tempName); logger.info(tempName); String userName = helloService.processService(tempName); map = new HashMap<String, Object>(); map.put("userName", userName); logger.trace("运行结果:" + map); } catch (UnsupportedEncodingException e) { logger.error("HelloController greet方法发生UnsupportedEncodingException异常:" + e); } catch (Exception e) { logger.error("HelloController greet方法发生Exception异常:" + e); } LogUtils.removeMDC(); return map; }
3.修改log4j2.xml,增加[%X{mdc_trace_id}]配置
4.启动Tomcat,浏览器中输入http://localhost:8080/SpringMVC/greet回车,日志输出如下所示
15:03:27.874 TRACE com.bijian.study.controller.HelloController[fceb3814-e400-4b86-939c-4e6aee1dc1aa] 67 greet - tempName:World 15:03:27.885 INFO com.bijian.study.controller.HelloController[fceb3814-e400-4b86-939c-4e6aee1dc1aa] 68 greet - World 15:03:27.885 INFO com.bijian.study.service.impl.HelloServiceImpl[fceb3814-e400-4b86-939c-4e6aee1dc1aa] 17 processService - HelloService processService name:World 15:03:27.886 TRACE com.bijian.study.controller.HelloController[fceb3814-e400-4b86-939c-4e6aee1dc1aa] 75 greet - 运行结果:{userName=Hello World} 15:03:40.878 TRACE com.bijian.study.controller.HelloController[1899a285-52fa-4b56-8e88-d230086f129f] 67 greet - tempName:World 15:03:40.880 INFO com.bijian.study.controller.HelloController[1899a285-52fa-4b56-8e88-d230086f129f] 68 greet - World 15:03:40.881 INFO com.bijian.study.service.impl.HelloServiceImpl[1899a285-52fa-4b56-8e88-d230086f129f] 17 processService - HelloService processService name:World 15:03:40.881 TRACE com.bijian.study.controller.HelloController[1899a285-52fa-4b56-8e88-d230086f129f] 75 greet - 运行结果:{userName=Hello World}
其中,fceb3814-e400-4b86-939c-4e6aee1dc1aa和1899a285-52fa-4b56-8e88-d230086f129f就是mdc_trace_id。
整个工程见附件《SpringMVC.zip》。
相关推荐
org.slf4j.MDC.class org.slf4j.Marker.class org.slf4j.MarkerFactory.class org.slf4j.helpers.BasicMDCAdapter.class org.slf4j.helpers.BasicMarker.class org.slf4j.helpers.BasicMarkerFactory.class org.slf4...
1.如果运行程序出现错误:“Exception in thread "main...3.错误:“Exception in thread "main" java.lang.NoSuchMethodError: org.slf4j.MDC.getCopyOfContextMap()Ljava/util/Map”,这是因为jar包版本冲突造成的。
org.slf4j.MDC.class org.slf4j.Marker.class org.slf4j.MarkerFactory.class org.slf4j.helpers.BasicMDCAdapter.class org.slf4j.helpers.BasicMarker.class org.slf4j.helpers.BasicMarkerFactory.class org.slf4...
slf4j-logback-mdc-玩具tldr; 您的日志应为JSON。 不要使用Splunk解析日志行。 使用SLF4J,Logback和MDC的示例应用程序。 这是一个玩具。跑我./gradlew run
slf4j-json-logger 随着越来越多的日志记录框架要求以此来索引用于搜索和分析的字段,对以任意JSON格式进行日志记录的需求正在增长。 现有的日志记录框架对完整JSON规范的支持不佳,并且经常使用快捷方式来扩展...
groovy-slf4j-ndc.zip,使用映射诊断上下文(mdc)模拟slf4j和groovy中的嵌套诊断上下文(ndc)。
一般概念日志应该存在并且对开发人员是透明的...用户信息安装指南(进行中) 包括Jars Jars提供了登录时的扩展,并使用slf4j进行日志记录。 be.vrt.services.logging日志收集器$ {be.vrt.services.logging-version} be
MDC logging (SLF4J) Upgrade to camel 2.7.0 DLQ processing per durable subscription New network connector MBeans IOExceptionHandler for JDBC store Added support for Apache Commons Daemon 改进内容...
Scala是描述配置的理想语言使用宏而不是反射来实现位置跟踪可大大提高性能控制台和日志文件的自己的性能记录器后端可组合的记录器,将不同的记录器与Monoid[Logger[F]]结合在一起SLF4J API的后端站在cats-effect...
欢迎您运行自己的 fork,但是还有另一个类似的库正在维护中。 我没用过。 如果其他人想采用这个库,请不要犹豫询问。 结束通知。用于 Logback 的 LogDNA Appender LogDNA 是托管日志记录平台: ://logdna.com 这个...
我并不是说所有的框架都一样好,而是说只要假以时日,所有的框架在发展过程中,必然会积聚好的方面,淘汰坏的方面,从而变得足够好。从这个角度看,的确没有特别明显的理由来选择Webx,但也没有明显的理由不选择Webx...