# 整合日志Logback
日志这个是一个系统重要的组成部分,不论任何系统,都会有详细的日志记录。日志对于查询问题有着至关重要的作用
# 一、背景历史
那么这个日志说起来有点故事,,在学校学习的时候,都是使用下面这俩
System.out.println()
System.err.println()
做一些必要信息的记录的 哈哈哈,虽然是很low但是你别说,还真管用嘞 哈哈哈
随着学习的深入和工作了,开始对这个日志有了一定的了解.....
以前的写法固然可以达到效果,但是在实际的开发中,难免会出现问题,比如 上线了,日志比较多,,System.out.println输出的不会长久保留,会顶掉了,,日后查问题页看不到日志....
接下来,高能时刻....让我装一下,,在下等这一刻很久了,biubiu
有位穿着格子衫,牛仔裤,运动hai的大佬 就开发了一款专门记录日志的框架 log4j 极大的解决了日志记录问题,在当时备受关注, 确实很好用,非常流行,使用的人也越来越多 于是这小伙子想着能不能 开源了这个玩意儿。 于是乎,在某天早晨,这个大佬兴致勃勃的就先找了jdk官方,想让jdk里原生支持下log4j,谁曾想,着tm的jdk不以为然,估计还傲娇的看不起小伙子, 这位大佬碰壁后骑着小破车就回去了...
越想越气,过了几天,他其上心爱的小摩托,去了 apache, 但是看门大爷看到他衣衫褴褛,不让他进去.... 淦,啊这。。。 还好,遇到了老板的大儿子tomcat,没错,就是你熟悉的那只tomcat..他看那小伙子很顺眼,,就打他去见了apache爸爸
apache二话不说,就同意了他的请求,于是乎 log4j 就成了apache的开源项目
jdk知道后,这能忍??于是乎自己开发了一个JUL
再后来,一个项目由多个小组开发,各用各的日志框架,,最后合并代码的时候出问题了,,于是乎,日志门面 出来了
什么是日志门面,就是提供统一的接口,并且做相应的适配器,转换器!可以把不同的日志实现转化为统一的
# 二、日志框架分类
日志门面 JCL Slf4j
日志实现 Log4j JUL LogBack Log4j2 .....
当jdk推出JCL之后,那个小伙子觉得apache不给力,人家都推出了日志门面,apache这一点动静页没有...于是乎就离开了
然后自己开发了一个日志门面 Slf4j 性能是十分好
再后来,由于系统对性能的要求越来越严格,log4j性能不行,,小伙子又开发了一个全新框架 logback,非常流行,,springboot默认页使用了logback
日志实现框架
log4j:几乎不用了 jul:小型的项目可以用用 logback:非常流行,性能很好 springboot默认采用 log4j2:非常流行,性能很好
日志门面
jcl:spring默认采用 JCL,全称为"Jakarta Commons Logging",也可称为"Apache Commons Logging"。 slf4j:springboot默认采用
推荐组合
slf4j + logback (Springboot默认使用的) slf4j + log4j2
# 三、Logback 配置
- SpringBoot工程自带logback和slf4j的依赖
- logback框架会默认加载classpath下命名为 logback-spring.xml 或 logback.xml 的配置文件
- 我们项目日志记录的最好是应该是将error日志和其他日志分开,并且不同级别的日志根据时间段进行记录存储。
# 1.通过application配置
因为springboot默认是logback,所以通过springboot的application.yml里可以配置最基础的日志相关的信息:如下
新建一个项目springboot-log-demo,就引入web
@SpringBootApplication
public class LogApplication {
private static final Logger log = LoggerFactory.getLogger(LogApplication.class);
public static void main(String[] args) {
SpringApplication.run(LogApplication.class, args);
log.trace("---- this is TRACE level-----");
log.debug("---- this is DEBUG level-----");
log.info("---- this is INFO level-----");
log.warn("---- this is WARN level-----");
log.error("---- this is ERROR level-----");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
springboot默认的日志级别是INFO,高于INFO的日志才会打印,如下图,我们的TRACE/DEBUG都没打印
自定义日志的级别 dev环境 com.biubiu.log包下面我们打印trace级别的日志
application-dev.yml
logging:
level:
com.biubiu.log: trace
2
3
logging.file.name把日志存到文件中
application-dev.yml
logging:
level:
com.biubiu.log: trace
file:
#name: biubiu-log.log
name: D:\logs\biubiu-log.log
2
3
4
5
6
# 2.logback配置文件
logback-spring.xml 最简配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--常量定义-->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<!--appender-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">\
<encoder>
<Pattern>${LOG_PATTERN}</Pattern>
</encoder>
</appender>
<logger name="com.biubiu" level="INFO"/>
<logger name="com.biubiu.mapper" level="DEBUG"/>
<!--logger-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 命名
官方推荐使用的xml名字的格式为:logback-spring.xml而不是logback.xml,至于为什么,因为带spring后缀的可以使用
<springProfile>
这个标签来区分环境 - 位置 在resource下创建logback-spring.xml文件
- 详细配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
根节点<configuration>包含三个属性:
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,
此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
这里配置的10秒钟检测一次配置文件
-->
<configuration scan="true" scanPeriod="10 seconds">
<!--
子节点<contextName>:用来设置上下文名称:每个logger都关联到logger上下文,默认上下文名称为“default”。
但可以使用设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改,可以通过%contextName来打印日志上下文名称
-->
<contextName>logback</contextName>
<!--
子节点<property>设置变量,类似于maven的property。用来定义变量值的标签,有两个属性,name和value;其中name的值是变量的名称,
value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
-->
<property name="log.path" value="./log"/>
<property name="log_pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<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" />
<!--彩色日志输出格式-->
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!--
日志输出格式:
%-5level 日志级别
%d{yyyy-MM-dd HH:mm:ss} 日期
%c 或者%logger类的完整名称
%M method方法名
%L 行号
%thread 线程名
%m或者%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}}"/>
<!--
子节点<appender>:appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,
常用就是控制台输出策略和文件输出策略。
-->
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--日志记录到文件-->
<!-- 时间滚动输出 level为 DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.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">
<!-- 日志归档 .log.gz可以压缩 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录DEBUG级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 设置过滤级别 -->
<level>DEBUG</level>
<!-- 用于配置符合过滤条件的操作 -->
<onMatch>ACCEPT</onMatch>
<!-- 用于配置不符合过滤条件的操作 -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责触发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志输出位置 可相对、和绝对路径 -->
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
<!--日志文件最大的大小-->
<maxFileSize>5KB</maxFileSize>
</rollingPolicy>
<!--日志文件输出格式-->
<encoder>
<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>
<!--
子节点<logger>:用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>
有三个属性:
- name:用来指定受此logger约束的某一个包或者具体的某一个类
- level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
- addtivity:是否向上级logger传递打印信息。默认是true。
-->
<!--使用mybatis的时候,sql语句只有在 debug 级别下才会打印-->
<!--<logger name="com.biubiu.mybatis.mapper" level="debug" />-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<root level="INFO">
</root>
<!--开发环境:打印控制台-->
<springProfile name="dev">
<logger name="com.biubiu.log" level="DEBUG">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</logger>
</springProfile>
<!--生产环境:输出到文件-->
<!--<springProfile name="pro">
<root level="warn">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>-->
</configuration>
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# 3.链路追踪
新增TraceID跟踪接口链路日志
以后查询日志可以用 cat -n info.log |grep "a415ad50dbf84e99b1b56a31aacd209c"
或者 grep -10 'a415ad50dbf84e99b1b56a31aacd209c' info.log (10是指上下10行)
# 1.logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--日志存储路径-->
<property name="log" value="./log" />
<property name="log_pattern" value="[%X{TRACE_ID}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" 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">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件名-->
<FileNamePattern>${log}/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log_pattern}</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</configuration>
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
# 2.日志拦截器
LogInterceptor.java
@Configuration
public class LogInterceptor implements HandlerInterceptor {
private static final String TRACE_ID = "TRACE_ID";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String tid = UUID.randomUUID().toString().replace("-", "");
//可以考虑让客户端传入链路ID,但需保证一定的复杂度唯一性;如果没使用默认UUID自动生成
if (!StringUtils.isEmpty(request.getHeader("TRACE_ID"))) {
tid = request.getHeader("TRACE_ID");
}
MDC.put(TRACE_ID, tid);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) {
MDC.remove(TRACE_ID);
}
}
@Configuration
public class WebConfigurerAdapter implements WebMvcConfigurer {
@Bean
public LogInterceptor logInterceptor() {
return new LogInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor())
//可以具体制定哪些需要拦截,哪些不拦截,其实也可以使用自定义注解更灵活完成
.addPathPatterns("/**")
.excludePathPatterns("");
}
}
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
# 4.ufs示例
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--日志保存路径-->
<property name="log.path" value="./log"/>
<!--日志格式-->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!--彩色日志输出格式-->
<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" />
<property name="log.pattern.console" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan}: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!--控制台打印-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>${log.pattern.console}</Pattern>
</encoder>
</appender>
<!--按天生成日志文件-->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--输出格式化-->
<Pattern>${log.pattern}</Pattern>
</encoder>
<!--滚动策略按照时间滚动-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件名称 -->
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--单个文件最大大小-->
<maxFileSize>10MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 错误日志文件 -->
<appender name="error-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 只记录ERROR级别 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!--开发环境-->
<springProfile name="dev | local | test">
<logger name="com.ufs" level="DEBUG" />
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</springProfile>
<!--生产环境-->
<springProfile name="pro">
<root level="WARN">
<appender-ref ref="file" />
<appender-ref ref="error-file" />
</root>
</springProfile>
</configuration>
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