1. Logback是什么 🔗
Logback的官方文档中指出,Logback是Log4j项目的继任者,是一个工业级的日志系统。Logback构建在SLF4J之上,因此我们使用Logback时也依赖于SLF4J。
Logback主要包含三个模块:logback-core
、logback-classic
和logback-access
,参见Logback架构,其中logback-core
定义了Appender和Layout接口和核心配置机制,logback-classic
则是logback-core
的实现,提供了另外一个核心的Logger
类,其实现了SLF4J,如下图所示。
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的配置机制还是比较复杂的,主要分为四个阶段。
- Logback提供了一个名为
Configurator
的配置器接口,首先Logback会找是否存在自定义的Configurator
实现类,如果存在的话则使用自定义的实现类,否则执行后续的阶段。 - 在
1.3.9/1.4.9
版本后,Logback会在没有找到配置类时实例化一个SerializedModelConfigurator
,它会读取系统属性、logback-test.scmo
、logback.scmo
,如果没有一个能够被找到的话,执行后面的阶段。 - Logback会在前面的步骤都无法完成时,初始化一个
DefaultJoranConfigurator
实例,这个默认的配置器实现类会处理Logback的配置,这也是Logback的最常用的配置方式。DefaultJoranConfigurator
首先会读取logback.configurationFile
系统属性,如果读取到系统属性且该属性对应的文件能够被读取的话,就采用该文件的配置。否则,它会在class path下按优先顺序搜索logback-test.xml
、logback.xml
,使用里面的配置。 - 如果前面的三个阶段都无法读取到配置,那么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.xml
或logback.xml
配置 🔗
为了自定义Logback的配置,另一种主流的Logback配置方式就是使用logback-test.xml
或logback.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>
运行可以发现,TRACE
和DEBUG
日志并没有被记录:
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的上下文信息。