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方法设置

时间: 2024-08-24 15:14:50

Logback的配置文件查找顺序的相关文章

1.模块2.循环导入问题及解决思路3.区分py文件的两种类型4.模块的查找顺序5.模块的绝对导入与相对导入6.项目开发的目录规范

一.模块 什么是模块? 模块就是一系列功能的结合体 模块的三种来源: 1.内置的(python解释器自带的) 2.第三方的(别人写的) 3.自定义的(你自己写的) 模块的四种表现形式: 1.使用python编写的py文件(也就是意味着py文件也是可以称之为模块 2.已被编译为共享库或DLL的或C++扩展(了解) 3.把一系列模块组织到一起的文件夹(文件夹下有一个__init__.py文件,该文件夹称之为包) 4.使用C编写并连接到Python解释器的内置模块 模块选择 1.用别人写好的模块(内置

Yii 2—— layout查找顺序

1.1  layout查找顺序 在应用中添加了一个模块,但是还没有给模块添加layouts,结果发现页面还是可以正常显示,只是layout用的是应用级的layout,有点好奇,于是跟了下代码,在yii2\base\Controller.php的findLayoutFile()看到有如下代码: public function findLayoutFile($view)  {      $module = $this->module;      if (is_string($this->layou

Windows下DLL查找顺序

Windows下DLL查找顺序 作者:Tocy    时间:2014-10-18 一.写作初衷 在Windows下单个DLL可能存在多个不同的版本,若不特别指定DLL的绝对路径或使用其他手段指定,在应用程序加载DLL时可能会查找到错误的版本,进而引出各种莫名其妙的问题.本文主要考虑以下两个方面: a. 参考MSDN,给出Windows下DLL查找顺序 b. 简单使用ProcessMonitor来验证DLL查找顺序 二.DLL查找顺序 (本部分多数内容是参考MSDN上的Dynamic-Link L

python 函数变量查找顺序

python 函数变量的查找顺序:优先级为: 局部---> 全局---> 如果仍没找到,将引发NameError错误. #!/usr/bin/env python #coding:utf-8 #@Author:Andy # Date: 2017/6/14 money = 1000 def tell_info(name): print("%s have %d " % (name, money)) def fun(): money = 10 tell_info('egon')

MySQL读取配置文件的顺序、启动方式、启动原理

一.MySQL读取配置文件的顺序 读取顺序:/etc/my.cnf > /etc/mysql/my.cnf > /usr/etc/my.cnf > ~/.my.cnf 命令验证:[[email protected] ~]# mysql --verbose --help | grep my.cnf order of preference, my.cnf, $MYSQL_TCP_PORT,/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.

变量在原型链中的查找顺序

js原型链 下面是一道js题目: [javascript] view plain copy function C1(name){ if(name){ this.name = name; } } function C2(name){ this.name = name; } function C3(name){ this.name = name || "John"; } C1.prototype.name = "Tom"; C2.prototype.name = &qu

【Log】logback指定配置文件(二)

摘自:https://www.cnblogs.com/h--d/p/5671528.html [Log]logback指定配置文件(二) 通常我们在不同的环境使用不同的日志配置文件,本章讲指定logback的配置文件,如何使用logback参照[Log]logback的配置和使用(一) 写一个配置加载类,注意JoranConfigurator这个导入的是ch.qos.logback.classic.joran.JoranConfigurator包下面的 1 package com.test; 2

从源码来理解slf4j的绑定,以及logback对配置文件的加载

https://www.cnblogs.com/youzhibing/p/6849843.html 编译期间,完成slf4j的绑定已经logback配置文件的加载.slf4j会在classpath中寻找org/slf4j/impl/StaticLoggerBinder.class(会在具体的日志框架如log4j.logback等中存在),找到并完成绑定:同时,logback也会在classpath中寻找配置文件,先找logback.configurationFile.没有则找logback.gr

模块导入、循环导入、模块查找顺序、相对导入及绝对导入

模块导入 什么是模块 模块:就是一系列功能的结合体 模块的三种来源: 1.内置的(python解释器自带) 2.第三方的(别人写的) 3.自定义的(自己写的) 模块的四种表现形式 1.使用python编写的py文件(也就意味着py文件也可以称之为模块:一个py文件也可以称之为一个模块) 2.已被编译为共享库或DLL的C或C++扩展(了解) 3.把一系列模块组织到一起的文件夹(文件夹下有一个__init__.py文件,该文件夹称之为包) 包:一系列py文件的结合体 4.使用C编写并连接到pytho