参考博客
NO.1 Spring Boot干货系列:(七)默认日志logback配置解析 【作者:嘟嘟MD】
NO.2 Java日志框架SLF4J和log4j以及logback的联系和区别
NO.3 SLF4J和Logback和Log4j和Logging的区别与联系
1. 为什么需要日志
- 对于程序的运行状态进行监控和行为分析
- 当程序运行出错时,快速定位问题的位置
2. 日志能做什么
- 将日志消息打印到控制台、输出到文件等
- 日志内容可以做格式化,如纯文本、XML、 HTML格式等
- 对不同类、不同包、不同等级日志可以灵活输出到不同的文件中
- 可以对日志进行分级,例如测试环境使用debug级别日志,生成环境使用error级别日志
3. 体系简单介绍
3.1 日志接口框架
常见日志接口框架有两个:
- JCL(Jakarta Commons Logging),又叫做 Apache Commons Logging
- SLF4J(Simple Logging Facade for JAVA)
日志接口框架只提供了供用户调用的接口,并没有给出具体实现
3.2 日志实现框架
- JUL(java.util.logging):Java 内置的日志模块,能满足基本的日志需要
- Log4j、Log4j2:经典的日志解决方式
- Logback:Log4j的替代产品,出自同一个作者。须要配合日志框架SLF4j使用
- slf4j-nop:no-operation
- slf4j-simple:simple
3.3 日志接口框架和日志实现框架
其中,log4j和JUL(java.util.logging)因为没有直接实现slf4j接口框架,所以需要相应的适配器(slf4j-log12、slf4j-jdk14)来将slf4j接口框架和其进行绑定。而logback、slf4j-simple、slf4j-nop直接实现了slf4j接口框架,所以不需要适配器。
3.4 推荐使用 “日志接口框架+日志实现框架”
在使用日志时,可以不配合日志接口框架而直接使用日志实现框架,但是并不建议这样使用。
假设项目中已经使用了log4j,而我们此时加载了一个类库,而这个类库依赖另一个日志实现框架。这个时候我们就需要维护两个日志实现框架,这是一个非常麻烦的事情。但是如果配合使用slf4j就不同了,由于应用调用的是日志接口方法,与底层日志实现是无关的,因此可以任意更换具体的日志实现框架。
4. 日志级别
日志级别从低到高分别是
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
级别简单介绍
- ALL:最低等级。用于打开所有日志记录
- TRACE:很低的日志级别,一般不会使用
- DEBUG:通常用在本地调试或测试环境上,打印一些调试的信息
- INFO:通常用在生产环境上,打印一些重要的监测信息
- WARN:表明会出现潜在错误的情形,有些信息不是错误信息,但需要给出提示
- ERROR:指出虽然发生错误事件,但仍然不影响系统的继续运行
- FATAL:每个严重的错误事件将会导致应用程序的退出
- OFF:最高等级的,用于关闭所有日志记录
大多数日志框架推荐常用的级别是,DEBUG、INFO、WARN、ERROR。
如果将log level设置在某一个级别上,那么比此级别优先级高的log都会打印出来,比此级别优先级低的log都不会打印出来。
5. springboot项目中使用logback日志
如何将日志加入到项目中?下面以在 springboot 项目中引入 logback 日志为例。
5.1 默认情况下
Spring框架使用的是Jakarta Commons Logging API (JCL)。
Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台(即,日志默认级别为INFO)。
5.2 日志信息介绍
- 时间日期:精确到毫秒
- 日志级别:ERROR, WARN, INFO, DEBUG、TRACE
- 进程ID
- 分隔符:--- 标识实际日志的开始
- 线程名:方括号括起来(可能会截断控制台输出)
- Logger名:通常使用源代码的类名
- 实际日志内容
5.3 引入日志依赖
在 springboot 项目中,只要添加了 spring-boot-starter-logging 依赖,则应用将自动使用 logback 作为应用日志框架。
通过查看依赖可知,spring-boot-starter 已经包含了 spring-boot-starter-logging。而 spring-boot-start-web、mybatis-spring-boot-starter、spring-booter-start-jdbc 等都包含了 spring-boot-starter-logging,所以并不需要直接依赖 spring-boot-starter-logging。
5.4 在 application.properties 配置文件配置日志
假设项目所在目录为 D:\Projects\Test。
- logging.file
该属性用来指定日志文件路径和文件名(路径可以是绝对路径,也可以是相对路径)。
logging.file=logs\\my.log
# 如果配置的是相对路径,则会在项目根目录生成指定日志文件
# D:\Projects\Test\logs\my.log
##############
logging.file=E:\\logs\\my.log
# 如果配置的是绝对路径,则生成指定日志文件
# E:\logs\my.log
# 如果logs目录不存在,则会自动创建该目录。
# 如果该目录下已存在同名文件,则会在原文件后继续追加当前日志内容。
- logging.path
该属性用来指定日志文件路径,在指定路径下生成默认日志文件 spring.log(只能指定目录,不能指定文件名)。
logging.path=E:\\logs
# E:\logs\spring.log
# 如果logs目录不存在,则会自动创建该目录。
# 如果该目录下已存在spring.log,则会在原文件后继续追加当前日志内容。
- 如果同时配置 logging.file 和 logging.path,则只有 logging.file 配置会生效。
5.5 logback.xml 与 logback-spring.xml
- 根据不同的日志系统,使用下面这些默认的命名规则,并且放在 src/main/resources 下面,日志文件就能被自动的加载。
> logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
> log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
> log4j2:log4j2-spring.xml, log4j2.xml
> JUL(java util logging):logging.properties
- 如果不想使用上面的默认命名规则(比如,针对不同profile使用不同的日志配置名称进行区分),则可以在 spring 配置文件中使用 logging.config 属性指定自定义日志名称。
logging.config=classpath:logging-dev.xml
- 使用 logback 日志时,推荐使用 logback-spring.xml 文件名代替 logback.xml 进行配置。因为 logback.xml 加载早于application.properties,则如果想要在 logback.xml 中使用 application.properties 配置文件中的变量就无法实现了,而改成 logback-spring.xml 就不会有这个问题了。
5.6 logback-spring.xml 配置文件示例
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback</contextName>
<property name="logPath" value="E:/logs" />
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/info.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="org.apache.ibatis" level="info"/>
<logger name="org.mybatis.spring" level="info"/>
<logger name="com.baomidou.mybatisplus" level="info"/>
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</configuration>
5.7 配置文件解析
5.7.1 <configuration>
配置文件的根节点
<configuration scan="true" scanPeriod="60 seconds" debug="false">
- scan:设置为true时,如果配置文件发生改变,将会被重新加载,默认值为true。
- scanPeriod:监测配置文件是否有修改的监测时间间隔,如果没有给出时间单位,默认单位是毫秒。只有当scan为true时,此属性生效。默认的时间间隔为1分钟。
- debug:设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
5.7.2 <contextName>
上下文名称
<contextName>logback</contextName>
每个 logger 都关联到 logger 上下文,默认上下文名称为 “default”。可以设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改,可以通过 %contextName 来打印日志上下文名称。
5.7.3 <property>
定义变量
<property name="logPath" value="E:/logs" />
- name:变量的名称
- value:变量的值
- 定义好的变量会保存到 logger 上下文中,可以使 ${varName} 来引用变量
5.7.4 <appender>
输出策略及其他配置
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logPath}/info_%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
解析
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
- name:节点名称,通过该值可以引用该节点的配置(后面再说)
- class:指定日志的输出策略,控制台输出(ch.qos.logback.core.ConsoleAppender),文件输出(ch.qos.logback.core.rolling.RollingFileAppender)
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
- filter.class:系统定义的拦截器(ch.qos.logback.classic.filter.ThresholdFilter)
- level:设置过滤级别。如果设置为 debug,则比 debug 级别低的(不包括debug级别)日志都不会打印到控制台上(或输出到日志文件中)。
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
可以直接指定日志格式,日志格式解析如下:
- %d{HH: mm:ss.SSS} —— 日志输出时间
- %contextName —— 日志上下文名称
- %thread —— 输出日志的进程名字,这在Web应用以及异步任务处理中很有用
- %-5level —— 日志级别,并且使用5个字符靠左对齐
- %logger{36} —— 日志输出者的名字
- %msg —— 日志消息
- %n —— 平台的换行符
示例
也可以设置彩色日志格式,但彩色日志格式要引入渲染类的依赖:
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
示例
彩色日志格式建议只用于控制台日志输出,因为如果在文件日志输出中采用彩色日志,会出现乱码。
<file>${logPath}/info.log</file>
<!-- 或 -->
<file>E:/logs/info.log</file>
指定日志文件位置,在文件输出策略中进行该配置。
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logPath}/info_%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
日志记录器的滚动策略。随着应用的运行时间越来越长,日志也会增长的越来越多,将他们输出到同一个文件并不合理。
- fileNamePattern:定义了日志的切分方式。如上述配置,把每一天的日志归档到一个文件中,当一个文件大小到了100M,就生成一个新的文件,后缀加1。
- maxFileSize:每个日志文件的上限大小。如上述配置,到了100M就生成一个新的日志文件
- maxHistory:保留最近60天的日志
- totalSizeCap:总日志文件大小上限,到了上限就删除旧的日志文件
示例
5.7.5 <root>
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性。
- level:设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。默认是DEBUG。
- appender-ref:引入 appender 节点配置,ref 指定 <appender> 的 name 属性值
5.7.6 <logger>
<logger name="org.apache.ibatis" level="info"/>
<logger name="org.mybatis.spring" level="info"/>
<logger name="com.baomidou.mybatisplus" level="info"/>
用来设置某一个包或者具体的某一个类的日志打印级别。
- name:指定受此 logger 约束的某一个包或者具体的某一个类
- level:设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特殊值 INHERITED或者同义词 NULL,代表强制执行上级的级别。如果未设置此属性,那么当前loger将会继承上级的级别。
- addtivity:是否向上级 logger 传递打印信息,默认是true。
5.7.7 <springProfile>
据不同环境(profile)来定义不同的日志输出。
<!-- 测试环境+开发环境. 多个使用逗号隔开. -->
<springProfile name="test,dev">
<logger name="com.test.controller" level="info" />
</springProfile>
<!-- 生产环境. -->
<springProfile name="prd">
<logger name="com.test.controller" level="error" />
</springProfile>
因为前面说过,要使用 spring 配置文件中的变量值(例如:当前环境变量profile),需要定义日志文件名为 logback-spring.xml 而不是 logback.xml。所以,要使用这个配置,需要定义日志文件名为 logback-spring.xml。
5.8 使用日志
方式一(LoggerFactory):
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test{
private static final Logger log = LoggerFactory.getLogger(Test.class);
public void test(){
log.trace("===================trace=============");
log.debug("===================debug=============");
log.info("===================info=============");
log.warn("===================warn=============");
log.error("===================error=============");
}
}
方式二(使用lombox注解):
引入lomobx 的 maven依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
使用注解
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Test{
public void test(){
log.trace("===================trace=============");
log.debug("===================debug=============");
log.info("===================info=============");
log.warn("===================warn=============");
log.error("===================error=============");
}
}