前言

日志记录这块,简单的控制台打印也是日志,输出log文件也是日志,跨服务器输出日志,也是日志。这还没说复杂的日志监控,日志监控,需要对代码打印日志的标准有要求。这个就比较复杂了,

首先我们要知道,日志是有级别的,log4j,我记得好像有7个级别,slf4j,有五个级别。首先我们得知道log4j和slf4j是什么东西,为啥把这两个放在一起说。题外话说一下命名,这个4j应该不少人有疑问,因为这东西不符合Java的驼峰命名规则啊,为啥要起这个名呢,好吧,其实就是For Java的音译加缩写。据说是传统,比如什么dom4j等等。这个级别是用来控制日志输出内容的,你设置的级别越高,打印的日志就越少,你配置级别最低,则打印全部级别的日志。准确来说是包含关系,就像一个金字塔结构一样。

还有Log4j和Slf4j这两个并不负责输出日志,准确的说这两个是Java日志的门面,又或者是标准,门面是什么意思,就是服务员,你去吃饭,只需要和服务员说,我要一碗蛋炒饭。至于服务员去找哪个厨师帮你做,你不用管,这两个东西也是一样,你和slf4j说,我要打印日志,slf4j得去找实现给你打印日志,但是只有slf4j是没有办法给你打印日志的。这个时候你就需要去找一个厨师,就是实现。logback是直接实现了slf4j的一个日志实现。好了。应该说明白了。

实际上logback官网上是有十分详细的介绍,尬就尬在,是英文文档。

依赖

普通的Java项目

1
2
3
implementation 'ch.qos.logback:logback-classic:1.2.10'
implementation 'ch.qos.logback:logback-core:1.2.10'
implementation 'org.slf4j:slf4j-api:1.7.32'

springboot中无需此依赖,默认的日志就是lagback。

配置文件介绍

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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?xml version="1.0" encoding="UTF-8" ?>
<!--
configuration节点有三个属性
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位默认单位是毫秒,当scan为true时此属性生效,默认时间间隔为1分钟
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态,默认值为false
-->
<configuration scan="true" scanPeriod="2 seconds" debug="false">

<!--
设置上下文名称,每个<logger>都关联到<logger>上下文,默认上下文名称为default,但可以使用设置成其他名字,用于区分不同应用程序的记录,一旦设置,不能修改,可以通过 %contextName 来打印日志上下文名称,一般来说我们不用这个属性,可有可无。
-->
<contextName>demo</contextName>


<!--
用来定义变量的节点,定义变量后,可以使${}来使用变量,两个属性
这个属性只有在springboot环境中使用才可以,且配置文件名要为logback-spring.xml才可正常使用。
name: 和下文中的name一样
scope:一般就填context就行了,具体配置可查看官网
source: 读取application.yml或application.properties文件中的配置,
-->
<springProperty scope="context" name="app_name" source="logging.file.name"/>

<!--
用来定义变量的节点,定义变量后,可以使${}来使用变量,两个属性,当定义了多个<appender>的时候还是很有用的:
name:变量名
value:变量值
-->
<property name="log.dir" value="logs"/>
<!--
定义滚动记录文件appender 作用:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件
RollingFileAppender class="ch.qos.logback.core.rolling.RollingFileAppender"
参数:
<append>:如果是true日志被追加到文件结尾,如果是false清空现存文件,默认是true
<fileNamePattern>:被写入的文件名,可以是相对目录也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值
<rollingPolicy>:当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名
<triggeringPolicy>:告知RollingFileAppender合适激活滚动
<prudent>:当为true时不支持FixedWindowRollingPolicy支持TimeBasedRollingPolicy,但是有两个限制:1不支持也不允许文件压缩,2不能设置file属性必须留空
-->
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天滚动一次的日志 只保留30天内的日志文件 -->
<fileNamePattern>logs/%d{yyyy-MM-dd}/info%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>

<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<prudent>true</prudent>

<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>logs/error.log</File>
<append>true</append>
<!--
当为true时不支持FixedWindowRollingPolicy支持TimeBasedRollingPolicy,但是有两个限制:1不支持也不允许文件压缩,2不能设置file属性必须留空
-->
<prudent>false</prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/error%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!--
配置日志级别过滤器 作用:根据日志级别进行过滤,如果日志级别等于配置级别过滤器会根据onMath和onMismatch接收或拒绝日志
参数:
<level>:设置过滤级别
<onMatch>:用于配置符合过滤条件的操作
<onMismatch>:用于配置不符合过滤条件的操作
此处配置为只接收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.ConsoleAppender" -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
</layout>
</appender>

<!--
logger用来设置某一个包的日志打印级别
<loger> 仅有一个name属性,一个可选的level和一个可选的addtivity属性
name:用来指定受此loger约束的某一个包或者具体的某一个类
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
addtivity:是否向上级loger传递打印信息。默认是true,会将信息输入到root配置指定的地方,可以包含多个appender-ref,标识这个appender会添加到这个logger
-->
<!-- <logger name="com.xcbeyond.springboot" level="debug"/>-->
<!-- 将root的打印级别设置为"error",指定了名字为"console","fileAppender","errorAppender"的appender -->

<!--
springProfile标签用来处理开发环境和生产环境的不同配置
name: 读取spring.profiles.active的值
profile即根据不同的环境使用不同的日志策略,这里举例开发和生产环境:
-->

<!-- 开发环境输出到控制台 -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</springProfile>

<!-- 生产环境输出到文件 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE_LOG" />
</root>
</springProfile>


<root level="debug">
<appender-ref ref="console"/>
<appender-ref ref="fileAppender"/>
<appender-ref ref="errorAppender"/>
</root>
</configuration>

应该是介绍的比较详细了,因为这东西平时很少有人去专门去记一下,我也是弄好一套,然后CV一下就可以了,注意上面的配置只是用来演示的,并不能直接CV下来用。下面我配置几种常用的配置,可以直接CV下来用的。

全部日志一个文件

控制台打印日志,并输出日志文件。

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

<configuration>
<!--
输出日志到控制台
-->
<appender name="soutAppender" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
</layout>
</appender>

<!--
输出日志到文件
-->
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<prudent>false</prudent>
<File>logs/log.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/log%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>

<root level="all">
<appender-ref ref="soutAppender"/>
<appender-ref ref="fileAppender"/>
</root>
</configuration>

不同级别不同文件

控制台打印太基础我就不说了,加强主要针对log文件,这个配置我们按日志级别输出对应级别的日志。方便我们定位和查找。一般来说,我们只需要info和error级别的日志即可。

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
<configuration>
<!--
输出日志到控制台
-->
<appender name="soutAppender" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
</layout>
</appender>

<!--
输出日志到文件
-->
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<File>logs/info.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/info%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 两个过滤器过滤warn和error基本的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 WARN-->
<level>WARN</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>ERROR</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>


<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<File>logs/error.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/error%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!--
过滤日志,只包含warn以及warn以上级别的日志也就是error的日志
-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>

<root level="all">
<appender-ref ref="soutAppender"/>
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</root>
</configuration>

最终结果是会输出两个日志文件,info.logerror.log, info包括info级别以及以下级别的日志,error.log包括warnerror两个级别的日志。

不同包不同日志文件

我们一般的系统基本都有几层架构,有controller层,以及service层,logback可以根据不同的包来输出日志,也可以精确到具体的某一个类名。主要使用logger这个标签来完成。这个没有办法CV,因为不同的项目包名不一样,根据自己的项目需要修改一下

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
<configuration>
<!--
输出日志到控制台
-->
<appender name="soutAppender" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
</layout>
</appender>

<!--
输出日志到文件
-->
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<File>logs/info.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/info%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>

<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 WARN-->
<level>WARN</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>ERROR</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>


<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<File>logs/error.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/error%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>

<appender name="wlfAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果是true,日志被追加到文件结尾,如果是false,清空现存文件.默认是true -->
<append>true</append>
<prudent>false</prudent>
<File>logs/wlf/wlf.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/wlf/%d{yyyy-MM-dd}/wlf%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个日志文件最大体积 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 对日志进行格式化 -->
<pattern>%date %level [%thread] %logger{10}.%class{0}#%method[%file:%line] %n%msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--
这个配置表示把com.wlf包下的日志以wlfAppender的配置进行打印日志
level: 代表日志级别,不配置默认为all
-->
<logger name="com.wlf" level="debug">
<appender-ref ref="wlfAppender"/>
</logger>

<root level="all">
<appender-ref ref="soutAppender"/>
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</root>
</configuration>

这个不怎么常用,只需要知道就行了,一般只使用第二个配置就行了,直接CV就行。至于和springboot中使用,可以整,但是没啥必要。具体的配置还是多看看介绍,多多学习。或者直接CV。😁😁

主要内容到这里就介绍完了,logback的配置十分的灵活,但想要灵活的使用,还是需要多多的了解。当然打印日志归打印日志,如果你写代码打日志时不按照标准输出,再牛逼的配置也救不了。打印日志也需要规范一点。开发使用debug,需要留存的日志信息用info,异常信息用error。