【二三方】_SLF4J日志应用

SLF4J日志应用

logback配置文件加载优先级顺序
  • 自动在classpath下查找并加载对应文件,前一个有就不会去查找下一个:logback.groovy>logback-test.xml>logback.xml>logback-spring.xml。
六个日志级别
  • 常见的日志级别有FATAL、ERROR、WARNING、INFO、DEBUG、TRACE,一般默认的日志级别为INFO。
logback配置文件节点
  • 根节点Configuration有三个子节点,其中可以定义多个Appender和多个Logger,只能定义一个Root。
  • Appender节点有三种常见的子节点:其中Console节点用来定义输出到控制台的Appender,File节点用来定义输出到指定位置的文件的Appender,RollingFile节点用来定义超过指定大小自动删除旧文件并创建新文件的Appender。
  • Logger节点用来单独指定日志输出的形式。
  • Root节点用来指定项目的根日志输出形式,如果某个类或包没有通过Logger单独指定日志输出形式,那么会默认使用该Root根日志输出形式。
logback日志文件示例

Logback.xml配置文件属性释义

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
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!--定义项目名-->
<property name="APP_NAME" value="jingzhao-log-test"/>
<!--java项目部署到lunix系统时可以由${user.home}获取到用户空间文件夹地址-->
<property name="LOG_PATH" value="${user.home}/${APP_NAME}/logs"/>
<property name="LOG_FILE_PLAY" value="${LOG_PATH}/jingzhao-log-test-play.log"/>
<property name="LOG_FILE_STUDY" value="${LOG_PATH}/jingzhao-log-test-study.log"/>
<property name="LOG_FILE_LIFE" value="${LOG_PATH}/jingzhao-log-test-life.log"/>

<!--为目的地命名,并指定该目的地类型为RollingFileAppender-->
<appender name="play-appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--目的地全路径文件名-->
<file>${LOG_FILE_PLAY}</file>
<!--定义日志格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [%class:%line] - %m %n</pattern>
</encoder>
<!--定义日志文件分割策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--定义被分割所得文件的文件名格式-->
<fileNamePattern>${LOG_FILE_PLAY}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--定义最多保留分割文件的个数,超出该数量则删除保存最久的-->
<maxHistory>7</maxHistory>
<maxFileSize>50MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
</appender>

<appender name="study-appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE_STUDY}</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [%class:%line] - %m %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_STUDY}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>50MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
</appender>

<appender name="life-appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE_LIFE}</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [%class:%line] - %m %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_LIFE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>50MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
</appender>

<!--指定目的地为控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [%class:%line] - %m %n</pattern>
      </encoder>
</appender>

<!--name属性用于指定使用该日志输出形式的类或者包;level="INFO"属性用于指定级别低于INFO的日志不能使用该形式输出到目的地;additivity="false"属性用于指定该类或包中的日志以该logger形式输出后,不需要再以root形式输出了。-->
<logger name="play" level="INFO" additivity="false">
<!--用来指定以该形式输出的日志打到哪个目的地-->
<appender-ref ref="play-appender"/>
</logger>

<logger name="study" level="INFO" additivity="false">
<appender-ref ref="study-appender"/>
</logger>

<!--根日志输出形式-->
<root level="INFO">
<appender-ref ref="life-appender"/>
<!--一条日志通过同一个输出格式可以打到不同的多个目的地,比如此处打到了life-appender,又打到了console。-->
<appender-ref ref="console"/>
</root>
</configuration>
引入maven依赖

在SpringBoot项目中必须引入lombok依赖才可以使用@SFL4J注解

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
</dependency>
在类中通过@SFL4J注解指定日志输出形式

没有特别指定输出形式,则使用root根日志输出形式:

1
2
3
4
5
6
7
@Slf4j
@Service
public class Life {
public void sleep() {
log.info("今天只睡了{}个小时",4);
}
}

通过注解指定日志输出形式为play:

1
2
3
4
5
6
7
@Slf4j(topic = "play")
@Service
public class Play {
public void computer() {
log.info("打电脑游戏死了{}次,妈妈很难受!",15);
}
}

通过注解指定日志输出形式为study:

1
2
3
4
5
6
7
@Slf4j(topic = "study")
@Service
public class Study {
public void math() {
log.info("数学考了{}分,妈妈很高兴!",99);
}
}
异步日志AsyncAppender配置

异步日志采用异步的方式打印日志,避免了在多应用高并发情况下日志打印消耗过多资源,影响工作线程效率。异步日志记录是在原来logback上的扩展,并不是替代方式,所以只需要在原来的配置文件上添加一下配置:

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
<configuration>
<appender name="study-appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE_STUDY}</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [%class:%line] - %m %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_STUDY}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>7</maxHistory>
<maxFileSize>50MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
</appender>

<appender name="study-async-appender" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>2000</queueSize>
<!-- 新增这行为了打印栈堆信息 -->
<includeCallerData>true</includeCallerData>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="study-appender"/>
</appender>

<root level="INFO">
<appender-ref ref="study-async-appender"/>
</root>
</configuration>
日志规约

格式清晰的日志输出能使我们在开发和测试过程中更准确地发现和解决问题。

格式1
  • INFO:
1
2
3
4
5
log.info("logType=[methodName_event], param0: {},param1: {},,,paramN:  {}",param0,param0,paramN);

exp:
log.info("logType=[querUserInfo_request], ytid: {}, tuid: {},,,alipayId: {}" , 12345, 67890, 12345);
log.info("logType=[querUserInfo_response], ytid: {}, tuid: {},,,alipayId: {}" , 12345, 67890, 12345);
  • ERROR:
1
2
3
4
5
log.error("logType=[methodName_event], param0: {},param1: {},,,paramN: {}",param0,param0,paramN);

exp:
log.error("logType=[querUserInfo_error], ytid: {}, tuid: {},,,alipayId: {}" , 12345, 67890, 12345);
log.error("logType=[querUserInfo_exception], ytid: {}, tuid: {},,,alipayId: {}" , 12345, 6789, 12345);
格式2
  • INFO
1
2
3
4
5
log.info("logType=[{eventName}], result=[{resultName}], param0: {}, param1: {},,,paramN: {}" , eventName, resultName, param0, param0, paramN);

exp:
log.info("logType=[eventName], result=[{resultName}], ytid: {}, tuid: {},,,alipayId: {}", "querUserInfo", "rquest", 12345, 67890, 12345);
log.info("logType=[eventName], result=[{resultName}], ytid: {}, tuid: {},,,alipayId: {}", "querUserInfo", "response", 12345, 67890, 12345);
  • ERROR
1
2
3
4
5
6
log.error("logType=[{eventName}], result=[{resultName}], param0: {}, param1: {},,,paramN: {}" , eventName, resultName, param0, param0, paramN);


exp:
log.error("logType=[eventName], result=[{resultName}], ytid: {}, tuid: {},,,alipayId: {}", "querUserInfo", "error", 12345, 67890, 12345);
log.error("logType=[eventName], result=[{resultName}], ytid: {}, tuid: {},,,alipayId: {}", "querUserInfo", "exception", 12345, 67890, 12345);