SpringBoot-整合Logback
参考文献
- SpringBoot配合logback达到日志切割管理通用配置
- Logback and Spring Boot’s new springProperty lookup mechanism not working
基础知识
-
日志等级
1
The value of the level attribute admitting one of the case-insensitive string values TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF.
- 日志级别由低到高
TRACE, DEBUG, INFO, WARN, ERROR
- 日志级别由低到高
遇到的问题
- Logback and Spring Boot’s new springProperty lookup mechanism not working(springProperty不起作用)
Logback配置
-
Spring Boot官方文档指出,根据不同的日志系统,可以按照如下的日志配置
文件名就能够被正确加载,如下:-
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
-
-
配置文件名称:
logback-spring.xml
1 |
|
-
SpringBoot
bootstrap.yml
配置1
2
3
4
5
6
7
8logging:
level:
logback: info
file:
# 指定日志文件的路径
path: logs/xxx
# 日志的文件名,默认为spring.log
name: xxxx -
配置日志级别 调试
1
2
3
4
5
6
7
8
9
10
11logging:
level:
root: WARN
org:
springframework:
security: DEBUG
web: ERROR
hibernate: DEBUG
apache:
commons:
dbcp2: DEBUG
configuration
节点
-
这是一个根节点,其中的各个属性如下:
属性 说明 scan
当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒.当scan为true时,此属性生效.
默认的时间间隔为1分钟.debug
当此属性设置为true时,将打印出logback内部日志信息, 实时查看logback运行状态.
默认值为false
root
节点
- 这是一个必须节点,用来指定基础的日志级别,只有一个
level
属性,默认是DEBUG
.该节点可以包含零个或多个元素,子节点是appender-ref
,标记这个appender
将会添加到一个logger
中.
contextName
节点
- 表示一个上下文名称,默认为
default
,一般用不到.
property
节点
- 标记一个上下文变量,属性有
name
和value
,定义变量之后可以使用${}
来获取.
appender
节点
- logback中appender是负责写日志的组件,主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、MySQL和其他数据库、JMS和远程UNIX Syslog守护进程等
1 | <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
-
用来格式化日志输出节点,有两个属性
name
和class
,class
是用来指定哪种输出策略,常用就是控制输出策略和文件输出策略. -
这个节点很重要,通过的日志文件需要定义三个
appender
,分别是控制台输出,常规日志文件输出,异常日志文件输出. -
该节点有几个重要的子节点:
属性 说明 filter
日志输出拦截器,没有特殊定制一般使用系统自带的即 可,但是如果要将日志分开,比如将 ERROR
级别的日志输出到一个 文件中,将除了ERROR
级别的日志输出到另外一个文件中,此时就要拦截ERROR
级别的日志了encoder
和pattern节点组合用于具体输出的日志格式和编码方式. file
节点用来指明日志文件的输出位置,可以是绝对路径也可以是相对路径 rollingPolicy
日志回滚策略 TimeBasedRollingPolicy
,基于时间的回滚策略,有以下子节点FileNamePattern
,必要节点,可以用来设置指定时间的日志归档.maxHistory
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,例如设置为30的话,则30天之后,旧的日志就会被删除 totalSizeCap
可选节点,用来指定日志文件的上限大小,例如设置为3GB的话,那么到了这个值,就会删除旧的日志
常见的appender
- ConsoleAppender: 将日志信息输出到控制台.它通常用于在开发环境中查看实时日志.
- FileAppender: 将日志信息输出到文件.可以配置日志文件的路径、文件名以及滚动策略,可用于记录应用程序的运行日志.
- RollingFileAppender: 与 FileAppender 类似,但它支持日志文件的滚动和归档.可以按照时间、文件大小等条件将日志信息分割成多个文件.
- SMTPAppender: 将日志信息通过电子邮件发送.可以配置邮件服务器和收件人信息,用于发送关键日志或错误报警通知.
- SyslogAppender: 将日志信息发送到远程 syslog 服务器.适用于与其他系统集成或将日志信息集中到远程日志服务器进行管理和分析.
- SocketAppender: 将日志信息发送到远程 TCP 或 UDP 服务器.可以将日志信息转发到远程日志收集器或中央日志管理系统.
- DBAppender: 将日志信息存储到数据库中.可以将日志信息保存在关系型数据库中,便于后续查询和分析.
- AsyncAppender: 异步地将日志信息输出到其他 Appender.它可以提高日志记录的性能,将日志写入队列后在后台异步处理.
常见的rollingPolicy
SizeAndTimeBasedRollingPolicy
: 根据日志文件的大小和时间来触发滚动.可以设置最大文件大小和保存时间,同时也支持按时间切割日志文件.TimeBasedRollingPolicy
: 根据时间来触发滚动.您可以指定滚动的时间间隔(例如每天、每周等),并设置最大历史记录文件数.FixedWindowRollingPolicy
: 根据文件数来触发滚动.您可以指定滚动时保留的文件数目,并随着新日志的产生按顺序覆盖旧的日志文件.这种策略适用于限制日志文件的数量.SizeBasedTriggeringPolicy
: 根据日志文件的大小来触发滚动.可以设置最大文件大小,当日志文件达到该大小时,将会触发滚动.TimeBasedTriggeringPolicy
: 根据时间来触发滚动.类似于TimeBasedRollingPolicy
,但不支持具体的时间间隔,而是基于系统时间的变化来触发滚动.
常见的triggeringPolicy
-
SizeBasedTriggeringPolicy
: 基于文件大小的触发策略.当日志文件达到指定的大小时,将触发滚动.1
2
3
4
5
6
7
8
9
10
11
12<appender name="RollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/path/to/logfile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>/path/to/logfile.%i.log</fileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
<encoder>
<!-- 配置编码器 -->
</encoder>
</appender> -
TimeBasedTriggeringPolicy
: 基于时间的触发策略.根据设定的时间间隔,例如每天、每小时或每分钟,触发滚动.1
2
3
4
5
6
7
8
9
10
11
12
13
14<appender name="RollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/path/to/logfile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/path/to/logfile.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.TimeBasedTriggeringPolicy">
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</triggeringPolicy>
<encoder>
<!-- 配置编码器 -->
</encoder>
</appender> -
OnStartupTriggeringPolicy
: 启动时触发策略.在应用程序启动时立即触发滚动. -
OnConsoleStatusTriggeringPolicy
: 控制台状态变化触发策略.当应用程序的控制台状态(激活或非激活)发生变化时,触发滚动. -
CompositeTriggeringPolicy
: 组合触发策略.可以将多个触发策略组合在一起,只要其中一个策略满足触发条件,就会触发滚动.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<appender name="RollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/path/to/logfile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>/path/to/logfile.%i.log</fileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.CompositeTriggeringPolicy">
<policies>
<SizeBasedTriggeringPolicy>
<maxFileSize>10MB</maxFileSize>
</SizeBasedTriggeringPolicy>
<TimeBasedTriggeringPolicy>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</TimeBasedTriggeringPolicy>
</policies>
</triggeringPolicy>
<encoder>
<!-- 配置编码器 -->
</encoder>
</appender>
logger
节点
-
可选节点,用来具体指明包的日志输出级别,它将会覆盖
root
的输出级别.有如下属性属性 说明 name
指定的包名 level
可选,日志的级别 addtivity
可选,默认为true,将此 logger
的信息向上级传递,将root
节点定义日志打印,如果设置为false,将不会上传,此时需要定义一个appender-ref
节点才会输出.
实战
根据不同业务模块将业务模块的日志输出到不同的日志文件中
-
配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定义日志文件的存储地址,勿在logback配置文件中使用相对路径.通过springProperty可以在properties文件设置相关path,level,name信息
application.properties中定义的变量,在logback的xml文件中无法直接读取,必须要增加springProperty属性中转一下,source属性里放的值是application.properties中定义的
-->
<springProperty name="log.path" source="logging.file.path" defaultValue="logs/sundry"/>
<springProperty name="log.name" source="logging.file.name" defaultValue="sundry"/>
<springProperty name="log.level" source="logging.level" defaultValue="INFO"/>
<!-- 定义日志文件名格式化,定义到哪个维度则按哪个维度切割日志,只支持每周,每天,每个小时,每分钟等创建一个文件 yyyy-MM-dd-HH-mm 分钟维度 -->
<property name="log.timeFormat" value="yyyy-MM-dd"/>
<!-- 定义日志文件的输出格式。%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%logger{50} 表示logger名字最长50个字符,否则按照句点分割。%msg:日志消息,%n是换行符 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 定义日志文件保留天数,单位和log.timeFormat定义的最小维度保持一致,上面定义到天,则单位默认为天 -->
<property name="log.maxHistory" value="7"/>
<!-- 定义日志文件最大限制,超过限制则切割日志 -->
<property name="log.maxFileSize" value="100MB"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件,并按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${log.name}.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${log.level}</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动 为了保证不重复
-->
<FileNamePattern>${log.path}/${log.name}.%d{${log.timeFormat}}.log</FileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件。仅记录错误日志 -->
<appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${log.name}_error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.path}/error/${log.name}_error.%d{${log.timeFormat}}.log</FileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 日志输出级别,root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
<appender-ref ref="FILE-ERROR"/>
</root>
<!-- 业务日志配置从此处开始 -->
<appender name="BUSINESS_A" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/business/business_a.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${log.level}</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.path}/business/business_a.%d{${log.timeFormat}}.log</FileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<appender name="BUSINESS_B" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/business/business_b.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${log.level}</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.path}/business/business_b.%d{${log.timeFormat}}.log</FileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<logger name="businessALogger" additivity="true" level="INFO">
<appender-ref ref="BUSINESS_A"/>
</logger>
<logger name="businessBLogger" additivity="true" level="INFO">
<appender-ref ref="BUSINESS_B"/>
</logger>
<!-- 业务日志配置到此处结束 -->
</configuration> -
Logger
工具类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package com.holelin.sundry.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:
* @Author: HoleLin
* @CreateDate: 2022/7/22 17:45
* @UpdateUser: HoleLin
* @UpdateDate: 2022/7/22 17:45
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class LoggerUtils {
public static <T> Logger Logger(Class<T> clazz) {
return LoggerFactory.getLogger(clazz);
}
/**
* 打印到指定的文件下
*
* @param desc 日志文件名称
* @return
*/
public static Logger Logger(String desc) {
return LoggerFactory.getLogger(desc);
}
public static Logger getBusinessALogger(){
return Logger("businessALogger");
}
public static Logger getBusinessBLogger(){
return Logger("businessBLogger");
}
} -
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package com.holelin.sundry.controller;
import com.holelin.sundry.utils.LoggerUtils;
import org.slf4j.Logger;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description:
* @Author: HoleLin
* @CreateDate: 2022/7/22 17:40
* @UpdateUser: HoleLin
* @UpdateDate: 2022/7/22 17:40
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class LogBackTestController {
public void doBusinessA() {
final Logger logger = LoggerUtils.getBusinessALogger();
logger.info("do business a ");
}
public void doBusinessB() {
final Logger logger = LoggerUtils.getBusinessBLogger();
logger.info("do business b ");
}
} -
日志文件输出的内容
-
business_a.log
1
2022-07-23 14:29:28.143 [http-nio-8094-exec-3] INFO businessALogger - do business a
-
business_b.log
1
2022-07-23 14:29:13.221 [http-nio-8094-exec-1] INFO businessBLogger - do business b
-
总的日志文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
222022-07-23 14:28:03.311 [background-preinit] INFO org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 6.2.3.Final
2022-07-23 14:28:03.336 [main] INFO com.holelin.sundry.SundryApplication - Starting SundryApplication using Java 11.0.12 on 192.168.0.105 with PID 46145 (/Users/holelin/Projects/MySelf/Java-Notes/sundry/target/classes started by holelin in /Users/holelin/Projects/MySelf/Java-Notes)
2022-07-23 14:28:03.336 [main] INFO com.holelin.sundry.SundryApplication - No active profile set, falling back to 1 default profile: "default"
2022-07-23 14:28:04.231 [main] INFO o.s.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8094 (http)
2022-07-23 14:28:04.238 [main] INFO org.apache.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8094"]
2022-07-23 14:28:04.238 [main] INFO org.apache.catalina.core.StandardService - Starting service [Tomcat]
2022-07-23 14:28:04.239 [main] INFO org.apache.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.60]
2022-07-23 14:28:04.296 [main] INFO o.a.c.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
2022-07-23 14:28:04.296 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 929 ms
2022-07-23 14:28:04.671 [main] INFO s.d.s.w.PropertySourcedRequestMappingHandlerMapping - Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
2022-07-23 14:28:04.881 [main] INFO org.apache.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8094"]
2022-07-23 14:28:04.901 [main] INFO o.s.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8094 (http) with context path ''
2022-07-23 14:28:04.902 [main] INFO s.d.s.web.plugins.DocumentationPluginsBootstrapper - Context refreshed
2022-07-23 14:28:04.910 [main] INFO s.d.s.web.plugins.DocumentationPluginsBootstrapper - Found 2 custom documentation plugin(s)
2022-07-23 14:28:04.928 [main] INFO s.d.spring.web.scanners.ApiListingReferenceScanner - Scanning for api listing references
2022-07-23 14:28:05.024 [main] INFO s.d.spring.web.scanners.ApiListingReferenceScanner - Scanning for api listing references
2022-07-23 14:28:05.031 [main] INFO com.holelin.sundry.SundryApplication - Started SundryApplication in 2.08 seconds (JVM running for 6.733)
2022-07-23 14:29:13.116 [http-nio-8094-exec-1] INFO o.a.c.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-23 14:29:13.117 [http-nio-8094-exec-1] INFO org.springframework.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
2022-07-23 14:29:13.141 [http-nio-8094-exec-1] INFO org.springframework.web.servlet.DispatcherServlet - Completed initialization in 24 ms
2022-07-23 14:29:13.221 [http-nio-8094-exec-1] INFO businessBLogger - do business b
2022-07-23 14:29:28.143 [http-nio-8094-exec-3] INFO businessALogger - do business a
-
给第三方框架指定logger
,日志内容输出执行文件
1 | <!--additivity=false时不会追加到root定义的文件里面,只会追加到当前PACS里面,如果additivity=true root里面没有定义ref也不生效--> |
- 完整信息
1 |
|