Logback中的MDC

来源:互联网 发布:淘宝代写作业 编辑:程序博客网 时间:2024/06/06 02:32

Logback学习交流群:603634815。


Logback是一个日志框架。

其中有一项功能很好使-MDC,映射诊断环境(Mapped Diagnostic Context)。

MDC本质上是使用的ThreadLocal。系统调用链可能很长,为了方便日志跟踪,统一打印标识。

以下是一个官方入门例子:

/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2015, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * *   or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */package chapters.mdc;import java.io.File;import java.net.MalformedURLException;import java.net.URL;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.slf4j.MDC;import ch.qos.logback.classic.LoggerContext;import ch.qos.logback.classic.encoder.PatternLayoutEncoder;import ch.qos.logback.classic.joran.JoranConfigurator;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.ConsoleAppender;import ch.qos.logback.core.joran.spi.JoranException;import ch.qos.logback.core.util.Loader;import ch.qos.logback.core.util.StatusPrinter;public class SimpleMDC {    static public void main(String[] args) throws Exception {        // You can put values in the MDC at any time. Before anything else        // we put the first name        MDC.put("first", "Dorothy");        // configure via the configuration file "chapters/mdc/simpleMDC.xml"        // which ships with the examples        //configureViaXML_File();        // For educational purposes, the same configuration can        // be accomplished programmatically.        //        programmaticConfiguration();        Logger logger = LoggerFactory.getLogger(SimpleMDC.class);        // We now put the last name        MDC.put("last", "Parker");        // The most beautiful two words in the English language according        // to Dorothy Parker:        logger.info("Check enclosed.");        logger.debug("The most beautiful two words in English.");        MDC.put("first", "Richard");        MDC.put("last", "Nixon");        logger.info("I am not a crook.");        logger.info("Attributed to the former US president. 17 Nov 1973.");    }    static void programmaticConfiguration() {        // Configure logback        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();        loggerContext.reset();        PatternLayoutEncoder layout = new PatternLayoutEncoder();        layout.setContext(loggerContext);        layout.setPattern("%X{first} %X{last} - %m%n");        layout.start();        ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<ILoggingEvent>();        appender.setContext(loggerContext);        appender.setEncoder(layout);        appender.start();        // cast root logger to c.q.logback.classic.Logger so that we can attach        // an appender to it        ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("root");        root.addAppender(appender);    }    static void configureViaXML_File() {        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();        try {            JoranConfigurator configurator = new JoranConfigurator();            configurator.setContext(lc);            lc.reset();            URL url = Loader.getResourceBySelfClassLoader("chapters/mdc/simpleMDC.xml");            try {                url = url==null?new File("src/main/java/chapters/mdc/simpleMDC.xml").toURI().toURL():url;            } catch (MalformedURLException e) {                e.printStackTrace();            }            configurator.doConfigure(url);        } catch (JoranException je) {            StatusPrinter.print(lc);        }    }}
MDC.put(String, String); 是将变量内容存到线程内部。看他的内部实现

    public static void put(String key, String val) throws IllegalArgumentException {        if (key == null) {            throw new IllegalArgumentException("key parameter cannot be null");        }        if (mdcAdapter == null) {            throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);        }        mdcAdapter.put(key, val);    }
是通过mdcAdapter存放的,类型org.slf4j.spi.MDCAdapter,是slf4j提供的一个统一接口。
它是通过一个静态块进行初始化的:

private static MDCAdapter bwCompatibleGetMDCAdapterFromBinder() throws NoClassDefFoundError {        try {            return StaticMDCBinder.getSingleton().getMDCA();        } catch (NoSuchMethodError nsme) {            // binding is probably a version of SLF4J older than 1.7.14            return StaticMDCBinder.SINGLETON.getMDCA();        }    }    static {        try {            mdcAdapter = bwCompatibleGetMDCAdapterFromBinder();        } catch (NoClassDefFoundError ncde) {            mdcAdapter = new NOPMDCAdapter();            String msg = ncde.getMessage();            if (msg != null && msg.contains("StaticMDCBinder")) {                Util.report("Failed to load class \"org.slf4j.impl.StaticMDCBinder\".");                Util.report("Defaulting to no-operation MDCAdapter implementation.");                Util.report("See " + NO_STATIC_MDC_BINDER_URL + " for further details.");            } else {                throw ncde;            }        } catch (Exception e) {            // we should never get here            Util.report("MDC binding unsuccessful.", e);        }    }
StaticMDCBinder是org.slf4j.impl.StaticMDCBinder,在logback-classic包里面。但是这段代码是在slf4j-api中的,所以,只要使用slf4j作为统一日志门面的日志框架在使用MDC功能时一定要在自己的jar包里面创建org.slf4j.impl.StaticMDCBinder,包名、类名不能错。

org.slf4j.impl.StaticMDCBinder里面 getMDCA()方法,直接返回的是new LogbackMDCAdapter();

ch.qos.logback.classic.util.LogbackMDCAdapter实现org.slf4j.spi.MDCAdapter,声明ThreadLocal:

final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal<Map<String, String>>();

进行get、set方法。

因为程序里面配置了pattern属性

layout.setPattern("%X{first} %X{last} - %m%n");
所以在日志打印的时候会从MDC中取出first和last进行打印。

如果是以下配置文件,也能起到同样作用:

<?xml version="1.0" encoding="UTF-8" ?><configuration><appender name="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><Pattern>%X{first} %X{last} - %m%n</Pattern></layout></appender><root level="debug"><appender-ref ref="CONSOLE" /></root></configuration>



未完待续:MDC取值过程。



原创粉丝点击