`
kanpiaoxue
  • 浏览: 1755534 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Mapped Diagnostic Context (MDC)

 
阅读更多

 

Mapped Diagnostic Context (MDC)

针对 MDC功能,目前只有logback 以及 log4j 支持。

相关文章:

  • https://www.baeldung.com/mdc-in-log4j-2-logback
  • http://logback.qos.ch/manual/mdc.html
  • https://www.jianshu.com/p/3fa7e7726fbb
  • https://ketao1989.github.io/2015/04/29/LogBack-Implemention-And-Slf4j-Mdc/

 

 

Let's now use the SLF4J's flavor of MDC. In this case, the syntax and semantics are the same as that in log4j:

import org.slf4j.MDC;

public class Slf4jRunnable implements Runnable {
    private final Transaction tx;
    
    public Slf4jRunnable(Transaction tx) {
        this.tx = tx;
    }
    
    public void run() {
        MDC.put("transaction.id", tx.getTransactionId());
        MDC.put("transaction.owner", tx.getOwner());
        new Slf4TransferService().transfer(tx.getAmount());
        MDC.clear();
    }
}

We have to provide the Logback configuration file, logback.xml:

 
<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%-4r [%t] %5p %c{1} - %m - tx.id=%X{transaction.id} tx.owner=%X{transaction.owner}%n</pattern>
	</encoder>
    </appender>
    <root level="TRACE">
        <appender-ref ref="stdout" />
    </root>
</configuration>

Again, we'll see that the information in the MDC is properly added to the logged messages, even though this information is not explicitly provided in the log.info() method:

1020 [pool-1-thread-3]  INFO c.b.m.s.Slf4jBusinessService 
  - Has transfer of 1869$ completed successfully ? true. - tx.id=3 tx.owner=John
1021 [pool-1-thread-3]  INFO c.b.m.s.Slf4jBusinessService 
  - Preparing to transfer 1303$. - tx.id=6 tx.owner=Samantha
1221 [pool-1-thread-1]  INFO c.b.m.s.Slf4jBusinessService 
  - Has transfer of 1498$ completed successfully ? true. - tx.id=4 tx.owner=Marc
1221 [pool-1-thread-1]  INFO c.b.m.s.Slf4jBusinessService 
  - Preparing to transfer 1528$. - tx.id=7 tx.owner=Samantha
1492 [pool-1-thread-2]  INFO c.b.m.s.Slf4jBusinessService 
  - Has transfer of 1110$ completed successfully ? true. - tx.id=5 tx.owner=Samantha
1493 [pool-1-thread-2]  INFO c.b.m.s.Slf4jBusinessService 
  - Preparing to transfer 644$. - tx.id=8 tx.owner=John

 

 

 

 

不合理使用MDC的危害

MDC and Thread Pools

MDC implementations are usually using ThreadLocals to store the contextual information. That's an easy and reasonable way to achieve thread-safety. However, we should be careful using MDC with thread pools.

 

Let's see how the combination of ThreadLocal-based MDCs and thread pools can be dangerous:

 

  1. We get a thread from the thread pool.
  2. Then we store some contextual information in MDC using MDC.put() or ThreadContext.put().
  3. We use this information in some logs and somehow we forgot to clear the MDC context.
  4. The borrowed thread comes back to the thread pool.
  5. After a while, the application gets the same thread from the pool.
  6. Since we didn't clean up the MDC last time, this thread still owns some data from the previous execution.

This may cause some unexpected inconsistencies between executions. One way to prevent this is to always remember to clean up the MDC context at the end of each execution. This approach usually needs rigorous human supervision and, therefore, is error-prone.

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics