文章目录
1 Logback
1.1 Logback简述
Logback
,一个“可靠、通用、快速而又灵活的Java日志框架”
。logback
当前分成三个模块:logback-core,logback- classic和logback-access
。logback-core
是其它两个模块的基础模块。logback-classic
是log4j
的一个改良版本。此外logback-classic
完整实现SLF4J API
使你可以很方便地更换成其它日志系统,如log4j
或JDK14 Logging
。logback-access
模块与Servlet
容器(如Tomcat和Jetty
)集成,以提供HTTP
访问日志功能。请注意,您可以在logback-core
之上轻松构建自己的模块。
1.2 logback.xml文件的引用
由于 Logback
为 spring-boot
默认日志框架,所以无需再引用,但对于非spring - boot
项目,可以做如下引用
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.12</version>
</dependency>
所以,在使用springboot
时,就不用移除掉自带的日志pom
依赖,而是用的springboot
自己的。
另外,官方推荐使用的xml
名字的格式为:logback-spring.xml
而不是logback.xml
,因为带spring
后缀的可以使用<springProfile>
这个标签。
倘若使用logback.xml
,则需要在配置文件中引用,如下:
application.properties
配置文件中进行如下配置
#配置日志
logging.config=classpath:logback.xml
1.3 logback.xml文件标签说明
1.3.1 configure标签
scan:
当此属性设置为true
时,配置文件如果发生改变,将会被重新加载,默认值为true
scanPeriod:
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan
为true
时,此属性生效。默认的时间间隔为1
分钟。
<configuration scan="true" scanPeriod="10 seconds">
1.3.2 appender标签
<appender>
是<configuration>
的子节点,是负责写日志的组件。
<appender>
有两个必要属性name
和class
。name
指定appender
名称,class
指定appender
的全限定名。
1.3.2.1 ConsoleAppender
把日志添加到控制台,有以下子节点:
<encoder>
:对日志进行格式化。<target>
:字符串System.out
或者System.err
,默认System.out
;
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
1.3.2.2 FileAppender
把日志添加到文件,有以下子节点:
<file>
:被写入的文件名,可以是相对目录
,也可以是绝对目录
,如果上级目录不存在会自动创建,没有默认值。<append>
:如果是true
,日志被追加到文件结尾,如果是false
,清空现存文件,默认是true
。<encoder>
:对记录事件进行格式化。<prudent>
:如果是true
,日志会被安全的写入文件,即使其他的FileAppender
也在向此文件做写入操作,效率低,默认是false
。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
1.3.2.3 RollingFileAppender
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:
<file>
:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。<append>
:如果是true
,日志被追加到文件结尾,如果是false
,清空现存文件,默认是true
。<encoder>
:对记录事件进行格式化。<rollingPolicy>
:当发生滚动时,决定RollingFileAppender
的行为,涉及文件移动和重命名。<triggeringPolicy>
: 告知RollingFileAppender
合适激活滚动。<prudent>
:当为true
时,不支持FixedWindowRollingPolicy
。支持TimeBasedRollingPolicy
,但是有两个限制:不支持也不允许文件压缩;不能设置file
属性,必须留空。
1.3.2.3.1 RollingPolicy
其中rollingPolicy
的选项范围:
1.3.2.3.1.1 TimeBasedRollingPolicy
TimeBasedRollingPolicy
: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。有以下子节点:
<fileNamePattern>:
必要节点,包含文件名及“%d”
转换符,“%d”
可以包含一个java.text.SimpleDateFormat
指定的时间格式,如:%d{yyyy-MM}
。如果直接使用%d
,默认格式是yyyy-MM-dd
。RollingFileAppender
的file
子节点可有可无,通过设置file
,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file
指定的文件(活动文件),活动文件的名字不会改变;如果没设置file,活动文件的名字会根据fileNamePattern
的值,每隔一段时间改变一次。“/”
或者“\”
会被当做目录分隔符。<maxHistory>:
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,且<maxHistory>
是6
,则只保存最近6
个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。
1.3.2.3.1.2 FixedWindowRollingPolicy
FixedWindowRollingPolicy
: 根据固定窗口算法重命名文件的滚动策略。有以下子节点:
<minIndex>
:窗口索引最小值<maxIndex>
:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12
。<fileNamePattern >
:必须包含“%i”
例如,假设最小值和最大值分别为1和2
,命名模式为mylog%i.log
,会产生归档文件mylog1.log
和mylog2.log
。还可以指定文件压缩选项,例如,mylog%i.log.gz
或者 没有log%i.log.zip
1.3.2.3.2 TriggeringPolicy
其中triggeringPolicy
的选项范围:
1.3.2.3.2.1 SizeBasedTriggeringPolicy
SizeBasedTriggeringPolicy
: 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender
触发当前活动文件滚动。只有一个节点:
<maxFileSize>
:这是活动文件的大小,默认值是10MB
。
eg
:每天生成一个日志文件,保存30天的日志文件。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
eg
:按照固定窗口模式生成日志文件,当文件大于20MB
时,生成新的日志文件。窗口大小是1
到3
,当保存了3个归档文件后,将覆盖最早的日志。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>test.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>tests.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
1.3.2.4 其他appender
还有SocketAppender、SMTPAppender、DBAppender、SyslogAppender、SiftingAppender
,并不常用,这些就不在这里讲解了,大家可以参考官方文档。当然大家可以编写自己的Appender
asyncAppender
定义了异步输出日志的方式,对于高并发时,可以使用异步输出来提高系统的性能
<!--异步输出日志信息-->
<appender name="asyncFile" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<appender-ref ref="file"/>
</appender>
1.3.3 encoder标签
<encoder>
:负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。
目前PatternLayoutEncoder
是唯一有用的且默认的encoder
,有一个<pattern>
节点,用来设置日志的输入格式。使用“%”
加“转换符”
方式,如果要输出“%”
,则必须用“\”
对“\%”
进行转义。
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<pattern>
里面的转换符说明:
转换符 | 作用 | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
c {length } lo {length } logger {length } | 输出日志的logger名,可有一个整形参数,功能是缩短logger名,设置为0表示只输入logger最右边点符号之后的字符串,规律如下:若长度length大于0,则最少显示各个点号旁的一个字母,直至长度length可以满足最右边点号的左边单词长度
| ||||||||||||||||||||||||
C {length } class {length } | 输出执行记录请求的调用者的全限定名。参数与上面的一样。尽量避免使用,除非执行速度不造成任何问题。 | ||||||||||||||||||||||||
contextName cn | 输出上下文名称。 | ||||||||||||||||||||||||
d {pattern } date {pattern } | 输出日志的打印日志,模式语法与java.text.SimpleDateFormat 兼容
| ||||||||||||||||||||||||
F file | 输出执行记录请求的java源文件名。尽量避免使用,除非执行速度不造成任何问题。 | ||||||||||||||||||||||||
caller{depth} caller{depth, evaluator-1, … evaluator-n} | 输出生成日志的调用者的位置信息,整数选项表示输出信息深度。 例如, %caller{2} 输出为: 0 [main] DEBUG - logging statement Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22) Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17) 例如, %caller{3} 输出为: 16 [main] DEBUG - logging statement Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22) Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17) Caller+2 at mainPackage.ConfigTester.main(ConfigTester.java:38) | ||||||||||||||||||||||||
L line | 输出执行日志请求的行号。尽量避免使用,除非执行速度不造成任何问题。 | ||||||||||||||||||||||||
m / msg / message | 输出应用程序提供的信息。 | ||||||||||||||||||||||||
M / method | 输出执行日志请求的方法名。尽量避免使用,除非执行速度不造成任何问题。 | ||||||||||||||||||||||||
n | 输出平台先关的分行符“\n”或者“\r\n”。 | ||||||||||||||||||||||||
p / le / level | 输出日志级别。 | ||||||||||||||||||||||||
r / relative | 输出从程序启动到创建日志记录的时间,单位是毫秒 | ||||||||||||||||||||||||
t / thread | 输出产生日志的线程名。 | ||||||||||||||||||||||||
replace(p ){r, t} | p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t 。 例如, “%replace(%msg){‘\s’, ‘’}” | ||||||||||||||||||||||||
X | 用于输出和当前线程相关联的NDC(嵌套诊断环境),在代码中给org.slf4j.MDC添加key/value即可增加新值,%X{testKey} 输出testKey所对应的value,且无默认值%X{testKey:-} 输出testKey所对应的value,默认为空%X{testKey:-aaa} 输出testKey所对应的value,默认为aaa |
格式修饰符,与转换符共同
使用:
- 可选的格式修饰符位于
"%"
和转换符
之间。 - 第一个可选修饰符是
左对齐
标志,符号是减号"-"
; - 接着是可选的
最小宽度
修饰符,用十进制数
表示。如果字符小于最小宽度,则左填充或右填充,默认是左填充(即右对齐)
,填充符为空格。如果字符大于最小宽度,字符永远不会被截断。 最大宽度
修饰符,符号是点号"."
后面加十进制数
。如果字符大于最大宽度,则从前面截断。点符号“.”
后面加减号“-”
在加数字,表示从尾部截断。
例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4。
1.3.4 logger标签
<logger>
用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>
。
<logger>
仅有一个name
属性,一个可选的level
和一个可选的addtivity
属性。
name
:用来指定受此logger
约束的某一个包或者具体的某一个类。level
:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前logger将会继承上级的级别。addtivity
:是否向上级logger
传递打印信息。默认是true
。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
用处: 使用mybatis
的时候,sql
语句是debug
下才会打印,而这里我们只配置了info
,所以想要查看sql语句的话,有以下两种操作:
- 把
<root level="info">
改成<root level="DEBUG">
这样就会打印sql
,不过这样日志那边会出现很多其他消息 - 单独给
dao
下目录配置debug
模式,代码如下,这样配置sql
语句会打印,其他还是正常info
级别
1.3.5 root标签
root
节点是必选节点,用来指定最基础的日志输出级别,只有一个level
属性
level
:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
,不能设置为INHERITED
或者同义词NULL
。默认是DEBUG
,可以包含零个或多个元素,标识这个appender
将会添加到这个logger
。
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
1.4 含有连字符的xml
当Spring Boot
中 logback
读取application.properties
中的属性其中使用的时候发现了一个问题,就是如果使用的lobback
配置文件的名称是logback.xml
会先出现先找不到设置的属性,然后项目启动起来才会找到,
比如:
<springProperty scope="context" name="log.path" source="logback.path" defaultValue="logs"/>
记录日志文件存放地址属性,会在项目启动的时候想出现一个找不到log.path_is_UNDIFIND
的目录,项目启动起来后才会读取到属性,在配置路径上生成日志文件。
可以通过将logback.xml
文件名称修改为logback-spring.xml
就不会出现这个情况。
SpringBoot
配置文件的加载顺序
logback.xml—>application.properties—>logback-spring.xml
1.5 logback.xml例子
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 用来加载logback的配置属性 -->
<!-- 使用classpath的方式引入文件,只需写明文件名即可-->
<property resource="logback.properties"/>
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="D:/nmyslog/nmys" />
<!-- 彩色日志格式 -->
<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 name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</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">
<!-- 日志归档 -->
<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为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.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">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.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">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</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>
<!--日志文件输出格式-->
<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">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--开发环境:打印控制台-->
<springProfile name="dev">
<logger name="com.nmys.view" level="debug"/>
</springProfile>
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!--生产环境:输出到文件-->
<!--<springProfile name="pro">-->
<!--<root level="info">-->
<!--<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>