最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

当前观察:logback的使用和原理

来源:博客园


(资料图片)

logback的使用和原理

1 依赖关系

在pom文件中引入springboot starter依赖,自动引入了这三个依赖,而这三个依赖,就是logback日志框架进行日志操作的。

                    org.springframework.boot            spring-boot-starter            

可以看到,logback-classic依赖于logback-core和slf4j-api。

2 执行流程

当我们在一个类中,使用 LoggerFactory.getLogger(xxx.class)获取一个类的 Logger对象时,发生了什么事是在什么时候加载的logback.xml文件中的配置的,这是本文要解决的问题

package org.example;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Date;import java.util.UUID;public class LogPathOnLinuxApp{    private static final Logger logger =  LoggerFactory.getLogger(LogPathOnLinuxApp.class);    public static void main(String[] args) {        logger.info(new Date().toString() + "生成了 UUID: " + UUID.randomUUID());    }}

单独的 T 代表一个类型 ,而 Class代表这个类型所对应的类, Class<?>表示类型不确定的类,Class<?extends A>表示类型不确定的类是A的子类

常见的调用方式,使用 LoggerFactory.getLogger(LogPathOnLinuxApp.class)获取 Logger对象,然后使用 logger.info()使用日志框架,输出日志信息。

首先,从 LoggerFactory.getLogger入手,他位于 org.slf4j包中

LoggerFactory类中,

// 1.1 使用时传入的class对象,调用的是这个方法public static Logger getLogger(Class clazz) {        // 1.2 调用上面的方法,传入一个String类型的class的名字,返回一个Logger对象,这个就是最终返回的Logger对象,ctrl+鼠标左键,点进去        Logger logger = getLogger(clazz.getName());        if (DETECT_LOGGER_NAME_MISMATCH) {            Class autoComputedCallingClass = Util.getCallingClass();            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");            }        }// 最终返回给调用者的logger        return logger;    }// 1.2 public static Logger getLogger(String name) {    // 1.3 调用getILoggerFactory方法,返回一个ILoggerFactory对象,点进去        ILoggerFactory iLoggerFactory = getILoggerFactory();    // 最终返回iLoggerFactory.getLogger(name)的Logger对象        return iLoggerFactory.getLogger(name);    }// 这是类中的静态变量,在类加载的时候初始化static final int UNINITIALIZED = 0; // 未初始化static final int ONGOING_INITIALIZATION = 1; // 正在初始化static final int FAILED_INITIALIZATION = 2; // 初始化失败static final int SUCCESSFUL_INITIALIZATION = 3; // 初始化成功static final int NOP_FALLBACK_INITIALIZATION = 4; // 无回退初始化static volatile int INITIALIZATION_STATE = 0; // 初始化状态// 1.3 public static ILoggerFactory getILoggerFactory() {    // 如果未初始化,就进行初始化操作        if (INITIALIZATION_STATE == 0) {            Class var0 = LoggerFactory.class;            // 对LoggerFactory类加锁            synchronized(LoggerFactory.class) {                // 如果未初始化,将状态设置为正在初始化,执行performInitialization()                if (INITIALIZATION_STATE == 0) {                    INITIALIZATION_STATE = 1;                    // 执行初始化                    performInitialization();                }            }        }// 判断初始化状态        switch (INITIALIZATION_STATE) {            case 1:                return SUBST_FACTORY;            case 2:                throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit");            // 如果初始化成功,返回 StaticLoggerBinder.getSingleton().getLoggerFactory();            case 3:                // 1.4 看这个方法 getLoggerFactory                return StaticLoggerBinder.getSingleton().getLoggerFactory();            case 4:                return NOP_FALLBACK_FACTORY;            default:                throw new IllegalStateException("Unreachable code");        }    }

StaticLoggerBinder类中,

private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder();private LoggerContext defaultLoggerContext = new LoggerContext();static {        SINGLETON.init();    }void init() {        try {            try {                // 自动配置,autoConfig 点进去                (new ContextInitializer(this.defaultLoggerContext)).autoConfig();            } catch (JoranException var2) {                Util.report("Failed to auto configure default logger context", var2);            }            if (!StatusUtil.contextHasStatusListener(this.defaultLoggerContext)) {                StatusPrinter.printInCaseOfErrorsOrWarnings(this.defaultLoggerContext);            }            this.contextSelectorBinder.init(this.defaultLoggerContext, KEY);            this.initialized = true;        } catch (Exception var3) {            Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", var3);        }    }

ContextInitializer类中,

// 此处的静态常量,表示的是logback的配置文件名public static final String AUTOCONFIG_FILE = "logback.xml";public static final String TEST_AUTOCONFIG_FILE = "logback-test.xml";public static final String CONFIG_FILE_PROPERTY = "logback.configurationFile";final LoggerContext loggerContext;// public void autoConfig() throws JoranException {        StatusListenerConfigHelper.installIfAsked(this.loggerContext);    // 没有任何配置文件时url为null        URL url = this.findURLOfDefaultConfigurationFile(true);        if (url != null) {            // 读取自定义的配置文件,logback.xml文件配置生效            this.configureByResource(url);        } else {            Configurator c = (Configurator)EnvUtil.loadFromServiceLoader(Configurator.class);            if (c != null) {                try {                    c.setContext(this.loggerContext);                    c.configure(this.loggerContext);                } catch (Exception var4) {                    throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass().getCanonicalName() : "null"), var4);                }            } else {                // 这一段代码保证了,没有任何配置文件时,也可以进行基础的自动配置,进行日志输出                BasicConfigurator basicConfigurator = new BasicConfigurator();                basicConfigurator.setContext(this.loggerContext);                basicConfigurator.configure(this.loggerContext);            }        }    }

3 日志滚动配置

需要注意在linux下执行的路径问题

                    ${LOG_PATH}/${PROJECT_NAME}/logs/LogsPathTest.log                                ${LOG_PATH}/${PROJECT_NAME}/logs/LogsPathTest.%d{yyyy-MM-dd}.%i.log.gz                        15                        2MB                            %date{yyyy-MM-dd HH:mm:ss}\t%level\t%logger{96}\t%msg%n                            INFO                                                %date{yyyy-MM-dd HH:mm:ss}\t%level\t%logger{96}\t%msg%n                            INFO                                    

关键词: