一、什么是日志?

在生活上,日志是一种日记,用于记录我们生活的一点一滴,我们可以通过日志回忆美好,平淡抑或是痛苦的过往。对于我们的程序来说日志就是记录
某个时刻应用执行的信息,错误等。

在没有比较成熟,好用的日志框架出现之前,我们程序员该这么打印日志呢?一千个哈姆莱特有一千个实现,没有统一的标准,每个公司都是闭门造车,
A公司造的车子是两个轮子的,B公司的是四个轮子,C公司不仅能在地上跑还能在天上飞,所以这三家公司的日志框架只能给自家用,无法开源给
其他公司使用,每个公司可能都要根据自己的情况造自己的车。

那么现在比较成熟,集大家之成,通用的框架实现有哪些呢?
我们比较熟悉的有log4j,logback等,log4j和logback的作者都是Ceki Gülcü,也在此基础上抽象出了 slf4j api,全称为 The Simple Logging Facade for Java,用来定义日志门面,logback 是在log4j与slf4j基础上优化而来,所以logback的性能要优于log4j,所以本博文将研究logback的源码实现

二、既然有那么多的日志实现,那如果我同时引入了log4j和logback等多个框架,将会使用哪个呢?

启动项目的时候会打印警告信息,信息如下:
SLF4J: Class path contains multiple SLF4J bindings.

那么这个信息是怎么打出来的呢?

// 获取日志上下文,内部会自动绑定当前存在的日志实现
org.slf4j.ILoggerFactory loggerContext = org.slf4j.LoggerFactory.getILoggerFactory();

上面这个方法会自定绑定日志实现,在绑定之前会判断当前系统中存在的实现是否有多个,如果有多个那么将会提示警告信息,具体代码
如下:


static Set<URL> org.slf4j.LoggerFactory.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) {
                // STATIC_LOGGER_BINDER_PATH =》org/slf4j/impl/StaticLoggerBinder.class
                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;
    }

上面这段代码会检查类路径下有多少个 org/slf4j/impl/StaticLoggerBinder.class,如果出现多个那么将会警告多个实现的日志,那么问题
来了,既然只是警告没有抛出错误,那么它到底最后使用的是哪个日志实现呢?这个主要看系统加载文件的顺序了,在不同的系统上它的加载
顺序可能不相同,比如我在mac电脑上启动能正常打印日志,但是在linux上却不能,所以最后一个系统里就只留一个日志实现,不要出现多个。