Logback简介
Logback 是由 log4j 创始人设计的又一个开源日志组件。
Logback 当前分成三个模块: logback-core,logback-classic和logback-access。
logback-core 是其它两个模块的基础模块。
logback-classic 是 log4j的一个改良版本。此外 logback-classic 完整实现SLF4J API。使你可以很方便地更换成其它日志系统如 log4j或JDK14 Logging。
logback-access 访问模块与 Servlet 容器集成提供通过 Http 来访问日志的功能。
Logback中的组件
- Logger:日志的记录器,
主要用于存放日志对象,也可以定义日志类型、级别。
- Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、数据库等等。
Layout:负责把事件转换成字符串,格式化的日志信息的输出。在Logback 中Layout 对象被封装在 encoder 中.也就是说我们未来使用的 encoder 其实就是 Layout
Logback配置文件
Logback提供了3种配置文件。
logback.groovy
- logback-test.xml
- logback.xml
如果都不存在则采用默认的配置。
日志输出格式
| 标识符及占位符 | 描述 |
|---|---|
| %-10level | 级别,设置10个这符,左对齐 |
| %d{yyyy-MM-dd HH:mm:ss.SSS} | 日期时间 |
| %c | 当前类全限定名 |
| %M | 当前执行日志的方法 |
| %L | 行号 |
| %thread | 线程名称 |
| %m或者%msg | 输出的日志信息 |
| %n | 换行 |
案例
引入依赖
我们已经学习了如何使用slf4j,那么我们就使用slf4j+logback的方式
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency><!--slf4j日志门面 核心依赖--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.32</version></dependency><!--logback-core是logback-classic的基础模块logback-classic已经涵盖了 logback-core,Maven有依赖传递性,会自动依赖logback-core--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.10</version></dependency>
日志级别
logback有5种级别的日志输出,分别是
trace < debug < info < warn < error
默认级别:debug
@Testpublic void testLogback(){Logger logger = LoggerFactory.getLogger(LogbackTest.class);logger.error("========= ERROR信息 test Logback =========");logger.warn("========= WARN信息 test Logback =========");logger.info("========= INFO信息 test Logback =========");logger.debug("========= DEBUG信息 test Logback =========");logger.trace("========= TRACE信息 test Logback =========");/***通过控制台信息,可以看到默认级别是debug。 trace级别的信息没有输出* 17:18:06.755 [main] ERROR cn.giteasy.logback.test.LogbackTest - ========= ERROR信息 test Logback =========* 17:18:06.757 [main] WARN cn.giteasy.logback.test.LogbackTest - ========= WARN信息 test Logback =========* 17:18:06.757 [main] INFO cn.giteasy.logback.test.LogbackTest - ========= INFO信息 test Logback =========* 17:18:06.757 [main] DEBUG cn.giteasy.logback.test.LogbackTest - ========= DEBUG信息 test Logback =========*/}
使用配置文件
logback.xml
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--<property name="" value=""></property>配置文件通用属性,通过${name}的形式取值--><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!-- 控制台Appender --><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><!--输出目标的配置,System.out:以黑色字体(默认)System.err:红色字体--><target>System.err</target><!-- 日志输出格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!--日志记录器配置,可以配置多个Appender,进行多方向的日志输出root => rootLoggerlevel: 表示日志级别--><root level="ALL"><appender-ref ref="consoleAppender"/></root></configuration>
@Testpublic void testLogbackConfigFile(){Logger logger = LoggerFactory.getLogger(LogbackTest.class);logger.error("========= ERROR信息 test Logback =========");logger.warn("========= WARN信息 test Logback =========");logger.info("========= INFO信息 test Logback =========");logger.debug("========= DEBUG信息 test Logback =========");logger.trace("========= TRACE信息 test Logback =========");}
输出日志到文件中
在实际生产环境中,我们更希望将日志信息保存到文件中
<?xml version="1.0" encoding="UTF-8" ?><configuration><property name="logDir" value="D://logback_log"></property><property name="fileName" value="logback.log"></property><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!--文件appender,默认是以追加日志的形式进行输出的--><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><!--输出文件位置--><file>${logDir}//${fileName}</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><root level="ALL"><appender-ref ref="fileAppender"/></root></configuration>
输出日志为HTML文件格式
<?xml version="1.0" encoding="UTF-8" ?><configuration><property name="logDir" value="D://logback_log"></property><property name="htmlFileName" value="logback.html"></property><property name="htmlPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS}%thread%-5level%c%M%L%m"></property><!--HTML文件appender--><appender name="htmlFileAppender" class="ch.qos.logback.core.FileAppender"><!--输出文件位置--><file>${logDir}//${htmlFileName}</file><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>${htmlPattern}</pattern></layout></encoder></appender><root level="ALL"><!-- <appender-ref ref="fileAppender"/> --><appender-ref ref="htmlFileAppender"/></root></configuration>
日志文件拆分和归档压缩
重要标签来源:
查看源码
RollingFileAppender类中找到rollingPolicy属性
SizeAndTimeBasedRollingPolicy类中找到maxFilesize属性
这些属性在类中都是以set方法的形式进行的赋值
我们在配置文件中配置的信息,其实找到的都是这些属性的set方法
在TimeBasedRollingPolicy找到
static final string FNP_NOT_SET ="The FileNamePattern option must be set before using TimeBasedRollingPolicy."
只要我们要使用到日志的拆分
FileNamePattern属性是必须要使用到了
logback.xml
<?xml version="1.0" encoding="UTF-8" ?><configuration><property name="logDir" value="D://logback_log"></property><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!--可拆分归档的appender--><appender name="rollFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}/roll_logback.log</file><!--指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--按照时间和压缩格式声明文件名,压缩格式gz--><fileNamePattern>${logDir}/roll_logback.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><!--按照文件大小进行拆分--><maxFileSize>2KB</maxFileSize></rollingPolicy></appender><root level="ALL"><!-- <appender-ref ref="fileAppender"/> --><!-- <appender-ref ref="htmlFileAppender"/> --><appender-ref ref="rollFileAppender"/></root></configuration>
为了看到拆分的效果,我们使用循环测试日志输出
@Testpublic void testFileSplit(){Logger logger = LoggerFactory.getLogger(LogbackTest.class);for (int i = 0; i < 100; i++) {logger.error("========= ERROR信息 test Logback =========");logger.warn("========= WARN信息 test Logback =========");logger.info("========= INFO信息 test Logback =========");logger.debug("========= DEBUG信息 test Logback =========");logger.trace("========= TRACE信息 test Logback =========");}}
使用过滤器
使用过滤器,对日志进行更细粒度的控制
logback.xml
<?xml version="1.0" encoding="UTF-8" ?><configuration><property name="logDir" value="D://logback_log"></property><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!--使用过滤器,进行细粒度控制--><appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><!-- 日志输出格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><!--高于level中设置的级别,则打印日志--><onMatch>ACCEPT</onMatch><!--低于level中设置的级别,则屏蔽--><onMismatch>DENY</onMismatch></filter></appender><root level="ALL"><appender-ref ref="consoleFilterAppender"/></root></configuration>
@Testpublic void test06(){Logger logger = LoggerFactory.getLogger(LogbackTest.class);logger.error("========= ERROR信息 test Logback =========");logger.warn("========= WARN信息 test Logback =========");logger.info("========= INFO信息 test Logback =========");logger.debug("========= DEBUG信息 test Logback =========");logger.trace("========= TRACE信息 test Logback =========");/*** 2022-01-28 21:27:30.784 [main] ERROR cn.giteasy.logback.test.LogbackTest test06 128 ========= ERROR信息 test Logback =========*/}
异步日志
@Testpublic void test07(){Logger logger = LoggerFactory.getLogger(LogbackTest.class);//日志输出for (int i = 0; i < 100; i++) {logger.error("========= ERROR信息 test Logback =========");logger.warn("========= WARN信息 test Logback =========");logger.info("========= INFO信息 test Logback =========");logger.debug("========= DEBUG信息 test Logback =========");logger.trace("========= TRACE信息 test Logback =========");}//业务逻辑操作for (int i = 0; i < 100; i++) {System.out.println(i);}}
按照我们当前的代码执行顺序,
代码肯定是按照从上向下的顺序执行,上面的代码完全执行完毕后,才会执行下面的业务逻辑
由此得出会出现的问题:
只要是在记录日志,那么系统本身的功能就处于一种停滞的状态,当日志记录完毕后,才会执行其他代码
如果日志记录量非常庞大的话,那么系统本身业务代码的执行效率会非常低
所以logback为我们提供了异步日志的功能
配置方式
- 配置异步日志
在异步日志中引入我们真正需要输出的appender
<appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="consoleAppender"/></appender>
- 在rootLogger中引入导步日志
完整配置文件logback.xml ```xml <?xml version=”1.0” encoding=”UTF-8” ?><root level="ALL"><appender-ref ref="asyncAppender"/></root>
<property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!-- 控制台Appender --><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!--异步日志Appender--><appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="consoleAppender"/></appender><root level="ALL"><appender-ref ref="asyncAppender"/></root>
<a name="P03D6"></a>#### 输出效果```java2022-02-12 19:10:25.437 [main] WARN cn.giteasy.logback.test.LogbackTest test07 191 ========= WARN信息 test Logback =========02022-02-12 19:10:25.437 [main] ERROR cn.giteasy.logback.test.LogbackTest test07 190 ========= ERROR信息 test Logback =========12022-02-12 19:10:25.437 [main] WARN cn.giteasy.logback.test.LogbackTest test07 191 ========= WARN信息 test Logback =========2
所谓异步日志的原理是:
系统会为日志操作单独的分配出来一个线程,主线程会继续向下执行
线程1:系统业务代码执行
线程2:打印日志
两个线程争夺CPU的使用权
在实际项目开发中,越大的项目对于日志的记录就越庞大,为了保证系统的执行效率,异步日志是不错的选择。
自定义Logger
<?xml version="1.0" encoding="UTF-8" ?><configuration><property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property><!-- 控制台Appender --><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><!-- 日志输出格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!--自定义Loggeradditivity="false" 表示不继承rootLogger--><logger name="cn.giteasy" level="warn" additivity="false"><appender-ref ref="consoleAppender"></appender-ref></logger></configuration>
关于Logback的补充
- 异步日志
可配置属性:
当队列的剩余容量小于这个阈值的时候,当前日志的级别 trace、debug、info这3个级别的日志将被丢弃<discardingThreshold>0</discardingThreshold>
设置为0,说明永远都不会丢弃trace、debug、info这3个级
<queueSize>256</queueSize>
配置队列的深度,这个值会影响记录日志的性能,默认值256<br /> <br /> 关于这两个属性,一般情况下,我们使用默认值即可,不要乱配置,会影响系统性能,了解其功能即可
- 配置文件转换
关于不同的日志实现,配置文件也是不同的:
log4j一般使用的是properties属性文件
logback使用的是xml配置文件
如果我们遇到了一种需求,需要将正在使用的log4j,替换为logback,应该如何处理?
使用转换工具:
访问logback官网
找到log4j.properties转换器 (https://logback.qos.ch/translator/)
只有是二者兼容的配置,才会被翻译
如果是log4j独立的技术,logback没有,或者是有这个技术但是并不兼容转义
那么这个工具则不会为我们进行转换,如果是遇到简单的配置,我们可以使用工具。如果是配置比较繁多,复杂,建议手动进行配置。
