Logback的配置文件查找顺序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Logback的配置文件查找顺序相关的知识,希望对你有一定的参考价值。

问题

使用slf4j和logback记录日志,有这样一个需求,如果指定了一个特定logback.xml,就用指定的配置,如果没有,则系统提供一个默认的配置。


解决

classpath下放一个配置文件logback.xml,使用环境变量logback.configurationFile指定另一个配置。logback会首先使用环境变量指定的文件,如果没有指定或文件不存在,logback会使用classpath下的文件。


原理 - logback配置文件查找过程

1. 使用如下代码获取日志器

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Logger logger = LoggerFactory.getLogger(LogTest.class);

2. slf4j首先会判断有没有初始化过

org.slf4j.LoggerFactory
    public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        ...
        return logger;
    }
    
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }
    
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    performInitialization();
                }
            }
        }
        ...
    }

3. 如果没有初始化过,则执行初始化,初始化的过程是加载org.slf4j.impl.StaticLoggerBinder类

    private final static void performInitialization() {
        bind();
        ...
    }
    
    private final static void bind() {
        ...
        staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
        ...
    }
    
    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
        
    static Set<URL> findPossibleStaticLoggerBinderPathSet() {
        // use Set instead of list in order to deal with bug #138
        // LinkedHashSet appropriate here because it preserves insertion order during iteration
        Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
        try {
            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
            Enumeration<URL> paths;
            if (loggerFactoryClassLoader == null) {
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            } else {
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            }
            while (paths.hasMoreElements()) {
                URL path = paths.nextElement();
                staticLoggerBinderPathSet.add(path);
            }
        } catch (IOException ioe) {
            Util.report("Error getting resources from path", ioe);
        }
        return staticLoggerBinderPathSet;
    }

4. 加载StaticLoggerBinder类的初始化过程

org.slf4j.impl.StaticLoggerBinder
    static {
        SINGLETON.init();
    }
    
    void init() {
        new ContextInitializer(defaultLoggerContext).autoConfig();    
    }
ch.qos.logback.classic.util.ContextInitializer
        final public static String GROOVY_AUTOCONFIG_FILE = "logback.groovy";
    final public static String AUTOCONFIG_FILE = "logback.xml";
    final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml";
    final public static String CONFIG_FILE_PROPERTY = "logback.configurationFile";
    
    public void autoConfig() throws JoranException {
        URL url = findURLOfDefaultConfigurationFile(true);
        if (url != null) {
            configureByResource(url);
        } else {
            Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);
            if (c != null) {
                try {
                    c.setContext(loggerContext);
                    c.configure(loggerContext);
                } catch (Exception e) {
                    throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass()
                                    .getCanonicalName() : "null"), e);
                }
            } else {
                BasicConfigurator basicConfigurator = new BasicConfigurator();
                basicConfigurator.setContext(loggerContext);
                basicConfigurator.configure(loggerContext);
            }
        }
    }
    
    public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }

        url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }

        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }

        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
    }
    
    private URL findConfigFileURLFromSystemProperties(ClassLoader classLoader, boolean updateStatus) {
        String logbackConfigFile = OptionHelper.getSystemProperty(CONFIG_FILE_PROPERTY);
        ...
    }

可见,logback加载的过程是

(1)使用logback.configurationFile环境变量的设置

(2)使用classpath中的logback.groovy

(3)使用classpath中的logback-test.xml

(4)使用classpath中的logback.xml

(5)查找com.qos.logback.classic.spi.Configurator接口实现类,调用实现类的configure方法设置

(6)使用BasicConfigurator类的configure方法设置

本文出自 “自强不息,厚德载物” 博客,请务必保留此出处http://wangzhichao.blog.51cto.com/2643325/1751748

以上是关于Logback的配置文件查找顺序的主要内容,如果未能解决你的问题,请参考以下文章

关于logback如何通过当前配置文件获取路径

logback 文件包含取决于内容的顺序

Logback日志系统

logback的加载过程

logback配置文件详解

Springboot项目使用Logback把日志输出到控制台或输出到文件