目录
- 1、前提说明
- 2、引入依赖、将logback配置文件打到classes下
- 3、使用说明
- 4、代码用法
- 5、使用案例
- 6、参考博客
1、前提说明
- 默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台。
- Slf4j(Simple Logging Facade For Java):它是一个针对于各类Java日志框架的统一外观抽象(门面模式)。
- 日志级别:
TRACE
<DEBUG
<INFO
<WARN
<ERROR
<FATAL
,如果设置为WARN
,则低于WARN
的信息都不会输出。
2、引入依赖、将logback配置文件打到classes下
2.1、引入依赖
java
<!-- 启动依赖中包含了spring-boot-starter-logging依赖,进而包含了logback相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入@Slf4j注解,方便使用log.XXX()方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.2、将logback配置文件打到classes下
xml
<!-- 在 -->
<build>
<resources>
<!-- 将resources目录中的配置文件统统打包 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!-- 将代码目录中的xml文件一并打包,针对将included标签引入的配置文件放在依赖jar包代码层的情况 -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
3、使用说明
3.1、配置文件名称和位置
名称
- logback-spring.xml
- logback-spring.groovy
- logback.xml
- logback.groovy
- 自定义文件名
说明1:
Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项(下面会提到)。
说明2:
在application.properties配置文件里面通过logging.config
属性指定自定义的名字,例如 logging.config=classpath:logging-config.xml
位置:
在src > main > resources
目录下面,例如:
3.2、常规用法
3.2.1、property标签(普通变量)
xml
# 语法
<property name="变量名" value="变量值"/>
# 使用范围
在所有logback的xml文件中都可以使用,包括使用include标签引入的文件中;
可以把一个项目中所有位置的logback的xml文件内容理解成一个合体大文件,
所以变量可以在各个文件中随意定义、随意使用,但是注意别重复了。
# 定义示例
<!-- 定义服务名称 -->
<property name="app_name" value="item"/>
<!-- 定义日志输出格式 -->
<property name="log.pattern" value="%date{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{56}.%method | %L : %msg%n" />
# 使用示例(即${变量名},此时变量LOG_PATH代表"/opt/log/item")
<!-- 在其他变量中使用 -->
<property name="LOG_PATH" value="/opt/log/${app_name}"/>
<!-- 将日志按照定义的日志输出格式输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
3.2.2、springProperty标签(spring变量)
xml
# 语法
<springProperty name="变量名" value="spring配置属性"/>
# 使用范围
在spring环境中使用
# 定义示例
<!-- 定义服务名称 -->
<springProperty name="app_name" source="spring.application.name"/>
<!-- 定义端口 -->
<springProperty name="server_port" source="server.port" />
# 使用示例(即${变量名},此时变量LOG_PATH代表"/opt/log/item")
<!-- 定义日志文件输出路径 -->
<property name="LOG_PATH" value="/opt/log/${app_name}"/>
<!-- 定义日志输出格式 -->
<property name="log.pattern" value="%date{yyyy-MM-dd HH:mm:ss.SSS} | ${app_name} | %-5level | %thread | %logger{56}.%method | %L : %msg%n" />
3.2.3、conversionRule标签(通过代码来自定义数据规则)
xml
# 语法(该变量的值指代该类中convert方法的返回值)
<conversionRule conversionWord="变量名" converterClass="ClassicConverter类的子类全路径"/>
# 定义示例
<!-- 获取本地服务的IP,LogIpConfig类的详细代码在下面 ->
<conversionRule conversionWord="app_ip" converterClass="com.atguigu.base.config.LogIpConfig"/>
# 使用示例(即$变量名,此时变量$app_ip代表真实ip)
<!-- 定义日志输出格式 -->
<property name="log.pattern" value="%date{yyyy-MM-dd HH:mm:ss.SSS} | %app_ip | ${app_name} | %-5level | %thread | %logger{56}.%method | %L : %msg%n" />
# 打印结果
2024-12-19 22:54:32.466 | 192.168.1.6 | item | INFO | main | com.atguigu.item.init.SystemInit.afterPropertiesSet | 29 : 测试......
LogIpConfig:
java
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
/**
* 打印ip类
* @author 明快de玄米61
* @date 2024/12/9 9:15
**/
public class LogIpConfig extends ClassicConverter {
private static final Logger logger = LoggerFactory.getLogger(LogIpConfig .class);
private static String webIP;
static {
try {
webIP = InetAddress.getLocalHost().getHostAddress();
} catch (Exception e) {
logger.error("获取日志Ip异常", e);
webIP = null;
}
}
@Override
public String convert(ILoggingEvent event) {
return webIP;
}
}
3.2.4、include标签(引入配置文件)
通过include标签可以将依赖jar包中的配置文件引入当前项目,这样所有配置文件内容将组装成一个合体大文件,不过注意被引入文件中标签的书写方式
3.2.5、root标签(定义全局的日志输出情况)
作用:
- 定义日志输出级别(日志级别:
TRACE
<DEBUG
<INFO
<WARN
<ERROR
<FATAL
) - 引入自定义日志输出规则(等会介绍具体输出规则的定义方式)
示例:
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
......
<!-- 控制打印输出的内容 -->
<root level="INFO">
<!-- 打印ERROR级别日志到文件中 -->
<appender-ref ref="FILE_ERROR"/>
<!-- 打印WARN级别日志到文件中 -->
<appender-ref ref="FILE_WARN"/>
<!-- 打印INFO级别日志到文件中 -->
<appender-ref ref="FILE_INFO"/>
<!-- 打印level以及以上级别的日志到控制台中-->
<appender-ref ref="STDOUT"/>
</root>
</configuration>
3.2.5、logger标签(定义特定包或者类的日志输出情况)
参数说明:
- name(必填):指定受此logger约束的某一个包或者具体的某一个类
- level(非必填,默认值:继承root标签的level):日志级别
- additivity(非必填,默认值:true):是否向上级logger传递打印信息,也就是让上级也去处理该打印结果,当然与上级的level级别无关
作用:
- 定义特定包或者类的日志输出级别(日志级别:
TRACE
<DEBUG
<INFO
<WARN
<ERROR
<FATAL
) - 引入自定义日志输出规则(等会介绍具体输出规则的定义方式)
示例:
logback-msg.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<included>
<!-- DEBUG日志记录器,日期滚动记录 -->
<appender name="MSG_PRODUCER_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/mq/producer/log.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/mq/producer/log-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过20M,若超过20M,日志文件会以索引0开始, 命名日志文件,例如log_error_2020-20-20_0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>20MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<MaxHistory>7</MaxHistory>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<logger name="com.atguigu.msg" level="DEBUG" additivity="false">
<appender-ref ref="MSG_PRODUCER_FILE" />
</logger>
</included>
在上述logback-msg.xml
所在的项目msg
代码中有这样一行代码:
java
log.debug("消息被发送到kafka了");
如果按照logback文件配置情况,将会把日志信息输出到文件中
由于additivity是false,所以日志信息不会向上传递,假设上级日志配置文件中root标签的level是INFO级别,那么这种情况下日志不会输出的
如果additivity是true,或者不设置(默认是true),依然假设上级日志配置文件中root标签的level是INFO级别,并且上级日志配置文件中会将所有日志信息输出到控制台,此时日志将在控制台输出,如下图:
3.2.6、springProfile标签(根据spring环境输出日志)
根据不同环境(prod:生产环境,test:测试环境,dev:开发环境)来定义不同的日志输出,在 logback-spring.xml中使用 springProfile 节点来定义,方法如下:
文件名称不是logback.xml,想使用spring扩展profile支持,要以logback-spring.xml命名
xml
<!-- 测试环境+开发环境. 多个使用逗号隔开. -->
<springProfile name="test,dev">
<logger name="com.dudu.controller" level="info" />
</springProfile>
<!-- 生产环境. -->
<springProfile name="prod">
<logger name="com.dudu.controller" level="ERROR" />
</springProfile>
可以启动服务的时候指定 profile (如不指定使用默认),如指定prod 的方式为:
bash
java -jar xxx.jar --spring.profiles.active=prod
3.2.7、appender标签(定义日志输出方式)
3.2.7.1、日志格式
一般情况下,通过pattern
标签定义日志输出格式,如下:
xml
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{56} | %L : %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
现在来讲解一下上面日志输出格式的含义:
- %date{yyyy-MM-dd HH:mm:ss.SSS}:年-月-日 时:分:秒 毫秒
- %-5level:日志级别,一共占用5个字符,并且靠左对齐
- %thread:线程名称
- %logger{56}:类全路径名称
- %L:日志所在代码的行数
- %msg:日志内容
- %n:换行符
3.2.7.2、日志输出策略---控制台输出
使用方式:
xml
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{56} | %L : %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
输出效果:
java
2024-12-23 12:11:43.947 | INFO | main | com.atguigu.item.init.SystemInit.afterPropertiesSet | 18 : 测试......
对应输出日志代码,如下所示:
解释:
- name:自己取的名字,可以在
root
标签或者logger
标签下面的appender-ref
标签中引用 - class:使用
ch.qos.logback.core.ConsoleAppender
类可以将日志内容输出到控制台 - encoder.pattern:日志内容输出格式,在上一章节讲过了
- encoder.charset:字符编码
3.2.7.3、日志输出策略---文件滚动输出
下面介绍"基于时间和日志文件大小来进行日志滚动输出到文件"
java
<!-- DEBUG日志记录器,日期滚动记录 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_error.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 备份记录的日志文件的路径及文件名,其中%d{yyyy-MM-dd}代表年-月-日(区分不同日期),而%i代表序号(用来区分同一天的不同文件) -->
<fileNamePattern>${LOG_PATH}/error/error-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<!-- 单个日志文件最大数据量,例如下面代表日志文件不能超过20M,若超过20M,日志文件会以索引0开始来命名日志文件,例如log_error_2020-20-20_0.log -->
<maxFileSize>20MB</maxFileSize>
<!-- 日志文件最大容量 -->
<totalSizeCap>10GB</totalSizeCap>
<!--日志文件保留天数-->
<MaxHistory>7</MaxHistory>
</rollingPolicy>
<!-- 以追加方式记录日志 -->
<append>true</append>
<!-- 日志格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 日志输出格式 -->
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 根据日志级别过滤;此日志文件只记录error级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
其实没有太多可以解释的,在示例中已经注释清晰了,最顶级的appender
的class
就是ch.qos.logback.core.rolling.RollingFileAppender
,代表滚动输出到文件中,下面介绍一下内部的标签:
- file:记录实时日志输出文件路径
- rollingPolicy:定义日志文件备份策略
- append:定义日志追加方式
- encoder:定义日志输出格式
- filter:根据日志级别过滤,控制日志输出级别
3.2.7.4、日志输出策略---异步输出(非必须,默认是同步输出)
logback
提供了大量的Appender
将日志输出到指定的位置。如ConsoleAppender
用于同步地将日志输出到控制台,FileAppender
用于同步地将日志输出到指定日志文件,SocketAppender
用于同步地将日志通过套接字发送到指定服务器。他们都有一个共同点:同步。
那么如何修改日志配置文件将日志输出改为异步呢?logback
提供了一个Appender
的异步实现类:AsyncAppender
。使用方法也非常简单,同样也是通过在配置文件中添加<appender>
标签声明AsyncAppender
,然后通过引用属性引用一个同步Appender
即可,如下所示:
java
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- 日志输出格式 -->
<property name="log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/>
<!-- 同步输出到控制台 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="async-console" class="ch.qos.logback.classic.AsyncAppender">
<!-- 引用同步,将其包装为异步 -->
<appender-ref ref="console" />
</appender>
<!-- 采用异步输出 -->
<root level="INFO">
<appender-ref ref="async-console" />
</root>
</configuration>
虽然示例中是控制台输出,但是也支持配合文件输出使用
为什么给同步Appender
包装一层AsyncAppender
就可以实现异步输出呢?
AsyncAppender
内部维护了一个阻塞队列ArrayBlockingQueue
,logback
将我们打印日志的代码log.info("第一条日志")
封装为一个事件Event
,每当我们需要打印一行日志时,logback
会将该事件放在阻塞队列中,然后再通过多线程的形式从该阻塞队列中获取一个事件执行。
阻塞队列可以保证日志的输出是有序的,多线程保证日志的输出是异步的。
4、代码用法
- 在类上添加
@Slf4j
注解 - 通过静态常量log来调用info、warn、error等方法,例如:
log.info("测试......");
5、使用案例
链接: https://pan.baidu.com/s/1eH1ZcaVdqKQuLp7hIq-cgA?pwd=3vd7
提取码: 3vd7