深入剖析源码系列(第七期):详细解读Logback的运用与内核代码解析
什么是logback
logback 用于日志记录,可以将日志输出到控制台、文件、数据库和邮件等,相比其它所有的日志系统,logback 更快并且更小,包含了许多独特并且有用的特性。
logback 被分成三个不同的模块:logback-core,logback-classic,logback-access。
- logback-core 是其它两个模块的基础。
- logback-classic 模块可以看作是 log4j 的一个优化版本,它天然的支持 SLF4J。
- logback-access 提供了 http 访问日志的功能,可以与 Servlet 容器进行整合,例如:Tomcat、Jetty。
本文将介绍以下内容,由于篇幅较长,可根据需要选择阅读:
- 如何使用 logback:将日志输出到控制台、文件和数据库,以及使用 JMX 配置 logback;
- logback 配置文件详解;
- logback 的源码分析。
如何使用logback
需求
- 使用 logback 将日志信息分别输出到控制台、文件、数据库。
- 使用 JMX 方式配置 logback。
工程环境
JDK:1.8.0_231
maven:3.6.1
IDE:Spring Tool Suite 4.3.2.RELEASE
mysql:5.7.28
主要步骤
- 搭建环境;
- 配置 logback 文件;
- 编写代码:获取
Logger
实例,并打印指定等级的日志; - 测试。
创建项目
项目类型 Maven Project ,打包方式 jar。
引入依赖
logack 天然的支持 slf4j,不需要像其他日志框架一样引入适配层(如 log4j 需引入 slf4j-log4j12 )。通过后面的源码分析可知,logback 只是将适配相关代码放入了 logback-classic。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- logback+slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<type>jar</type>
</dependency>
<!-- 输出日志到数据库时需要用到 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!-- 使用数据源方式输出日志到数据库时需要用到 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
</dependencies>
将日志输出到控制台
配置文件
配置文件放在 resources 下,文件名可以为 logback-test.xml 或 logback.xml,实际项目中可以考虑在测试环境中使用 logback-test.xml ,在生产环境中使用 logback.xml( 当然 logback 还支持使用 groovy 文件或 SPI 机制进行配置,本文暂不涉及)。
在 logback中,logger 可以看成为我们输出日志的对象,而这个对象打印日志时必须遵循 appender 中定义的输出格式和输出目的地等。注意,root logger 是一个特殊的 logger。
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--定义控制台输出格式-->
<encoder charset="utf-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
另外,即使我们没有配置,logback 也会默认产生一个 root logger ,并为它配置一个 ConsoleAppender
。
编写测试类
为了程序的解耦,一般我们在使用日志时会采用门面模式,即通过 slf4j 或 commons-logging 来获取 Logger
对象。
以下代码中,导入的两个类 Logger
、 LoggerFactory
都定义在 slf4j-api 中,完全不会涉及到 logback 包的类。这时,如果我们想切换 log4j 作为日志支持,只要修改 pom.xml 和日志配置文件就行,项目代码并不需要改动。源码分析部分将分析 slf4j 如何实现门面模式。
@Test
public void test01() {
Logger logger = LoggerFactory.getLogger(LogbackTest.class);
logger.debug("输出DEBUG级别日志");
logger.info("输出INFO级别日志");
logger.warn("输出WARN级别日志");
logger.error("输出ERROR级别日志");
}
注意,这里获取的 logger 不是我们配置的 root logger,而是以 cn.zzs.logback.LogbackTest 命名的 logger,它继承了祖先 root logger 的配置。
测试
运行测试方法,可以看到在控制台打印如下信息:
2020-01-16 09:10:40 [main] INFO ROOT - 输出INFO级别的日志
2020-01-16 09:10:40 [main] WARN ROOT - 输出WARN级别的日志
2020-01-16 09:10:40 [main] ERROR ROOT - 输出ERROR级别的日志
这时我们会发现,怎么没有 debug 级别的日志?因为我们配置了日志等级为 info,小于 info 等级的日志不会被打印出来。日志等级如下:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < OFF
将日志输出到滚动文件
本例子将在以上例子基础上修改。测试方法代码不需要修改,只要修改配置文件就可以了。
配置文件
前面已经讲过,appender 中定义日志的输出格式和输出目的地等,所以,要将日志输出到滚动文件,只要修改appender 就行。logback 提供了RollingFileAppender
来支持打印日志到滚动文件。
以下配置中,设置了文件大小超过100M后会按指定命名格式生成新的日志文件。
<configuration>
<!-- 定义变量 -->
<property name="LOG_HOME" value="D:/growUp/test/log" />
<property name="APP_NAME" value="logback-demo"/>
<!-- 滚动文件输出 -->
<appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${APP_NAME}/error.log</file>
<!-- 配置追加写入 -->
<append>true</append>
<!-- 级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 滚动文件名称 -->
<fileNamePattern>${LOG_HOME}/${APP_NAME}/notError-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。
注意,删除旧文件时, 那些为了归档而创建的目录也会被删除。 -->
<MaxHistory>50</MaxHistory>
<!-- 当日志文件超过maxFileSize指定的大小时,根据上面提到的%i进行日志文件滚动 -->
<maxFileSize>100MB</maxFileSize>
<!-- 设置文件总大小 -->
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<!-- 日志输出格式-->
<encoder charset="utf-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="FILE" />
</root>
</configuration>
测试
运行测试方法,我们可以在指定目录看到生成的日志文件。
查看日志文件,可以看到只打印了 error 等级的日志:
将日志输出到数据库
logback 提供了DBAppender
来支持将日志输出到数据库中。
创建表
logback 为我们提供了三张表用于记录日志, 在使用DBAppender
之前,这三张表必须存在。
这三张表分别为:logging_event, logging_event_property 与 logging_event_exception。logback 自带 SQL 脚本来创建表,这些脚本在 logback-classic/src/main/java/ch/qos/logback/classic/db/script 文件夹下,相关脚本也可以再本项目的 resources/script 找到。
由于本文使用的是 mysql 数据库,执行以下脚本(注意,官方给的 sql 中部分字段设置了NOT NULL 的约束,可能存在插入报错的情况,可以考虑调整):
BEGIN;
DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;
COMMIT;
BEGIN;
CREATE TABLE logging_event
(
timestmp BIGINT NOT NULL,
formatted_message TEXT NOT NULL,
logger_name VARCHAR(254) NOT NULL,
level_string VARCHAR(254) NOT NULL,
thread_name VARCHAR(254),
reference_flag SMALLINT,
arg0 VARCHAR(254),
arg1 VARCHAR(254),
arg2 VARCHAR(254),
arg3 VARCHAR(254),
caller_filename VARCHAR(254),
caller_class VARCHAR(254) NOT NULL,
caller_method VARCHAR(254) NOT NULL,
caller_line CHAR(4) NOT NULL,
event_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
COMMIT;
BEGIN;
CREATE TABLE logging_event_property
(
event_id BIGINT NOT NULL,
mapped_key VARCHAR(254) NOT NULL,
mapped_value TEXT,
PRIMARY KEY(event_id, mapped_key),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;
BEGIN;
CREATE TABLE logging_event_exception
(
event_id BIGINT NOT NULL,
i SMALLINT NOT NULL,
trace_line VARCHAR(254) NOT NULL,
PRIMARY KEY(event_id, i),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;
可以看到生成了三个表:
配置文件
logback 支持使用 DataSourceConnectionSource,DriverManagerConnectionSource 与 JNDIConnectionSource 三种方式配置数据源 。本文选择第一种,并使用以 c3p0 作为数据源(第二种方式文中也会给出)。
这里需要说明下,因为实例化 c3p0 的数据源对象ComboPooledDataSource
时,会去自动加载 classpath 下名为 c3p0-config.xml 的配置文件,所以,我们不需要再去指定 dataSource 节点下的参数,如果是 druid 或 dbcp 等则需要指定。
<configuration>
<!--数据库输出-->
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<!-- 使用jdbc方式 -->
<!-- <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.cj.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true</url>
<user>root</user>
<password>root</password>
</connectionSource> -->
<!-- 使用数据源方式 -->
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
</dataSource>
</connectionSource>
</appender>
<root level="info">
<appender-ref ref="DB" />
</root>
</configuration>
测试
运行测试方法,可以看到数据库中插入了以下数据:
使用JMX配置logback
logback 支持使用 JMX 动态地更新配置。开启 JMX 非常简单,只需要增加 jmxConfigurator 节点就可以了,如下:
<configuration scan="true" scanPeriod="10 seconds" debug="true">
<!-- 定义变量 -->
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 开启JMX支持 -->
<jmxConfigurator />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
在我们通过 jconsole 连接到服务器上之后(jconsole 在 JDK 安装目录的 bin 目录下),在 MBeans 面板上,在 "ch.qos.logback.classic.jmx.Configurator" 文件夹下你可以看到几个选项。如下图所示:
我们可以看到,在属性中,我们可以查看 logback 已经产生的 logger 和 logback 的内部状态,通过操作,我们可以:
- 获取指定 logger 的级别。返回值可以为 null
- 设置指定的 logger 的级别。想要设置为 null,传递 "null" 字符串就可以
- 通过指定的文件重新加载配置
- 通过指定的 URL 重新加载配置
- 使用默认配置文件重新加载 logback 的配置
- 或者指定 logger 的有效级别
更多 JMX 相关内容可参考我的另一篇博客:如何使用JMX来管理程序?
补充--两种打印方式
实际项目中,有时我们需要对打印的内容进行一定处理,如下:
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
这种情况会产生构建消息参数的成本,为了避免以上损耗,可以修改如下:
if(logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}
当我们打印的是一个对象时,也可以采用以下方法来优化:
// 不推荐
logger.debug("The new entry is " + entry + ".");
// 推荐
logger.debug("The new entry is {}", entry);
配置文件详解
前面已经说过, logback 配置文件名可以为 logback-test.xml 、 logback.groovy 或 logback.xml ,除了采用配置文件方式, logback 也支持使用 SPI 机制加载 ch.qos.logback.classic.spi.Configurator 的实现类来进行配置。以下讲解仅针对 xml 格式文件的配置方式展开。
另外,如果想要自定义配置文件的名字,可以通过系统属性指定:
-Dlogging.config=classpath:logback-sit.xml
如果没有加载到配置,logback 会调用 BasicConfigurator 进行默认的配置。
configuration
configuration 是 logback.xml 或 logback-test.xml 文件的根节点。
configuration 主要用于配置某些全局的日志行为,常见的配置参数如下:
属性名 | 描述 |
---|---|
debug | 是否打印 logback 的内部状态,开启有利于排查 logback 的异常。默认 false |
scan | 是否在运行时扫描配置文件是否更新,如果更新时则重新解析并更新配置。如果更改后的配置文件有语法错误,则会回退到之前的配置文件。默认 false |
scanPeriod | 多久扫描一次配置文件是否修改,单位可以是毫秒、秒、分钟或者小时。默认情况下,一分钟扫描一次配置文件。 |
配置方式如下:
<configuration debug="true" scan="true" scanPeriod="60 seconds" >
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
使用以上配置进行测试:
如上图,通过控制台我们可以查看 logback 加载配置的过程,这时,我们尝试修改 logback 配置文件的内容:
观察控制台,可以看到配置文件重新加载:
logger
前面提到过,logger 是为我们打印日志的对象,这个概念非常重要,有助于更好地理解 logger 的继承关系。
在以下代码中,我们可以在getLogger
方法中传入的是当前类的 Class 对象或全限定类名,本质上获取到的都是一个 logger 对象(如果该 logger 不存在,才会创建)。
@Test
public void test01() {
Logger logger1 = LoggerFactory.getLogger(LogbackTest.class);
Logger logger2 = LoggerFactory.getLogger("cn.zzs.logback.LogbackTest");
System.err.println(logger == logger2);// true
}
这里补充一个问题,该 logger 对象以 cn.zzs.logback.LogbackTest 命名,和我们配置文件中定义的 root logger 并不是同一个,但是为什么这个 logger 对象却拥有 root logger 的行为?
这要得益于 logger 的继承关系,如下图:
如果我们未指定当前 logger 的日志等级,logback 会将其日志等级设置为最近父级的日志等级。另外,默认情况下,当前 logger 也会继承最近父级持有的 appender。
下面测试下以上特性,将配置文件进行如下修改:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds" debug="true">
<!-- 定义变量 -->
<property scope="system" name="LOG_HOME" value="D:/growUp/test/logs" />
<property scope="system" name="APP_NAME" value="logback-demo"/>
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<timestamp key="bySecond" datePattern="yyyy-MM-dd'T'HH-mm-ss" />
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<append>true</append>
<file>${LOG_HOME}/${APP_NAME}/file-${bySecond}.log</file>
<immediateFlush>true</immediateFlush>
<!-- 是否启用安全写入 -->
<prudent>false</prudent>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<logger name="cn.zzs" level="error">
<appender-ref ref="FILE" />
</logger>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
这里自定义了一个 logger,日志等级是 error,appender 为文件输出。运行测试方法:
可以看到,名为 cn.zzs.logback.LogbackTest 的 logger 继承了名为 cn.zzs 的 logger 的日志等级和 appender,以及继承了 root logger 的 appender。
实际项目中,如果不希望继承父级的 appender,可以配置 additivity="false" ,如下:
<logger name="cn.zzs" additivity="false">
<appender-ref ref="FILE" />
</logger>
注意,因为以下配置都是建立在 logger 的继承关系上,所以这部分内容必须很好地理解。
appender
appender 用于定义日志的输出目的地和输出格式,被 logger 所持有。logback 为我们提供了以下几种常用的appender:
类名 | 描述 |
---|---|
ConsoleAppender | 将日志通过 System.out 或者 System.err 来进行输出,即输出到控制台。 |
FileAppender | 将日志输出到文件中。 |
RollingFileAppender | 继承自 FileAppender,也是将日志输出到文件,但文件具有轮转功能。 |
DBAppender | 将日志输出到数据库 |
SocketAppender | 将日志以明文方式输出到远程机器 |
SSLSocketAppender | 将日志以加密方式输出到远程机器 |
SMTPAppender | 将日志输出到邮件 |
本文仅会讲解前四种,后四种可参考官方文档。
ConsoleAppender
ConsoleAppender 支持将日志通过 System.out 或者 System.err 输出,即输出到控制台,常用属性如下:
属性名 | 类型 | 描述 |
---|---|---|
encoder | Encoder | 后面单独讲 |
target | String | System.out 或 System.err。默认为 System.out |
immediateFlush | boolean | 是否立即刷新。默认为 true。 |
withJansi | boolean | 是否激活 Jansi 在 windows 使用 ANSI 彩色代码,默认值为 false。 在windows电脑上我尝试开启这个属性并引入 jansi 包,但老是报错,暂时没有解决方案。 |
具体配置如下:
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
FileAppender
FileAppender 支持将日志输出到文件中,常用属性如下:
属性名 | 类型 | 描述 |
---|---|---|
append | boolean | 是否追加写入。默认为 true |
encoder | Encoder | 后面单独讲 |
immediateFlush | boolean | 是否立即刷新。默认为 true。 |
file | String | 要写入文件的路径。如果文件不存在,则新建。 |
prudent | boolean | 是否采用安全方式写入,即使在不同的 JVM 或者不同的主机上运行 FileAppender 实例。默认的值为 false。 |
具体配置如下:
<!-- 定义变量 -->
<property scope="system" name="LOG_HOME" value="D:/growUp/test/logs" />
<property scope="system" name="APP_NAME" value="logback-demo"/>
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<timestamp key="bySecond" datePattern="yyyy-MM-dd'T'HH-mm-ss" />
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_HOME}/${APP_NAME}/file-${bySecond}.log</file>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
RollingFileAppender
RollingFileAppender 继承自 FileAppender,也是将日志输出到文件,但文件具有轮转功能。
RollingFileAppender 的属性如下所示:
属性名 | 类型 | 描述 |
---|---|---|
file | String | 要写入文件的路径。如果文件不存在,则新建。 |
append | boolean | 是否追加写入。默认为 true。 |
immediateFlush | boolean | 是否立即刷新。默认为true。 |
encoder | Encoder | 后面单独将 |
rollingPolicy | RollingPolicy | 定义文件如何轮转。 |
triggeringPolicy | TriggeringPolicy | 定义什么时候发生轮转行为。如果 rollingPolicy 使用的类已经实现了 triggeringPolicy 接口,则不需要再配置 triggeringPolicy,例如 SizeAndTimeBasedRollingPolicy。 |
prudent | boolean | 是否采用安全方式写入,即使在不同的 JVM 或者不同的主机上运行 FileAppender 实例。默认的值为 false。 |
具体配置如下:
<!-- 定义变量 -->
<property scope="system" name="LOG_HOME" value="D:/growUp/test/logs" />
<property scope="system" name="APP_NAME" value="logback-demo"/>
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 轮转文件输出 -->
<appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 轮转策略,它根据时间和文件大小来制定轮转策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 按天轮转 -->
<fileNamePattern>${LOG_HOME}/${APP_NAME}/log-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 保存 30 天的历史记录,最大大小为 30GB -->
<MaxHistory>30</MaxHistory>
<totalSizeCap>30GB</totalSizeCap>
<!-- 当日志文件超过100MB的大小时,根据上面提到的%i进行日志文件轮转 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<!-- 日志输出格式-->
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
DBAppender
参见使用例子。
encoder
encoder 负责将日志事件按照配置的格式转换为字节数组,常用属性如下:
属性名 | 类型 | 描述 |
---|---|---|
pattern | String | 日志打印格式。 |
outputPatternAsHeader | boolean | 是否将 pattern 字符串插入到日志文件顶部。默认false。 |
针对 pattern 属性,这里补充下它的常用转换字符:
转换字符 | 描述 |
---|---|
c{length} lo{length} logger{length} | 输出 logger 的名字。可以通过 length 缩短其长度。 但是,logger 名字最右边永远都会存在。 例如,当我们设置 logger{0}时,cn.zzs.logback.LogbackTest 中的 LogbackTest 永远不会被删除 |
C{length} class{length} | 输出发出日志请求的类的全限定名称。 可以通过 length 缩短其长度。 |
d{pattern} date{pattern} d{pattern, timezone} date{pattern, timezone} | 输出日志事件的日期。 可以通过 pattern 设置日期格式,timezone 设置时区。 |
m / msg / message | 输出与日志事件相关联的,由应用程序提供的日志信息。 |
M / method | 输出发出日志请求的方法名。 |
p / le / level | 输出日志事件的级别。 |
t / thread | 输出生成日志事件的线程名。 |
n | 输出平台所依赖的行分割字符。 |
F / file | 输出发出日志请求的 Java 源文件名。 |
caller{depth} caller{depthStart..depthEnd} caller{depth, evaluator-1, ... evaluator-n} caller{depthStart..depthEnd, evaluator-1, ... evaluator-n} | 输出生成日志的调用者所在的位置信息。 |
L / line | 输出发出日志请求所在的行号。 |
property{key} | 输出属性 key 所对应的值。 |
注意,在拼接 pattren 时,应该考虑使用“有意义的”转换字符,避免产生不必要的性能开销。具体配置如下:
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="utf-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<outputPatternAsHeader>true</outputPatternAsHeader>
</encoder>
</appender>
其中, 转换说明符 %-5level 表示日志事件的级别的字符应该向左对齐,保持五个字符的宽度。
filter
appender 除了定义日志的输出目的地和输出格式,其实也可以对日志事件进行过滤输出,例如,仅输出包含指定字符的日志。而这个功能需配置 filter。
LevelFilter
LevelFilter 基于级别来过滤日志事件。修改配置文件如下:
<configuration scan="true" scanPeriod="10 seconds" debug="true">
<!-- 定义变量 -->
<property scope="system" name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>system.err</target>
<encoder charset="utf-8">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<!-- 设置过滤器 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
下一篇: logback的MDC机制