日志
1.日志级别
1.常见的日志级别
-
几种常见的日志级别由低到高分别为
- trace:追踪
TRACE 级别是最低的日志级别,用于追踪程序的详细执行过程。它通常用于输出非常详细的调试信息,例如方法的输入参数、变量的值等。TRACE 级别的日志通常用于排查问题和调试应用程序。
- debug:调试
DEBUG 级别用于输出调试信息,以帮助开发人员进行应用程序的调试和排查。它通常包括关键变量的值、方法的执行流程等详细信息。DEBUG 级别的日志在开发和测试阶段非常有用,但在生产环境中应谨慎使用,以避免过多的日志输出。
- info:信息
INFO 级别用于输出应用程序的关键信息,如应用程序启动、关键操作的成功完成等。它提供了应用程序正常运行时的重要信息,通常用于监控应用程序的状态和运行情况。
- warn:警告
WARN 级别用于输出警告信息,表示潜在的问题或不符合预期的情况。警告信息通常不会导致应用程序的中断或错误,但可能需要引起注意和处理,以避免潜在的错误发生。
- error:错误
ERROR 级别用于输出错误信息,表示应用程序遇到了无法继续执行的错误。错误信息通常包括异常堆栈跟踪、错误码等详细信息。ERROR 级别的日志表示应用程序遇到了严重的问题,可能需要立即采取措施进行修复。
- fatal:致命
FATAL 级别是最高的日志级别,用于输出致命错误信息。它表示应用程序遇到了无法恢复的严重错误,导致应用程序无法继续执行。FATAL 级别的日志通常用于记录导致应用程序崩溃或无法正常运行的异常情况。
debug: true logging: level: web: debug
2.日志框架
1.常见的日志框架
-
log4j
Log4j 是一个强大的、灵活的日志框架,广泛应用于 Java 应用程序。它提供了丰富的日志记录功能,包括多种日志级别、日志格式化、输出目标等。Log4j 具有高度可配置性,可以通过配置文件或编程方式进行设置。
-
logback
Logback 是由 log4j 创始人设计的一种日志框架,作为 log4j 的继承者。它提供了高性能和灵活的日志记录功能,支持多种日志级别、日志格式和输出目标。Logback 具有丰富的配置选项和插件支持,被广泛应用于各种 Java 应用程序。
-
log4j2
Log4j 2 是 Apache Log4j 日志框架的最新版本。它提供了高度可配置的日志记录功能,支持多种日志级别、日志格式和输出目标。Log4j 2 具有更好的性能和扩展性,并引入了许多新特性,如异步日志记录、插件架构等。
-
java.util.logging(JUL)
java.util.logging,简称 JUL,是 Java 平台自带的标准日志框架。它提供了基本的日志功能,可以在大多数 Java 环境中直接使用,无需额外的依赖。JUL 提供了日志记录器、处理器和格式化器等组件,可以通过配置文件或编程方式进行配置。
-
SLF4J
SLF4J 是一个日志门面(Logging Facade)框架,它提供了统一的日志接口,可以与不同的日志实现(如 Logback、Log4j、JUL 等)进行集成。SLF4J 允许开发人员在代码中使用统一的日志 API,而无需关心具体的日志实现。
2.SpringBoot默认使用的日志框架
-
SpringBoot默认使用的日志框架为Logback
Logback的依赖为
<!--Logback依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
因为是默认的日志系统,因此不需要再添加依赖
从图中可以看出,输出的日志默认格式为
1. 时间:精确到ms
2. 日志级别
3. 进程ID
4. 分隔符:"-"标识日期的开始
5. 线程名:\[ ]内的
6. Logger名:通常为类名
7. 日志内容
3.使用日志
1.代码中如何使用日志
-
第一种
在代码中添加
private static final Logger logger = LoggerFactory.getLogger(testController.class); testController可以替换为当前类的类名
-
第二种
可以使用lombok
lombok依赖
<!--lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
我们只需要在类上添加@Slf4j
package jiasen; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.RestController; @SpringBootTest @RestController @Slf4j public class testController { @Test public void testLog() { log.info("info"); log.debug("debug"); log.error("error"); log.warn("warn"); } }
测试结果
2.如何定制日志级别
-
Spring Boot中默认的日志级别为INFO,但是可以自己定制日志级别,如下
#日志配置 logging: level: root: debug
root可替换为
> 1. root:根纪录器
>
> 根记录器是日志系统的顶级记录器,它是所有其他记录器的父记录器,通过设置根记录器的日志级别,可以控制整个应用程序的日志输出.
>
> 2. web:包记录器
>
> web是一个包记录器,用于控制与web相关类的日志输出,通过设置web的日志级别,可以独立的控制与Web请求,Web组件,框架相关的日志输出.
>
> 3. sql:包记录器
>
> sql包记录器,用于控制与Sql数据库访问相关的类的日志输出,通过设置sql的日志级别,可以独立的控制与Sql查询,事务,数据库操作相关的日志输出.
这样就可以将所有的日志级别改为DEBUG
SpringBoot还支持package级别的日志级别调整,格式为
```yaml
#日志配置
logging:
level:
#包名
jiasen:
entity: info
```
可以直接指定项目中具体的某个包的日志格式
3.日志输出到文件中
-
Spring Boot中日志默认是输出到控制台中,但是在生产环境中是不可取的,因此需要配置日志输出到日志文件中
logging: file: #指定日志文件的路径 path: D:/logs #日志的文件名 name: SpringBoot.log #文件日志的最大大小 max-size: #指定要保留的日志文件的最大数量 max-history: #指定应用程序启动时是否清理历史日志文件 clean-history-on-start:
属性 | 含义 |
---|---|
path | 指定输出日志的路径 |
name | 指定输出日志的文件名 |
max-size | 日志文件的最大大小 |
max-history | 保留日志文件的最大数量 |
clean-history-on-start | 是否在启动时删除历史日志文件 |
4.定制日志格式
-
日志的格式有两个配置,分别为控制台的输出格式和文件中的输出格式
logging: pattern: console: "%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n" #控制台的输出格式 logging: pattern: file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n" #日志文件的输出格式
常见格式
%d{format}
:日期和时间,可以使用指定的日期格式。例如,%d{yyyy-MM-dd HH:mm:ss}
将以 "年-月-日 时:分:秒" 的格式输出日期和时间。%p
:日志级别(如 DEBUG、INFO、WARN、ERROR 等)。%t
:线程名。%c
:记录器(类)的名称。%m
:日志消息。%n
:换行符。%ex
:输出异常栈轨迹。%X{key}
:输出指定键的线程上下文变量。%d
:日期时间%thread
:输出日志的进程名称%-5level
:日志级别%logger
:日志输出者的名称%msg
:日志消息
使用修改过后自定义的控制台输出格式
5.自定义日志配置
-
SpringBoot官方文档指出,根据不同的日志系统,可以按照如下的日志配置文件名就能够被正确加载

> * 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
> * JDK (Java Util Logging) :logging.properties
2. SpringBoot官方推荐使用带有-spring的文件名作为你的日志配置,所以只需要在src/resources
文件夹下创建logback-spring.xml即可
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 定义日志存放目录 -->
<property name="logPath" value="logs"/>
<!-- 日志输出的格式-->
<property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} %L %M -
%msg%xEx%n"/>
<contextName>logback</contextName>
<!--输出到控制台 ConsoleAppender-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<!--展示格式 layout-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${PATTERN}</pattern>
</layout>
<!--过滤器,只有过滤到指定级别的日志信息才会输出,如果level为ERROR,那么控制台只会输出
ERROR日志-->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <level>ERROR</level>-->
<!-- </filter>-->
</appender>
<!--正常的日志文件,输出到文件中-->
<appender name="fileDEBUGLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
所以我们使用下面的策略,可以避免输出 Error 的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>Error</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logPath}/log_demo.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个
磁盘空间-->
<FileNamePattern>${logPath}/log_demo_%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<!--<totalSizeCap>1GB</totalSizeCap>-->
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<!--输出ERROR日志到指定的文件中-->
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>Error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logPath}/error.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个
磁盘空间-->
<FileNamePattern>${logPath}/error_%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<!--<totalSizeCap>1GB</totalSizeCap>-->
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<!--指定最基础的日志输出级别-->
<root level="DEBUG">
<!--appender将会添加到这个loger-->
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileDEBUGLog"/>
<appender-ref ref="fileErrorLog"/>
</root>
<!-- 定义指定package的日志级别-->
<logger name="org.springframework" level="DEBUG"></logger>
<logger name="org.mybatis" level="DEBUG"></logger>
<logger name="java.sql.Connection" level="DEBUG"></logger>
<logger name="java.sql.Statement" level="DEBUG"></logger>
<logger name="java.sql.PreparedStatement" level="DEBUG"></logger>
<logger name="io.lettuce.*" level="INFO"></logger>
<logger name="io.netty.*" level="ERROR"></logger>
<logger name="com.rabbitmq.*" level="DEBUG"></logger>
<logger name="org.springframework.amqp.*" level="DEBUG"></logger>
<logger name="org.springframework.scheduling.*" level="DEBUG"></logger>
<!--定义com.xxx..xx..xx包下的日志信息不上传,直接输出到fileDEBUGLog和fileErrorLog这个两个appender
中,日志级别为DEBUG-->
<logger name="com.xxx.xxx.xx" additivity="false" level="DEBUG">
<appender-ref ref="fileDEBUGLog"/>
<appender-ref ref="fileErrorLog"/>
</logger>
</configuration>
```
1. configuration:这是根节点,其中的属性有
* scan:当前属性设置为true时,配置文件如果发生变化,将会重新加载,默认值为true
* scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位为ms,当scan设置为true时,此属性生效,默认的时间间隔为1分钟
* debug :当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。 默认值为false。
2. root节点
* 这是一个必须节点,用来指定基础的日志级别,只有一个 level 属性,默认值是 DEBUG 。 该节点可以包含零个或者多个元素,子节点是 appender-ref ,标记这个 appender 将会添加到这个logger 中。
3. contextName节点
* 标识一个上下文名称,默认为default,一般用不到
4. property节点
* 标记一个上下文变量,属性有name和value,定义变量之后可以使用 \${} 来获取。
5. appender节点
* 用来格式化日志输出节点,有两个属性 name 和 class ,class用来指定哪种输出策略,常用就是`控制台 输出`策略和`文件输出`策略。
* 这个节点很重要,通常的日志文件需要定义三个appender,分别是控制台输出,常规日志文件输出,异 常日志文件输出。
* 该节点有几个重要的子节点,如下:
> 1. filter :日志输出拦截器,没有特殊定制一般使用系统自带的即可,但是如果要将日志分开,比 如将ERROR级别的日志输出到一个文件中,将除了 ERROR 级别的日志输出到另外一个文件中,此 时就要拦截 ERROR 级别的日志了。
> 2. encoder : 和pattern节点组合用于具体输出的日志格式和编码方式。
> 3. file : 节点用来指明日志文件的输出位置,可以是绝对路径也可以是相对路径
> 4. rollingPolicy : 日志回滚策略,在这里我们用了TimeBasedRollingPolicy,基于时间的回滚策略, 有以下子节点fileNamePattern,必要节点,可以用来设置指定时间的日志归档。
> 5. maxHistory : 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,,例如设置为 30的话,则30天之后,旧的日志就会被删除
> 6. totalSizeCap : 可选节点,用来指定日志文件的上限大小,例如设置为3GB的话,那么到了这个 值,就会删除旧的日志
6. logger节点
* 可选节点,用来具体指明包的日志输出级别,它将会覆盖root的输出级别。
* 该节点有几个重要的属性如下:
> 1. name :指定的包名
> 2. level :可选,日志的级别
> 3. addtivity :可选,默认为true,将此logger的信息向上级传递,将有root节点定义日志打印。 如果设置为false,将不会上传,此时需要定义一个 appender-ref 节点才会输出。
如果不想使用Spring Boot推荐的名字,想要修改,只需要在配置文件中指定配置文件名即可
```yaml
logging:
#自定义文件名称
config: classpath:logback-spring.xml
```
4.切换日志
1.日志门面
日志门面是一个抽象的接口或类,它定义了一组用于记录日志的方法,例如记录调试信息、错误消息等。它提供了一种统一的方式来编写日志记录代码,而不依赖于具体的日志实现。使用日志门面可以使我们的代码与特定的日志实现解耦,从而更容易切换和配置不同的日志实现。
2.日志实现
日志实现是实际执行日志记录的具体库或框架。它实现了日志门面提供的接口,并负责将日志消息写入到适当的目标,比如控制台输出或日志文件。常见的日志实现包括Logback、Log4j、SLF4J等。选择合适的日志实现可以根据需求进行配置,例如定义日志输出的格式、级别、存储位置等。
日志门面是老板,日志实现就是员工,
3.如何做到无感知切换
SLF4j是日志门面,无论什么框架都是基于SLF4j的api实现,因此无论是代码打印日志还是 Lombok注解形式打印日志,都要使用的SLF4j的API,而不是日志框架的API,这样才能解耦,做到无 感知。因为最终切换的框架只是对于SLF4j的实现,并不是切换SLF4j。
4.如何实现
-
引入依赖
<!--log4j2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
-
排除掉SpringBoot的默认日志实现Logback
<!--web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--排除spring默认的日志框架logback--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency>
-
指定配置文件
Spring Boot官方文档给出了默认的两个log4j2的配置名称,两个名称为
log4j2-spring.xml
和log4j2.xml
推荐使用`log4j2-spring.xml`,因为Spring Boot会做一些扩展
注意:
如果不想使用默认的配置名称,需要在application.yaml中指定新的配置名称
```yaml
logging:
config: classpath:log4j2-spring.xml
```
5.日志如何配置
其实log4j2的一些配置和logback类似
<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看
到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5">
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--变量配置-->
<Properties>
<!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:
日志消息,%n是换行符-->
<!-- %logger{36} 表示 Logger 名字最长36个字符 -->
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
%msg%n" />
<!-- 定义日志存储的路径 -->
<property name="FILE_PATH" value="更换为你的日志路径" />
<property name="FILE_NAME" value="更换为你的项目名" />
</Properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${LOG_PATTERN}"/>
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}"/>
</File>
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入
按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log"
filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入
按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log"
filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入
按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log"
filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
</appenders>
<!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
<!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
<logger name="org.mybatis" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<!--监控系统信息-->
<!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的
appender里输出。-->
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>
上面的配置如果需要使用的话,需要修改掉全局变量的日志路径和项目名称
<property name="FILE_PATH" value="更换为你的日志路径" />
<property name="FILE_NAME" value="更换为你的项目名" />