logback的使用和原理(代码片段)

永恒& 永恒&     2023-03-26     782

关键词:

logback的使用和原理

1 依赖关系

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>


可以看到,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<T>代表这个类型所对应的类, 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下执行的路径问题

<configuration>
    
	<!--    加入监听器,可以在监听器中设置 $LOG_PATH和$PROJECT_NAME 的值,从而实现指定日志输出路径的效果 -->
    <!-- 也可以使用 $user.dir:-./logs/xxxx.log, user.dir 表示执行运行jar包命令时所在的路径 -->
	<contextListener class="org.example.com.smy.CustomLogContextListener" />
    <appender name="dailyRollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>$LOG_PATH/$PROJECT_NAME/logs/LogsPathTest.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名,.gz 表示开启文件压缩-->
            <FileNamePattern>$LOG_PATH/$PROJECT_NAME/logs/LogsPathTest.%dyyyy-MM-dd.%i.log.gz</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>15</MaxHistory>
            <!--日志文件最大的大小-->
            <MaxFileSize>2MB</MaxFileSize>
        </rollingPolicy>
        <encoder>
            <Pattern>%dateyyyy-MM-dd HH:mm:ss\\t%level\\t%logger96\\t%msg%n</Pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>


    <!-- Console output -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <Pattern>%dateyyyy-MM-dd HH:mm:ss\\t%level\\t%logger96\\t%msg%n</Pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <root level="INFO">
        <appender-ref ref="dailyRollingFileAppender"/>
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

利用springboot+logback手写一个简单的链路追踪(代码片段)

...一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简单的链路追踪,下面详细介绍下。一、实现原理SpringBoot默认使用LogBack日志系统,并且已经引入了相关的jar包,所以我们无需任何配置便可以使用LogBack打... 查看详情

logback的使用和logback.xml详解,在spring项目中使用log打印日志(代码片段)

logback的使用和logback.xml详解一、logback的介绍  Logback是由log4j创始人设计的另一个开源日志组件,官方网站:http://logback.qos.ch。它当前分为下面下个模块:  logback-core:其它两个模块的基础模块  logback-classic:它是log4j的一... 查看详情

源码详解系列------全面讲解logback的使用和源码(代码片段)

什么是logbacklogback用于日志记录,可以将日志输出到控制台、文件、数据库和邮件等,相比其它所有的日志系统,logback更快并且更小,包含了许多独特并且有用的特性。logback被分成三个不同的模块:logback-core,logback-classic,logba... 查看详情

logback日志框架的简单使用(代码片段)

最近在自己搭建项目的时候,遇到logback选的问题,现在记录如下在框架中使用logback日志框架,关于logback和log4j日志框架的选择,这里就不多说了网上百度一大堆,总之一句话logback要比log4j效率高,性能好,配置灵活。1.首先在ma... 查看详情

logback的使用和logback.xml详解(代码片段)

一、logback的介绍Logback是由log4j创始人设计的另一个开源日志组件,官方网站:http://logback.qos.ch。它当前分为下面下个模块:logback-core:其它两个模块的基础模块logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4jAPI使你... 查看详情

日志框架之logback的使用与详细配置(代码片段)

(日志框架之Logback的使用与详细配置)Logback概述Logback特点:高性能:采用异步日志机制,可以将日志操作和业务逻辑分离,从而大幅度提升系统的性能。灵活的配置:支持多种不同的配置方式,包括基于XML、Groovy、JSON等格式的配... 查看详情

springbootlogback日志组件使用(代码片段)

一logback简介    Logback是一个开源日志组件。Logback一般和SLF4结合起来使用。外层使用SLF4J,里面的实现是logback。什么意思,简单来说我们使用层看到的是SLF4J。我们使用的时候就是和SLF4J提供的一些api打交道。    我们可能... 查看详情

slfj4+logback(代码片段)

...再代码中或配置文件中指定使用的那个具体的日志系统。logback:是由log4j创始人设计的一个开源日志组件。logback当前分成三个模块:logback-core,logback-classic和logback-access。l 查看详情

springboot整合logback集成elk实现日志的汇总分析统计和检索功能(代码片段)

  在SpringBoot当中,默认使用logback进行log操作。logback支持将日志数据通过提供IP地址、端口号,以Socket的方式远程发送。在SpringBoot中,通常使用logback-spring.xml来进行logback配置。首先、创建一个elk的springboot项目,然后先对logback... 查看详情

logback中%x的使用(代码片段)

1.参考资料https://gist.github.com/logogin/ff44c254f655340b653chttp://www.cnblogs.com/zhudongchang/p/6861375.html2.环境Java:jdk1.8.0_144Logback:1.0.133.%X的使用方法%X用于输出和当前线程相关联的NDC(嵌套诊断环境),在代码中给org.slf4j.MDC添加k 查看详情

slf4j和logback(代码片段)

问题:由于项目需要,今天弄了很久,SLF4J和Logback 一、SLF4J和Logback和CommonsLogging和Log4j的区别以及在普通的java项目中使用:SLF4J和CommonsLogging类似,充当日志API,Logback和Log4j类似,充当其实现类,为什么有了CommonsLogging和Log4j,又... 查看详情

slf4j作用及其实现原理(代码片段)

为什么要使用slf4j现实场景:我们自己的系统中使用了logback这个日志系统我们的系统使用了A.jar,A.jar中使用的日志系统为log4j我们的系统又使用了B.jar,B.jar中使用的日志系统为slf4j-simple这样,我们的系统就不得不同时支持并维... 查看详情

为web项目添加logback(代码片段)

...中,难免要涉及到日志查看和打印,所以学习了logback的使用和配置方法,在这里记录下,和大家分享1.jar包上面的两个包是必须要使用的,注意不要重复加载了,不然会找不到这个包,导致加载失败2.... 查看详情

使用logstash结合logback收集微服务日志(代码片段)

...out中,那以后只要输出这个文件则可查看所有的日志结合logback和logstash收集日志1.为需要收集日志的微服务引入logstash-logback-encode依赖//用logstash收集logbackcompile‘net.lo 查看详情

logback的简单使用(代码片段)

logback的使用logback是由log4j的创始人设计的另一个开源日志组件,性能比log4j好LogBack主要分为三个模块:logback-core:其他两个模块的基础模块logback-class:它是log4j的改良版本,完整实现了Slf4jAPIlogback-access:访问模块与... 查看详情

loglogback指定配置文件(代码片段)

  摘自:https://www.cnblogs.com/h--d/p/5671528.html【Log】logback指定配置文件(二)通常我们在不同的环境使用不同的日志配置文件,本章讲指定logback的配置文件,如何使用logback参照【Log】logback的配置和使用(一)写一个配置加... 查看详情

logback的简单使用(代码片段)

logback的使用logback是由log4j的创始人设计的另一个开源日志组件,性能比log4j好LogBack主要分为三个模块:logback-core:其他两个模块的基础模块logback-class:它是log4j的改良版本,完整实现了Slf4jAPIlogback-access:访问模块与... 查看详情

slf4j+logback实现日志输出和记录(代码片段)

一、SLF4J   SLF4J,即简单日志门面(SimpleLoggingFacadeforJava),不是具体的日志解决方案,它只服务于各种各样的日志系统。在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。   使用... 查看详情