slf4j MDC使用

最近也是在项目代码里发现一个地方有个MDC.put(),忍不住好奇点了进去,于是知道了MDC这个东西,细研究一下,发现还真是个好东西。

MDC解决了什么问题

MDC全名Mapped Diagnostic Contexts,是slf4j提供的一个API,主要功能就是在多线程环境下进行日志调用链路的跟踪,比如在一次事务处理中,会经过多个处理的流程,为了定位问题方便,在每个流程中免不了打印一些日志信息。在线上环境中,最后打出来的日志是很多的,如何定位哪些信息是在同一个线程中打印的呢?MDC很优雅地解决了这个问题。其他的日志框架有没有这个功能我暂时没去研究,对于slf4j(现在应该都会优先用这个吧?),实现了MDC的有logback和log4j,这里暂时以logback为例,更详细的文档见这里

MDC的使用

MDC使用起来还是相当简单的,一个例子就搞定了。

首先配置日志配置文件logback.xml

<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{txId} - %msg%n</pattern>
</encoder>
</appender> <root level="debug">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

为了输出很简单的一个配置注意有个占位符txId,这就是我们每次事务处理的id。现在我们模拟多个线程同时处理事务。定义了一次事务处理的流程。

public class TxFlow {
private static final Logger LOGGER = LoggerFactory.getLogger(TxFlow.class); private void prepare() {
LOGGER.info("prepare tx");
} private void handle() {
LOGGER.info("handle tx");
try {
Thread.sleep(new Random().nextInt(4) * 1000);
} catch (InterruptedException ignored) {
}
} private void submit() {
LOGGER.info("submit tx");
} public void run() {
prepare();
handle();
submit();
}
}

对每一次事务处理,我们生成一个事务ID,并put到MDC中去。

public class TxMDC {
private static final Logger LOGGER = LoggerFactory.getLogger(TxMDC.class); public static void main(String[] args) {
LOGGER.info("main thread start");
for (int i = 0; i < 5; i++) {
new Thread(() -> {
MDC.put("txId", UUID.randomUUID().toString());
new TxFlow().run();
}).start();
}
}
}

得到输出如下,这样就很容易根据事务ID将一次事务中各个流程中的日志信息串联起来,便于后期的处理(比如查到一次事务的txId后grep一下txId就把整个处理流程中的日志信息串联起来了)。

13:20:21.581 [main] INFO  i.d.l.TxMDC txId=主线程ID - main thread start
13:20:22.050 [Thread-1] INFO i.d.l.TxFlow txId=c4bd7356-b932-4571-bbad-d450e90de821 - prepare tx
13:20:22.050 [Thread-1] INFO i.d.l.TxFlow txId=c4bd7356-b932-4571-bbad-d450e90de821 - handle tx
13:20:22.050 [Thread-2] INFO i.d.l.TxFlow txId=9ee129de-0dfe-4086-9267-e6868e1478b0 - prepare tx
13:20:22.050 [Thread-2] INFO i.d.l.TxFlow txId=9ee129de-0dfe-4086-9267-e6868e1478b0 - handle tx
13:20:22.052 [Thread-3] INFO i.d.l.TxFlow txId=7971563a-2807-4e1f-bbd9-639a090b5689 - prepare tx
13:20:22.053 [Thread-3] INFO i.d.l.TxFlow txId=7971563a-2807-4e1f-bbd9-639a090b5689 - handle tx
13:20:22.053 [Thread-4] INFO i.d.l.TxFlow txId=5c5656c4-bc7a-4277-be25-2269aee0b54e - prepare tx
13:20:22.053 [Thread-4] INFO i.d.l.TxFlow txId=5c5656c4-bc7a-4277-be25-2269aee0b54e - handle tx
13:20:22.054 [Thread-0] INFO i.d.l.TxFlow txId=ebaa0082-1a19-450d-ba71-679510a2fa92 - prepare tx
13:20:22.054 [Thread-0] INFO i.d.l.TxFlow txId=ebaa0082-1a19-450d-ba71-679510a2fa92 - handle tx
13:20:22.082 [Thread-1] INFO i.d.l.TxFlow txId=c4bd7356-b932-4571-bbad-d450e90de821 - submit tx
13:20:23.055 [Thread-0] INFO i.d.l.TxFlow txId=ebaa0082-1a19-450d-ba71-679510a2fa92 - submit tx
13:20:24.050 [Thread-2] INFO i.d.l.TxFlow txId=9ee129de-0dfe-4086-9267-e6868e1478b0 - submit tx
13:20:25.054 [Thread-3] INFO i.d.l.TxFlow txId=7971563a-2807-4e1f-bbd9-639a090b5689 - submit tx
13:20:25.055 [Thread-4] INFO i.d.l.TxFlow txId=5c5656c4-bc7a-4277-be25-2269aee0b54e - submit tx

MDC的实现原理

slf4j只提供了一个接口,具体的实现在logback和log4j中。不过从上面功能中,我们已经知道MDC记录了是线程上下文,聪明的你肯定已经想到了实现是基于ThreadLocal,事实也如此,有兴趣继续研究代码我就不多说了。

slf4j MDC使用的更多相关文章

  1. Slf4j MDC 使用和 基于 Logback 的实现分析

    前言 如今,在 Java 开发中,日志的打印输出是必不可少的, 关于  有了日志之后,我们就可以追踪各种线上问题.但是,在分布式系统中,各种无关日志穿行其中,导致我们可能无法直接定位整个操作流程.因此 ...

  2. [转] Slf4j MDC机制

    MDC ( Mapped Diagnostic Contexts ),线程安全的诊断日志存放容器. 可用于存放线程的全局日志信息, 通过xml配置后可以打印在日志中,用于日志记录.定位.分析 相关:h ...

  3. slf4j中的MDC

    slf4j中MDC是什么鬼 slf4j除了trace.debug.info.warn.error这几个日志接口外,还可以配合MDC将数据写入日志.换句话说MDC也是用来记录日志的,但它的使用方式与使用 ...

  4. Slf4j的MDC初尝试

    为什么会用到MDC? 本人使用Java两年时间,鉴于经验有限,在开发java后端代码过程中,为了定位问题,希望同一个线程的requestId可以从web层的日志一直输出到dao层,这样使用Linux命 ...

  5. LogBack sl4j 通过MDC实现日志记录区分用户Session[以Spring mvc为例]

    1.首先实现一个interceptor,在请求开始的时候MDC put一个Session标志,interceptor结束的时候remove掉   import javax.servlet.http.H ...

  6. SLF4J user manual

    http://www.slf4j.org/manual.html The Simple Logging Facade for Java (SLF4J) serves as a simple facad ...

  7. SLF4J warning or error messages and their meanings(转)

    The method o.a.commons.logging.impl.SLF4FLogFactory#release was invoked. Given the structure of the ...

  8. logback输出json格式日志(包括mdc)发送到kafka

    1,pom.xml <!-- kafka --> <dependency> <groupId>com.github.danielwegener</groupI ...

  9. 日志收集(ElasticSearch)串联查询 MDC

    之前写过将应用程序或服务程序产生的日志直接写入搜索引擎的博客 其中基本过程就是  app->redis->logstash->elasticsearch 整个链路过程  本来想将re ...

随机推荐

  1. Linux下C语言编程基础学习记录

    VIM的基本使用  LINUX下C语言编程 用gcc命令编译运行C语言文件 预处理阶段:将*.c文件转化为*.i预处理过的C程序. 编译阶段:将*.i文件编译为汇编代码*.s文件. 汇编阶段:将*.s ...

  2. Linux内核实验作业七

    实验作业:Linux内核如何装载和启动一个可执行程序 20135313吴子怡.北京电子科技学院 [第一部分]理解编译链接的过程和ELF可执行文件格式 1.编译链接的过程 2.ELF可执行文件格式 一个 ...

  3. 对常用软件的评价(TGP腾讯游戏平台)

    1,首先说下界面,这款软件的界面有些类似于QQ的界面,登录方式和QQ的方式是一样的,可以简单的说是一款给游戏用的QQ,就是里面的用户变成了游戏 2,功能,简单的说就是将你常玩的游戏放于这游戏平台的表面 ...

  4. C#简述(二)

    详情请参考:http://www.runoob.com/csharp/csharp-operators.html 1.C# 运算符 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 ...

  5. formidable模块的使用

    Node.js的Formidable模块的使用   今天总结了下Node.js的Formidable模块的使用,下面做一些简要的说明. 1)     创建Formidable.IncomingForm ...

  6. 学习 TTreeView [1] - TTreeNodes、TTreeNode 与 Items、Items.Count、Items.Clear

    填写 TTreeView 的内容一般是这样开始的(下图), 不过我觉得最好习惯用动态建立. 打个比方: 譬如 TreeView 是一个军营的"营部"! 这里会有营长.连长.排长.班 ...

  7. Python 使用multiprocessingm模块创建多进程

    from multiprocessing import Process def run_proc(name): print("子进程Process %s(%s)运行..."%(na ...

  8. 在c语言中嵌入汇编语句,对于我来说相当难。

    今天早上在csdn论坛上看到一个帖子http://topic.csdn.net/u/20120917/14/82f42e17-977a-4824-95bd-7b79db15d283.html:“C语言 ...

  9. 《剑指offer》— JavaScript(25)复杂链表的复制

    复杂链表的复制 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数 ...

  10. android 系统开发板挂载U盘

    cat /proc/partitions 查看有u盘设备 df 查看挂载情况 iTOP4416开发板插入u盘,自动挂载到 /mnt/udisk1