slf4j MDC使用

slf4j MDC使用

最近也是在項目代碼裏發現一個地方有個MDC.put(),忍不住好奇點了進去,因而知道了MDC這個東西,細研究一下,發現還真是個好東西。html

MDC解決了什麼問題

MDC全名Mapped Diagnostic Contexts,是slf4j提供的一個API,主要功能就是在多線程環境下進行日誌調用鏈路的跟蹤,好比在一次事務處理中,會通過多個處理的流程,爲了定位問題方便,在每一個流程中免不了打印一些日誌信息。在線上環境中,最後打出來的日誌是不少的,如何定位哪些信息是在同一個線程中打印的呢?MDC很優雅地解決了這個問題。其餘的日誌框架有沒有這個功能我暫時沒去研究,對於slf4j(如今應該都會優先用這個吧?),實現了MDC的有logback和log4j,這裏暫時以logback爲例,更詳細的文檔見這裏java

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。如今咱們模擬多個線程同時處理事務。定義了一次事務處理的流程。app

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就把整個處理流程中的日誌信息串聯起來了)。dom

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,事實也如此,有興趣繼續研究代碼我就很少說了。線程

相關文章
相關標籤/搜索