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的方式

  1. <dependency>
  2. <groupId>junit</groupId>
  3. <artifactId>junit</artifactId>
  4. <version>4.13.2</version>
  5. </dependency>
  6. <!--slf4j日志门面 核心依赖-->
  7. <dependency>
  8. <groupId>org.slf4j</groupId>
  9. <artifactId>slf4j-api</artifactId>
  10. <version>1.7.32</version>
  11. </dependency>
  12. <!--
  13. logback-core是logback-classic的基础模块
  14. logback-classic已经涵盖了 logback-core,
  15. Maven有依赖传递性,会自动依赖logback-core
  16. -->
  17. <dependency>
  18. <groupId>ch.qos.logback</groupId>
  19. <artifactId>logback-classic</artifactId>
  20. <version>1.2.10</version>
  21. </dependency>

日志级别

logback有5种级别的日志输出,分别是
trace < debug < info < warn < error
默认级别:debug

  1. @Test
  2. public void testLogback(){
  3. Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  4. logger.error("========= ERROR信息 test Logback =========");
  5. logger.warn("========= WARN信息 test Logback =========");
  6. logger.info("========= INFO信息 test Logback =========");
  7. logger.debug("========= DEBUG信息 test Logback =========");
  8. logger.trace("========= TRACE信息 test Logback =========");
  9. /**
  10. *通过控制台信息,可以看到默认级别是debug。 trace级别的信息没有输出
  11. * 17:18:06.755 [main] ERROR cn.giteasy.logback.test.LogbackTest - ========= ERROR信息 test Logback =========
  12. * 17:18:06.757 [main] WARN cn.giteasy.logback.test.LogbackTest - ========= WARN信息 test Logback =========
  13. * 17:18:06.757 [main] INFO cn.giteasy.logback.test.LogbackTest - ========= INFO信息 test Logback =========
  14. * 17:18:06.757 [main] DEBUG cn.giteasy.logback.test.LogbackTest - ========= DEBUG信息 test Logback =========
  15. */
  16. }

使用配置文件

logback.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <!--
  4. <property name="" value=""></property>
  5. 配置文件通用属性,通过${name}的形式取值
  6. -->
  7. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  8. <!-- 控制台Appender -->
  9. <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
  10. <!--
  11. 输出目标的配置,
  12. System.out:以黑色字体(默认)
  13. System.err:红色字体
  14. -->
  15. <target>
  16. System.err
  17. </target>
  18. <!-- 日志输出格式 -->
  19. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  20. <pattern>${pattern}</pattern>
  21. </encoder>
  22. </appender>
  23. <!--
  24. 日志记录器配置,可以配置多个Appender,进行多方向的日志输出
  25. root => rootLogger
  26. level: 表示日志级别
  27. -->
  28. <root level="ALL">
  29. <appender-ref ref="consoleAppender"/>
  30. </root>
  31. </configuration>
  1. @Test
  2. public void testLogbackConfigFile(){
  3. Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  4. logger.error("========= ERROR信息 test Logback =========");
  5. logger.warn("========= WARN信息 test Logback =========");
  6. logger.info("========= INFO信息 test Logback =========");
  7. logger.debug("========= DEBUG信息 test Logback =========");
  8. logger.trace("========= TRACE信息 test Logback =========");
  9. }

输出日志到文件中

在实际生产环境中,我们更希望将日志信息保存到文件中

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <property name="logDir" value="D://logback_log"></property>
  4. <property name="fileName" value="logback.log"></property>
  5. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  6. <!--文件appender,默认是以追加日志的形式进行输出的-->
  7. <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
  8. <!--输出文件位置-->
  9. <file>${logDir}//${fileName}</file>
  10. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  11. <pattern>${pattern}</pattern>
  12. </encoder>
  13. </appender>
  14. <root level="ALL">
  15. <appender-ref ref="fileAppender"/>
  16. </root>
  17. </configuration>

输出日志为HTML文件格式

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <property name="logDir" value="D://logback_log"></property>
  4. <property name="htmlFileName" value="logback.html"></property>
  5. <property name="htmlPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS}%thread%-5level%c%M%L%m"></property>
  6. <!--HTML文件appender-->
  7. <appender name="htmlFileAppender" class="ch.qos.logback.core.FileAppender">
  8. <!--输出文件位置-->
  9. <file>${logDir}//${htmlFileName}</file>
  10. <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
  11. <layout class="ch.qos.logback.classic.html.HTMLLayout">
  12. <pattern>${htmlPattern}</pattern>
  13. </layout>
  14. </encoder>
  15. </appender>
  16. <root level="ALL">
  17. <!-- <appender-ref ref="fileAppender"/> -->
  18. <appender-ref ref="htmlFileAppender"/>
  19. </root>
  20. </configuration>

日志文件拆分和归档压缩

重要标签来源:
查看源码
RollingFileAppender类中找到rollingPolicy属性
SizeAndTimeBasedRollingPolicy类中找到maxFilesize属性
这些属性在类中都是以set方法的形式进行的赋值
我们在配置文件中配置的信息,其实找到的都是这些属性的set方法
在TimeBasedRollingPolicy找到

  1. static final string FNP_NOT_SET =
  2. "The FileNamePattern option must be set before using TimeBasedRollingPolicy."


只要我们要使用到日志的拆分
FileNamePattern属性是必须要使用到了

logback.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <property name="logDir" value="D://logback_log"></property>
  4. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  5. <!--可拆分归档的appender-->
  6. <appender name="rollFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
  7. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  8. <pattern>${pattern}</pattern>
  9. </encoder>
  10. <file>${logDir}/roll_logback.log</file>
  11. <!--指定拆分规则-->
  12. <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  13. <!--按照时间和压缩格式声明文件名,压缩格式gz-->
  14. <fileNamePattern>${logDir}/roll_logback.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
  15. <!--按照文件大小进行拆分-->
  16. <maxFileSize>2KB</maxFileSize>
  17. </rollingPolicy>
  18. </appender>
  19. <root level="ALL">
  20. <!-- <appender-ref ref="fileAppender"/> -->
  21. <!-- <appender-ref ref="htmlFileAppender"/> -->
  22. <appender-ref ref="rollFileAppender"/>
  23. </root>
  24. </configuration>

为了看到拆分的效果,我们使用循环测试日志输出

  1. @Test
  2. public void testFileSplit(){
  3. Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  4. for (int i = 0; i < 100; i++) {
  5. logger.error("========= ERROR信息 test Logback =========");
  6. logger.warn("========= WARN信息 test Logback =========");
  7. logger.info("========= INFO信息 test Logback =========");
  8. logger.debug("========= DEBUG信息 test Logback =========");
  9. logger.trace("========= TRACE信息 test Logback =========");
  10. }
  11. }

使用过滤器

使用过滤器,对日志进行更细粒度的控制

logback.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <property name="logDir" value="D://logback_log"></property>
  4. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  5. <!--使用过滤器,进行细粒度控制-->
  6. <appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender">
  7. <target>
  8. System.err
  9. </target>
  10. <!-- 日志输出格式 -->
  11. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  12. <pattern>${pattern}</pattern>
  13. </encoder>
  14. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  15. <level>ERROR</level>
  16. <!--高于level中设置的级别,则打印日志-->
  17. <onMatch>ACCEPT</onMatch>
  18. <!--低于level中设置的级别,则屏蔽-->
  19. <onMismatch>DENY</onMismatch>
  20. </filter>
  21. </appender>
  22. <root level="ALL">
  23. <appender-ref ref="consoleFilterAppender"/>
  24. </root>
  25. </configuration>
  1. @Test
  2. public void test06(){
  3. Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  4. logger.error("========= ERROR信息 test Logback =========");
  5. logger.warn("========= WARN信息 test Logback =========");
  6. logger.info("========= INFO信息 test Logback =========");
  7. logger.debug("========= DEBUG信息 test Logback =========");
  8. logger.trace("========= TRACE信息 test Logback =========");
  9. /**
  10. * 2022-01-28 21:27:30.784 [main] ERROR cn.giteasy.logback.test.LogbackTest test06 128 ========= ERROR信息 test Logback =========
  11. */
  12. }

异步日志

  1. @Test
  2. public void test07(){
  3. Logger logger = LoggerFactory.getLogger(LogbackTest.class);
  4. //日志输出
  5. for (int i = 0; i < 100; i++) {
  6. logger.error("========= ERROR信息 test Logback =========");
  7. logger.warn("========= WARN信息 test Logback =========");
  8. logger.info("========= INFO信息 test Logback =========");
  9. logger.debug("========= DEBUG信息 test Logback =========");
  10. logger.trace("========= TRACE信息 test Logback =========");
  11. }
  12. //业务逻辑操作
  13. for (int i = 0; i < 100; i++) {
  14. System.out.println(i);
  15. }
  16. }

按照我们当前的代码执行顺序,
代码肯定是按照从上向下的顺序执行,上面的代码完全执行完毕后,才会执行下面的业务逻辑
由此得出会出现的问题:
只要是在记录日志,那么系统本身的功能就处于一种停滞的状态,当日志记录完毕后,才会执行其他代码
如果日志记录量非常庞大的话,那么系统本身业务代码的执行效率会非常低
所以logback为我们提供了异步日志的功能

配置方式

  1. 配置异步日志

在异步日志中引入我们真正需要输出的appender

  1. <appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
  2. <appender-ref ref="consoleAppender"/>
  3. </appender>
  1. 在rootLogger中引入导步日志
    1. <root level="ALL">
    2. <appender-ref ref="asyncAppender"/>
    3. </root>
    完整配置文件logback.xml ```xml <?xml version=”1.0” encoding=”UTF-8” ?>
  1. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  2. <!-- 控制台Appender -->
  3. <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
  4. <target>
  5. System.err
  6. </target>
  7. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  8. <pattern>${pattern}</pattern>
  9. </encoder>
  10. </appender>
  11. <!--异步日志Appender-->
  12. <appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
  13. <appender-ref ref="consoleAppender"/>
  14. </appender>
  15. <root level="ALL">
  16. <appender-ref ref="asyncAppender"/>
  17. </root>

  1. <a name="P03D6"></a>
  2. #### 输出效果
  3. ```java
  4. 2022-02-12 19:10:25.437 [main] WARN cn.giteasy.logback.test.LogbackTest test07 191 ========= WARN信息 test Logback =========
  5. 0
  6. 2022-02-12 19:10:25.437 [main] ERROR cn.giteasy.logback.test.LogbackTest test07 190 ========= ERROR信息 test Logback =========
  7. 1
  8. 2022-02-12 19:10:25.437 [main] WARN cn.giteasy.logback.test.LogbackTest test07 191 ========= WARN信息 test Logback =========
  9. 2

所谓异步日志的原理是:
系统会为日志操作单独的分配出来一个线程,主线程会继续向下执行
线程1:系统业务代码执行
线程2:打印日志
两个线程争夺CPU的使用权
在实际项目开发中,越大的项目对于日志的记录就越庞大,为了保证系统的执行效率,异步日志是不错的选择。

自定义Logger

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <configuration>
  3. <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %c %M %L %m%n"></property>
  4. <!-- 控制台Appender -->
  5. <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
  6. <target>
  7. System.err
  8. </target>
  9. <!-- 日志输出格式 -->
  10. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  11. <pattern>${pattern}</pattern>
  12. </encoder>
  13. </appender>
  14. <!--
  15. 自定义Logger
  16. additivity="false" 表示不继承rootLogger
  17. -->
  18. <logger name="cn.giteasy" level="warn" additivity="false">
  19. <appender-ref ref="consoleAppender"></appender-ref>
  20. </logger>
  21. </configuration>

关于Logback的补充

  1. 异步日志
    可配置属性:
    1. <discardingThreshold>0</discardingThreshold>
    当队列的剩余容量小于这个阈值的时候,当前日志的级别 trace、debug、info这3个级别的日志将被丢弃
    设置为0,说明永远都不会丢弃trace、debug、info这3个级
  1. <queueSize>256</queueSize>
  1. 配置队列的深度,这个值会影响记录日志的性能,默认值256<br /> <br /> 关于这两个属性,一般情况下,我们使用默认值即可,不要乱配置,会影响系统性能,了解其功能即可
  1. 配置文件转换
    关于不同的日志实现,配置文件也是不同的:
    log4j一般使用的是properties属性文件
    logback使用的是xml配置文件
    如果我们遇到了一种需求,需要将正在使用的log4j,替换为logback,应该如何处理?
    使用转换工具:
    访问logback官网
    找到log4j.properties转换器 (https://logback.qos.ch/translator/)
    只有是二者兼容的配置,才会被翻译
    如果是log4j独立的技术,logback没有,或者是有这个技术但是并不兼容转义
    那么这个工具则不会为我们进行转换,如果是遇到简单的配置,我们可以使用工具。如果是配置比较繁多,复杂,建议手动进行配置。