MDC是SLF4J中的一个类,通过MDC我们可以很方便的实现同一个线程内(包括父线程和子线程之间)的日志的追踪,对于一个请求能够很容易的根据
traceId
这样的值很快的找到该线程包括子线程所经历的全部的日志,轻松的把程序中的逻辑串联起来,通过一个例子来说明。
MDC使用
MDC使用
引入相关依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
同时需要在logback.xml中添加对应的appender的pattern,主要是这个
[traceId = %X{traceId}]
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd hh:mm:ss} [%thread] [traceId = %X{traceId}] [%logger{32}] - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
</root>
</configuration>
在一个线程中的使用,代码如下:
@ProviderAnnotation(value = "sync")
public String sync(DTO dto) {
MDC.put("traceId", dto.getTraceId);
LogConstant.ACC_LOG.info("begin");
return "hello";
主要的代码是
MDC.put("traceId", dto.getTraceId);
需要注意的是和使用ThreadLocal一样,一定要记得clear,事实上这玩意的底层就是ThreadLocal,只是slf4j自己封装了而已,我此处的在aop中统一进行的clear操作。
finally {
MDC.clear();
[pool-12-thread-2] [traceId = aaa] .......
使用上面的方法发现在我主线程中开启异步的线程或者使用线程池时没有将该traceId打印出来,我们需要相关的代码做如下调整:
ExecutorService executor = Executors.newSingleThreadExecutor();
Map<String, String> context = MDC.getCopyOfContextMap();
executor.execute(()->{
MDC.setContextMap(context);
LogConstant.ACC_LOG.info("xxx ");
} finally {
MDC.clear();
关键代码是:
Map<String, String> context = MDC.getCopyOfContextMap();
这个一定要在run之前先获取一下,否则可能导致下面取不到值。
MDC.setContextMap(context);
同时别忘记clear的操作,打印效果和上面一致。
slf4j 打印traceID介绍
slf4j除了trace、debug、info、warn、error这几个日志接口外,还可以配合日志分析将数据写入日志。
在使用日志接口时我们一般这么做
Logger LOG = LoggerFactory.getLogger("LOGNAME_OR_CLASS");
if(LOG.isDebugEnabled()) {
LOG.debug("log debug");
那么 如果我们想在日志文件中打印自定义信息该怎么办呢?比如打印以下信息:
我们想在日志
SLF4J的全称是Simple Logging Facade for Java,即简单日志门面。
SLF4J并不是具体的日志框架,而是作为一个简单门面服务于各类日志框架,如java.util.logging, logback和log4j。
SLF4J支持{}作为占位符,等价于C语言中的%s,而不必再进行字符串的拼接,效率有显著的提。
1.slf4j使用
引入包 slf4j-api-1.6....
一.slf4j中MDC是什么
slf4j除了trace、debug、info、warn、error这几个日志接口外,还可以配合MDC将数据写入日志。换句话说MDC也是用来记录日志的,但它的使用方式与使用日志接口不同。
在使用日志接口时我们一般这么做
Logger LOG = LoggerFactory.getLogger("LOGNAME_OR_CLASS");
if(LOG....
最近遇到一个问题,使用slf4j和log4j2日志框架时,需要将请求的id放入到打印日志中。因为MDC和ThreadContext是跟线程绑定的,所以遇到了子线程无法读取父线程MDC和ThreadContext的问题,网上搜了很多,有各种各样的答案,折腾了一天,总算搞定了,今天花点时间把答案总结梳理一下,希望大家能少走弯路。
问题现象:在父线程中使用了MDC.put("key","value")或者ThreadContext.put("key","value"),在子线程中使用MDC.get("key")
slf4j MDC是个好东西
MDC 全拼 Mapped Diagnostic Contexts,是SLF4J类日志系统中实现分布式多线程日志数据传递的重要工具。
同时,用户也可利用MDC将一些运行时的上下文数据打印出来。
什么意思呢?
常规情况下,写打日志的代码时,一般都是log.info、log.warn、log.error将想要打的日志进行拼装和格式化,打到日志输出中。MDC能干什么呢?能在不改动log.xxx打日志代码的情况下,在最终的日志输出的指定位置打印额外的信息。而这,就是靠MDC进行
MDC 简介
MDC (org.slf4j.MDC)( Mapped Diagnostic Contexts ),它是一个线程安全的存放诊断日志的容器。SLF4J的MDC实质上就是一个Map。通常实现SLF4J的日志系统支持MDC,即表明该日志系统负责维护这个Map。应用就可以依赖于日志系统,直接存取key/value对到该Map中。
2. 源码关键分析
2.1 org.slf4j.MDC
2.2 org.sl.
什么是MDC机制
MDC(Mapped Diagnostic Contexts)映射诊断上下文,主要用在做日志链路跟踪时,动态配置用户自定义的一些信息,比如requestId、sessionId等等。MDC使用的容器支持多线程操作,满足线程安全。
MDC的使用
pom.xml依赖
<!-- 日志log4j2 -->
<dependency>
<groupI...
MDC(Mapped Diagnostic Context)诊断上下文映射,是slf4j提供的一个支持动态打印日志信息的工具,举例来说,对于一个web Server,如果服务端想在打印出的每行日志中都记录客户端的ip,你只需要在服务端入口获取到cleint ip,设置到MDC中,服务请求结束时,移除掉。如果日志配置文件配置得当,这一过程中所有打印的日志信息中都会显示clientIp。
slf4j介绍MDC
logback中的MDC
见logback中的MDC一文即可,比较简单。
在大型分布式系统中
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相
使用 SkyWalking traceid 进行链路追踪;
使用 Elastic APM 的 trace.id 进行链路追踪;
自己生成 traceId并put 到 MDC 里面。
MDC(Mapp...
您可以使用log4j或者logback框架来实现按日期生成日志文件的功能。下面是使用logback框架的示例代码:
1. 首先,在pom.xml中添加logback依赖:
```xml
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
2. 在logback.xml中配置按日期生成日志文件:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/path/to/logs/mylog.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>/path/to/logs/mylog-%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="FILE" />
</root>
</configuration>
这里的`fileNamePattern`指定了生成的日志文件名格式为`mylog-yyyy-MM-dd.log`,并且保留最近30天的日志文件。`encoder`中的`pattern`指定了日志输出的格式。
3. 使用Logger输出日志:
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
public void myMethod() {
logger.info("This is a log message");
这样就可以在`/path/to/logs`目录下按日期生成日志文件了。