Skip to content

1. Logback 简介

Logback 旨在作为流行log4j的后续版本项目。

Logback 的架构非常通用,在不同的情况下。 目前,logback 日志驱动分为三个模块:

  • logback-core
  • logback-classic
  • logback-access

日志驱动核心模块为其他两个模块奠定了基础 模块。经典日志驱动模块可以同化为 log4j 1.x 的显著改进版本。 此外, logback-classic 本机实现 SLF4J API 这样你就可以在日志驱动和其他日志记录框架之间来回切换。

例如: log4j 1.x 或 java.util.logging(JUL)

2. 日志输出

  • 日志: 主要记录系统出现问题时,故障排查、性能分析、安全审计。

Spring Boot 日志格式

  • spring Boot 中依赖 spring-boot-starter-web包含了 logback-classic 依赖, 默认使用的是 logback 日志框架。
xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • 如图所示:

  • Spring Boot 中的控制台输出日志内容格式如下
log
2022-10-20 08:38:39.629  INFO 16059 --- [           main] o.s.b.d.f.s.MyApplication                : Starting MyApplication using Java 1.8.0_345 on myhost with PID 16059 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2022-10-20 08:38:39.635  INFO 16059 --- [           main] o.s.b.d.f.s.MyApplication                : No active profile set, falling back to 1 default profile: "default"

# 日期和时间 => 2022-10-20 08:38:40.911
# 日志级别   => INFO
# 进程ID    => 16059
# 线程名称   => [           main]
# 源类名称   => o.s.b.w.embedded.tomcat.TomcatWebServer
# 日志内容   => Tomcat initialized with port(s): 8080 (http) // [!code focus]
2022-10-20 08:38:40.911  INFO 16059 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http) // [!code focus]
2022-10-20 08:38:40.924  INFO 16059 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-10-20 08:38:40.925  INFO 16059 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
2022-10-20 08:38:41.009  INFO 16059 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-10-20 08:38:41.010  INFO 16059 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1122 ms
2022-10-20 08:38:41.443  INFO 16059 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-10-20 08:38:41.454  INFO 16059 --- [           main] o.s.b.d.f.s.MyApplication                : Started MyApplication in 2.512 seconds (JVM running for 3.243)
2022-10-20 08:38:41.468  INFO 16059 --- [ionShutdownHook] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]

主要记录:

  • 1.日期和时间:毫秒级精度,易于分类。
  • 2.日志级别ERROR, WARN, INFO, DEBUG ,或TRACE.
  • 3.进程ID
  • 4.线程名称: 括在方括号中(控制台输出可能被截断)。
  • 5.源类名称
  • 6.日志内容

3. 文件输出

默认情况下,Spring Boot只记录到控制台,不写入日志文件。 如果除了控制台输出之外还想写入日志文件。

  • 设置 logging.file.name 属性: 写入指定的日志文件。 (或者 设置 logging.file.path属性: 写入spring.log 到指定的目录。 两者选择其中一个)
  • application.yml中添加,logging.file.name
yaml
# 日志配置
logging: 
  level:
    # mybatis 日志级别为 INFO
    mybatis: INFO
  # 文件输出
  file: 
    # 路径文件名(会自动创建)
    name: /Users/calvin/学习/01-后端开发/Java/03-框架知识/Spring Boot/spring-boot-2.x/spring-boot-example-03-logback/log/AppExample03.log // [!code focus]

创建目录展示如下:


4. 日志等级

所有支持的日志记录系统都可以在 Spring 中设置日志记录器级别Environment

  • 使用 logging.level.<logger-name>=<level>
  • <level> 设置等级 TRACE > DEBUG > INFO > WARN > ERROR > FATAL or OFF 依次输出信息将会减少
  • 如果想打印当前项目中的所有日志输出,可以使用root进行记录,使用 logging.level.root=<level>
yaml
# 日志配置
logging:
  level:
    # 项目输出为 WARN
    root: warn
    # mybatis 输出为 INFO
    mybatis: INFO
    # Spring WEB 输出为 Debug
    org.springframework.web: debug
    # Tomcat 输出为 TRACE
    tomcat: trace

5. 日志组

  • 日志组 将相关的记录器分组在一起.
yaml
# 日志配置
logging:
  # tomcat 分组
  group:
    tomcat: org.apache.catalina,org.apache.coyote,org.apache.tomcat
  level:
    # Tomcat 输出为 TRACE
    tomcat: trace

6. 自定义日志配置

Spring Boot`官方推荐优先使用带有 xxx-spring 的文件名作为你的日志配置。

  • 注意事项: 使用logback-spring.xml,而不是logback.xml,命名为logback-spring.xml的日志配置文件,将 xml 放至 src/main/resource下面
  • 配置: 使用 logging.config 配置指定文件路径, 根据您的日志记录系统, 将加载以下文件。
yaml
# 日志配置
logging: 
  level:
    # 项目输出为 WARN
    root: warn
    # mybatis 输出为 INFO
    mybatis: INFO
    # Spring WEB 输出为 Debug
    org.springframework.web: debug
    # Tomcat 输出为 TRACE
    tomcat: trace
  # 文件输出
  file:
    # 文件名
    name: /Users/calvin/学习/01-后端开发/Java/03-框架知识/Spring Boot/spring-boot-2.x/spring-boot-example-03-logback/log/${spring.application.name}
  # tomcat 分组
  group:
    tomcat: org.apache.catalina,org.apache.coyote,org.apache.tomcat
  # 自定义日志配置文件
  config: classpath:logback-spring.xml // [!code focus]

当前使用 logback-spring.xmlLogback基于三个主要类:

  • Logger: 记录器
  • Appender: 附加器,<appender>是 configuration 的子节点,是负责写日志的组件
  • Layout: 布局

详细如下:

xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">

  <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
  <property name="LOG_HOME" value="/Users/calvin/学习/01-后端开发/Java/03-框架知识/Spring Boot/spring-boot-2.x/spring-boot-example-03-logback/log/AppExample03" />

  <!-- ConsoleAppender 把日志输出到控制台 BEGIN -->
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 默认情况下,每个日志事件都会【立即刷新】到【基础输出流】。
         - 这种默认方法更安全,因为如果应用程序在没有正确关闭appender的情况下退出,则日志事件不会丢失。
         - 但是,为了显着增加日志记录吞吐量,您可能希望将immediateFlush属性设置为false -->
    <!--<immediateFlush>true</immediateFlush>-->
    <encoder>

      <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
      <charset>UTF-8</charset>

      <!-- %37():如果字符没有37个字符长度,则左侧用空格补齐 -->
      <!-- %-37():如果字符没有37个字符长度,则右侧用空格补齐 -->
      <!-- %15.15():如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符 -->
      <!-- %-40.40():如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符 -->
      <!-- %msg:日志打印详情 -->
      <!-- %n:换行符 -->
      <!-- %highlight():转换说明符以粗体红色显示其级别为ERROR的事件,红色为WARN,BLUE为INFO,以及其他级别的默认颜色。 -->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n
      </pattern>
    </encoder>

  </appender>
  <!-- ConsoleAppender 把日志输出到控制台 END -->


  <!-- RollingFileAppender 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。 INFO 级别日志 BEGIN -->
  <!-- 以下的大概意思是:
            1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是project_info.log
            2.如果日期没有发生变化,但是当前日志的文件大小超过10MB时,对当前日志进行分割 重命名
  -->
  <appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender">

    <!-- 日志文件路径和名称 -->
    <File>${LOG_HOME}_info.log</File>

    <!-- 是否追加到文件末尾,默认为true -->
    <append>true</append>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <!-- 如果命中ERROR就禁止这条日志 -->
      <onMatch>DENY</onMatch>
      <!-- 如果没有命中就使用这条规则 -->
      <onMismatch>ACCEPT</onMismatch>
    </filter>

    <!-- 有两个与RollingFileAppender交互的重要子组件。
           - RollingPolicy: 负责执行翻转所需的操作。
           - TriggeringPolicy: 将确定是否以及何时发生翻转。
         RollingFileAppender 必须同时设置 【RollingPolicy】和【TriggeringPolicy】但是,如果其RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者
    -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

      <!-- 日志文件的名字会根据【fileNamePattern】的值,每隔一段时间改变一次
           - 文件名:logs/project_info.2017-12-05.0.log
           - 注意:SizeAndTimeBasedRollingPolicy中 %i和%d令牌都是强制性的,必须存在,要不会报错
      -->
      <fileNamePattern>${LOG_HOME}_info.%d.%i.log</fileNamePattern>

      <!-- 每产生一个日志文件,该日志文件的保存期限为30天
           - ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
           - 如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd
      -->
      <maxHistory>30</maxHistory>

      <!-- 每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天也要删除多余的日志 -->
      <totalSizeCap>20GB</totalSizeCap>

      <!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成5KB看效果 -->
      <maxFileSize>10MB</maxFileSize>

    </rollingPolicy>

    <!--编码器-->
    <encoder>
      <!-- 记录日志的编码:此处设置字符集 - -->
      <charset>UTF-8</charset>
      <!-- pattern节点,用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码-->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
    </encoder>

  </appender>
  <!-- RollingFileAppender 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。 INFO 级别日志 END -->

  <!-- ERROR 级别日志 BEGIN -->
  <appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${LOG_HOME}_error.log</File>
    <append>true</append>
    <!-- 【ThresholdFilter】过滤低于指定阈值的事件。 对于等于或高于阈值的事件,ThresholdFilter将在调用其decision()方法时响应NEUTRAL。 但是,将拒绝级别低于阈值的事件 -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <!-- 低于ERROR级别的日志(debug,info)将被拒绝,等于或者高于ERROR的级别将相应NEUTRAL -->
      <level>ERROR</level>
    </filter>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
      <fileNamePattern>${LOG_HOME}_error.%d.%i.log</fileNamePattern>
      <maxHistory>30</maxHistory>
      <totalSizeCap>20GB</totalSizeCap>
      <maxFileSize>10MB</maxFileSize>
    </rollingPolicy>
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
      <charset>UTF-8</charset>
    </encoder>
  </appender>
  <!-- ERROR 级别日志 END -->

  <!-- 给定记录器的每个启用的日志记录请求都将转发到该记录器中的所有appender以及层次结构中较高的appender(不用在意level值)。
       换句话说,appender是从记录器层次结构中附加地继承的。
        - 如果将控制台appender添加到根记录器,则所有启用的日志记录请求将至少在控制台上打印。
        - 如果另外将文件追加器添加到记录器(例如L),则对L和L'子项启用的记录请求将打印在文件和控制台上。
        - 通过将记录器的additivity标志设置为false,可以覆盖此默认行为,以便不再添加appender累积
  -->

  <!-- configuration 中最多允许一个root,别的logger如果没有设置级别则从父级别root继承 -->
  <root level="INFO">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="info_log"/>
    <appender-ref ref="error_log"/>
  </root>

  <!-- 指定【项目中某个包】,当有日志操作行为时的日志记录级别
         - 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE
  -->

  <!--
     <logger name="com.calvin.spring.boot.example.logback" level="INFO">
        <appender-ref ref="info_log"/>
        <appender-ref ref="error_log"/>
     </logger>
  -->


  <!-- 利用logback输入mybatis的sql日志,
         - 注意:如果不加 additivity="false" 则此logger会将输出转发到自身以及祖先的logger中,就会出现日志文件中sql重复打印
  -->
  <!--
    <logger name="com.calvin.spring.boot.example.logback.dao" level="DEBUG" additivity="false">
      <appender-ref ref="info_log"/>
      <appender-ref ref="error_log"/>
    </logger>
  -->

  <!-- additivity=false代表禁止默认累计的行为
         - 即com.atomikos中的日志只会记录到日志文件中,不会输出层次级别更高的任何appender
   -->
  <logger name="com.atomikos" level="INFO" additivity="false">
    <appender-ref ref="info_log"/>
    <appender-ref ref="error_log"/>
  </logger>

</configuration>

7. 视频演示