Logback的基本使用

· 2717字 · 6分钟

1. Logback是什么 🔗

Logback的官方文档中指出,Logback是Log4j项目的继任者,是一个工业级的日志系统。Logback构建在SLF4J之上,因此我们使用Logback时也依赖于SLF4J。

Logback主要包含三个模块:logback-corelogback-classiclogback-access,参见Logback架构,其中logback-core定义了Appender和Layout接口和核心配置机制,logback-classic则是logback-core的实现,提供了另外一个核心的Logger类,其实现了SLF4J,如下图所示。

image-20240717004255142

2. Logback的安装与配置 🔗

2.1 引入依赖 🔗

参考官方文档的安装页面,如果采用官方提供的logback-classic作为实现的话,我们仅仅需要引入logback-classic坐标就可以,logback-core以及slf4j-api都已经被包含了。

<dependencies>                                     
    <!--Logback的具体实现,负责Logback-core实现与SLF4J接口的继承-->
    <dependency>                                   
        <groupId>ch.qos.logback</groupId>          
        <artifactId>logback-classic</artifactId>   
        <version>1.5.6</version>                   
    </dependency>                                  
</dependencies>                                    

1.2 配置Logback 🔗

Logback的配置可以参阅官方文档,其实官方文档已经写得很清楚了,在这里我写下来仅作笔记加深理解。我们可以看到Logback的配置机制还是比较复杂的,主要分为四个阶段。

  1. Logback提供了一个名为Configurator的配置器接口,首先Logback会找是否存在自定义的Configurator实现类,如果存在的话则使用自定义的实现类,否则执行后续的阶段。
  2. 1.3.9/1.4.9版本后,Logback会在没有找到配置类时实例化一个SerializedModelConfigurator,它会读取系统属性、logback-test.scmologback.scmo,如果没有一个能够被找到的话,执行后面的阶段。
  3. Logback会在前面的步骤都无法完成时,初始化一个DefaultJoranConfigurator实例,这个默认的配置器实现类会处理Logback的配置,这也是Logback的最常用的配置方式。DefaultJoranConfigurator首先会读取logback.configurationFile系统属性,如果读取到系统属性且该属性对应的文件能够被读取的话,就采用该文件的配置。否则,它会在class path下按优先顺序搜索logback-test.xmllogback.xml,使用里面的配置。
  4. 如果前面的三个阶段都无法读取到配置,那么Logback会初始化一个BasicConfigurator实例,这个默认的配置器实现类会直接把日志输出到终端。

1.2.1 默认的自动配置 🔗

如果我们什么配置器类和配置文件都不写,显然Logback配置会执行到第四阶段,这个阶段会用BasicConfigurator实现类加载配置,其实现如下。

public class BasicConfigurator extends ContextAwareBase implements Configurator {
    public BasicConfigurator() {
    }

    public Configurator.ExecutionStatus configure(LoggerContext loggerContext) {
        this.addInfo("Setting up default configuration.");
        // Appender为ConsoleAppender,即日志写入到控制台
        ConsoleAppender<ILoggingEvent> ca = new ConsoleAppender();
        ca.setContext(this.context);
        ca.setName("console");
        LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder();
        encoder.setContext(this.context);
        TTLLLayout layout = new TTLLLayout();
        layout.setContext(this.context);
        layout.start();
        encoder.setLayout(layout);
        ca.setEncoder(encoder);
        ca.start();
        Logger rootLogger = loggerContext.getLogger("ROOT");
        rootLogger.addAppender(ca);
        return ExecutionStatus.NEUTRAL;
    }
}

Logback默认的自动配置是最简单的Logback配置方式,日志会直接被写入到控制台里。相比于System.out.println,日志API的直接优势就是可以控制部分日志的输出,如通过日志等级控制在运行环境中输出哪些日志信息。下面的例子中使用了Logback所有的日志等级分别输出日志。

package app.aeof;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    // 在需要使用日志的类中获取一个logger实例,也可以通过Lombok通过注解方式避免这一行
    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        // 日志等级从低到高分别为TRACE, DEBUG, INFO, WARN, ERROR
        logger.trace("TRACE日志");
        logger.debug("DEBUG日志");
        logger.info("INFO日志");
        logger.warn("WARN日志");
        logger.error("ERROR日志");
    }
}

运行上述程序,我们可以在终端中看到以下日志信息,可以发现TRACE等级的日志并没有被记录,因为Logger默认的日志等级是DEBUG,只会记录高于等于DEBUG等级的日志。

21:28:32.201 [main] DEBUG app.aeof.Main -- DEBUG日志
21:28:32.203 [main] INFO app.aeof.Main -- INFO日志
21:28:32.203 [main] WARN app.aeof.Main -- WARN日志
21:28:32.203 [main] ERROR app.aeof.Main -- ERROR日志

1.2.2 logback-test.xmllogback.xml配置 🔗

为了自定义Logback的配置,另一种主流的Logback配置方式就是使用logback-test.xmllogback.xml配置文件。Logback的配置很灵活,我们不仅可以配置日志的输出位置、输出格式这种基本配置,也可以控制日志文件压缩归档等,语法参见配置文件格式

官方文档为我们提供了很多配置的示例,下面这个配置文件定义了一个名为STDOUT的Appender,它采用的实现类为ConsoleAppender,因此日志的输出位置即为控制台。这个配置文件又通过root标签定义日志等级为TRACE,Appender下配置Encoder的日志输出格式与BasicConfigurator的输出格式相同,因此可以得到与BasicConfigurator相同的效果,但是可以打印TRACE等级的日志。

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
            </pattern>
        </encoder>
    </appender>

    <root level="TRACE">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
21:31:31.098 [main] TRACE app.aeof.Main -- TRACE日志
21:31:31.100 [main] DEBUG app.aeof.Main -- DEBUG日志
21:31:31.100 [main] INFO  app.aeof.Main -- INFO日志
21:31:31.101 [main] WARN  app.aeof.Main -- WARN日志
21:31:31.101 [main] ERROR app.aeof.Main -- ERROR日志

我们也可以配置各个类的日志输出等级,将app.aeof.Main的日志等级调至INFO

<configuration>
	<!-- ... -->
    
    <!--添加这一行,指定app.aeof.Main的输出等级为info-->
    <logger name="app.aeof.Main" level="info"/>

    <!-- ... -->
</configuration>

运行可以发现,TRACEDEBUG日志并没有被记录:

21:34:06.991 [main] INFO  app.aeof.Main -- INFO日志
21:34:06.993 [main] WARN  app.aeof.Main -- WARN日志
21:34:06.993 [main] ERROR app.aeof.Main -- ERROR日志

当然,有时候日志并不会写入到控制台,而是写入到文件,我们可以配置Appender为FileAppender,甚至为不同的日志等级配置不同的Appender。下面的示例中,通过root标签配置日志等级为DEBUG,并且配置了两个Appender,一个写入到文件,一个写入到控制台,写入到控制台的日志格式信息较少。

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%kvp %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

2. Logback的使用 🔗

2.1 Logger Context 🔗

日志API通过日志等级控制日志是否会被输出,Logback为每一个Logger携带了一个LoggerContext,即Logger的上下文信息。

comments powered by Disqus