Logback 旨在作为流行的 log4j 项目的继承者。它是由 log4j 创始人 Ceki Gulcu 设计的。同时它也是 SpingBoot 项目的默认日志框架。
因为 logback 需要和 slf4j 一起使用,所以总共需要添加依赖的包有 slf4j-api.jar,logback-core.jar,logback-classic.jar,logback-access.jar 这个暂时用不到所以不添加依赖了。
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<logback.version>1.1.7logback.version>
<slf4j.version>1.7.21slf4j.version>
properties>
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
<scope>compilescope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>${logback.version}version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>${logback.version}version>
dependency>
dependencies>
在 SpringBoot 项目中,如果你引入了 spring-boot-starter-web
,那你已经引入了上述的所有依赖。
Logback 的配置文件名为 logback.xml,在应用程序启动之后,Logback 会尝试在类路径中寻找该文件,如果没有找到,则会使用 Logback 内部的默认配置。
如果你的 logback.xml 配置文件在应用程序外部,可以通过环境变量 logback.configurationFile=/path/to/config.xml
来指定外部配置文件的路径。
configuration 是 logback.xml 中的顶级元素,它包含了一些属性:
<configuration scan="true" scanPeriod="30 seconds" debug="false">
...
configuration>
上述实例中表示开启配置文件扫描,扫描周期为 30s,并且不打印 Logback 内部日志。
configuration 元素下有三个子元素 appender,logger,root,其中 appender 和 logger 可以是零个或多个,root 元素则做多只能有一个。
用于配置变量,配置的变量可以在 appender 和 logger 中通过 ${}
来使用,可以用于统一配置。
<configuration>
<property name="PATTERN" value="%-4relative [%thread] %-5level %logger{35} - %msg %n" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN}pattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
root>
configuration>
appender 元素用来定义写日志的组件,它有两个必填的属性 name 和 class,name 表示组件的名称和 class 用于配置写日志逻辑的类,不同的类对应不同的写日志方式,目前,Logback 中定义了有 ConsoleAppender(控制台)、FileAppender(文件)、ServerSockerAppender(远程 Socker 服务器)、SMTPAppender(远程邮件服务器)、和 SyslogAppender(远程 Syslog 守护程序) 等 appender;当然,你也可以通过实现 Appender 接口来实现自己的 appender 并在配置文件中使用。
而这其中最常使用的就是 ConsoleAppender、FileAppender 和 RollingFileAppender。其中 RollingFileAppender 是 FileAppender 子类,它在日志写文件的基础上附加了滚动日志的功能,它解决了日志一直记录在一个文件而造成超大日志文件的痛点。
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
root>
configuration>
上述示例中的名为 STDOUT 的 appender 使用了 ConsoleAppender 来输出日志,即将日志输出到控制台上,其中的
子标签定对日志进行格式化。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.logfile>
<append>trueappend>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
root>
configuration>
上述示例中的名为 FILE 的 appender 使用了 FileAppender 来输出日志,即将日志输出到一个文件中,其中子标签释义如下:
<configuration>
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="ROLLING_FILE" />
root>
configuration>
上述示例中名为 ROLLING_FILE 的 appender 使用 RollingFileAppender 来输出日志,使用的滚动策略是基于时间的滚动策略,其中子标签释义如下:
类是 ch.qos.logback.core.rolling.TimeBasedRollingPolicy
,常用属性如下:
%d
来只当滚动周期,如 logFile.%d{yyyy-MM-dd}.log
表示按天滚动,logFile.%d{yyyy-MM}.log
表示按月滚动,logFile.%d.log
表示按天滚动
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logFile.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
<totalSizeCap>3GBtotalSizeCap>
rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
root>
configuration>
类是 ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
,常用属性如下:
fileNamePattern:用法和基于时间的滚动策略一样,除了 %d
,还需要使用 %i
,用于解决没有到下一个滚动时间但是因为文件大小而触发的滚动,文件名一样的问题,%i
从 0 开始递增
maxFileSize:每个文件的最大大小,如果超过指定的值会触发滚动
maxHistory:用法和基于时间的滚动策略一样
totalSizeCap:用法和基于时间的滚动策略一样
appender 标签用来配置日志的输出目的地,而 logger 标签可以看做日志的来源,即使从哪个包下或具体哪个类打印的日志,logger 标签可以绑定零个或多个 appender 来指定日志输出目的地。它有以下参数:
logger 包含零个或多个子标签
,它用来绑定 appender。
在 logback 中,logger 具有树形结构的层级关系,这种层级关系通过包名来构建,如下所示:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %npattern>
encoder>
appender>
<logger name="com.test.logback" level="debug" additivity="true">
<appender-ref ref="STDOUT" />
logger>
<logger name="com.test" level="debug" additivity="true">
<appender-ref ref="STDOUT" />
logger>
<root level="debug">
root>
configuration>
上述两个 logger,通过包名的层级结构,name 为 com.test
的 logger 是 name 为 com.test.logback
的父 logger,如果通过包名的层级结构找不到该 logger 的父 logger,那么它的父 logger 就是 root logger,比如,name 为 com.test
的父 logger 就是 root logger,如果之后又定义了一个 name 为 com
的 logger,那么它的父 logger 会更变为新定义的 name 为 com
的 logger,而 name 为 com
的父 logger 就是 root logger。
通过上面介绍,我们 additivity 属性用于配置当前 logger 是否将日志传递给父 logger,默认为传递(true),以上面的例子来说,如果 com.test.logback
包下的类打印了日志,如果会传递到 name 为 com.test.logback
的 logger,并使用它绑定的 appender 来输出日志,又因为它的 additivity 的值为 true,那么当前 logger 在自己输出日志之后,还会将日志传递给父 logger,也就是 name 为 com.test
的 logger,不合理的使用 additivity 属性可能导致重复打印日志的情况。
其中 level 属性也与 logger 的层级结构有关,如果当前 logger 没有定义 level 属性,那么将会从最近的定义了 level 属性的父 logger 中继承,因此 root logger 一般都会设置 level 属性,用于给其他的 logger 统一设置 level 属性。
level 级别:
优先级从高到低依次是:FATAL -> ERROR -> WARN -> INFO -> DEBUG,开启指定的日志级别,会打印该日志级别的日志和所有优先级高于该日志级别的日志,如设置日志级别是 INFO,那么会打印 FATAL,ERROR,WARN 和 INFO 级别的日志,如果设置日志级别是 WARN,那么会打印 FATAL,ERRO 和 WARN 级别的日志。
通过实例来验证上述中 logger 的层级关系,首先创建两个类 com.test.Logback01Tests
和 com.test.logback.Logback02Tests
。类定义中省略了 package 和 import 语句。
com.test.Logback01Tests
public class Logback01Tests {
private static final Logger log = LoggerFactory.getLogger(Logback01Tests.class);
public void test01(){
log.debug("debug");
log.info("info");
}
}
com.test.logback.Logback02Tests
public class Logback02Tests {
private static final Logger log = LoggerFactory.getLogger(Logback02Tests.class);
public void test01(){
log.debug("debug");
log.info("info");
}
}
logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %npattern>
encoder>
appender>
<logger name="com.test.logback" level="debug" additivity="true">
<appender-ref ref="STDOUT" />
logger>
<logger name="com.test" level="debug" additivity="true">
<appender-ref ref="STDOUT" />
logger>
<root level="debug">
root>
configuration>
通过 logback.xml 配置预测日志的输出结果。
因为两个 logger 都设置了 debug 日志级别,所以方法中打印的 debug 和 info 级别两条日志都会打印出来,然后都设置了将日志传递到父 logger 中,则 name 为 com.test.logback 的 logger 会将日志传递到 name 为 com.test 父 logger 中,所以 com.test.logback.Logback02Tests
中的两条日志应该会打印两次,name 为 com.test 的 logger 会将日志传递到 root logger 中,但是 root logger 没有绑定任何的 appender,所以即使传递了也不会打印日志,所以 com.test.Logback01Tests
中的四条日志(加上子 logger 中传递过来的两条日志)应该只会打印一次。
定义一个测试方法调用两个类的方法。
public class NormalTests {
@Test
public void test02(){
Logback01Tests logback01Tests = new Logback01Tests();
Logback02Tests logback02Tests = new Logback02Tests();
logback01Tests.test01();
logback02Tests.test01();
}
}
实际输出结果:
127 [main] DEBUG com.test.Logback01Tests - debug
129 [main] INFO com.test.Logback01Tests - info
129 [main] DEBUG com.test.logback.Logback02Tests - debug
129 [main] DEBUG com.test.logback.Logback02Tests - debug
129 [main] INFO com.test.logback.Logback02Tests - info
129 [main] INFO com.test.logback.Logback02Tests - info
可以看到输出结果完全符合我们的预期,读者可以通过扩展这个例子来验证其他的一些问题,如将日志级别设置成 INFO 之后的日志输出应该是怎么样的?
root 标签用来配置 root logger,它只有一个属性,即 level 属性。与 logger 元素类似,root 元素可以包含零个或多个
子标签。
在实际使用中,root logger 通常不会绑定 appender,以避免日志重复打印,日志打印被分配到各个子 logger 中来负责。root logger 中会定义一个 level,以保证每个子 logger 都能继承 level。
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line\)- %m%npattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="fileLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/file/fileLog.logFile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/file/fileLog.log.%d.%ifileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>64 MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<encoder>
<pattern>
%d %p (%file:%line\)- %m%n
pattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="sqlFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/sql/sqlFile.logFile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/sql/sqlFile.log.%d.%ifileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>64 MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<encoder>
<pattern>
%d %p (%file:%line\)- %m%n
pattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="errorFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/error/errorFile.logFile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/error/errorFile.%d.log.%ifileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>64 MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<encoder>
<pattern>
%d %p (%file:%line\)- %m%n
pattern>
<charset>UTF-8charset>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERRORlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<root level="INFO">
<appender-ref ref="fileLog" />
<appender-ref ref="console" />
<appender-ref ref="errorFile" />
root>
<logger name="com.springboot.demo.mapper" level="DEBUG" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="sqlFile" />
logger>
configuration>
SpringBoot 项目的默认日志框架就是 Logback,在 SpingBoot 项目中可以通过 application.properties 来配置日志的打印行为。
# 设置logback.xml位置
logging.config=classpath:log/logback.xml
# 为不同的包名设置不同的打印级别
# org.springframework.web 包的打印级别为 debug
logging.level.org.springframework.web=debug
# org.hibernate 包的打印级别为 error
logging.level.org.hibernate=error
# 指定日志文件的名称
logging.file.name=springboot.log
# 指定日志文件的全路径,它包含了指定日志文件名称的功能
logging.file.name=/usr/log/springboot.log
参考:
https://logback.qos.ch/manual/index.html
https://blog.csdn.net/weixin_41377777/article/details/120962037
https://www.cnblogs.com/gavincoder/p/10091757.html
https://juejin.cn/post/6844903841318567949