一 logback简介
Logback是一个开源日志组件。Logback一般和SLF4结合起来使用。外层使用SLF4J,里面的实现是logback。什么意思,简单来说我们使用层看到的是SLF4J。我们使用的时候就是和SLF4J提供的一些api打交道。
我们可能经常听到SLF4J,logback,log4j,logging这些个名词。下面我们用一个简单的图来解释下他们之间的关系之间的关系。我们用一个图来表述他们之间的关系。
- SLF4J: Simple Logging Facade for Java 简单日志门面,不是具体的日志解决方案,它只服务于各种各样的日志系统。换句话说SLF4J只是一个日志标准(按照我们程序员的思维,我们可以把它认为是接口)。并不是日志系统的具体实现。如果项目只有slf4j的包是没办法实现日志功能的,需要配合其他的实现框架比如logback,logback,log4j,logging等。
- Logback:logback框架完全按照slf4j的规范开发。是日志的具体实现框架。
- log4j:log4j不是按照slf4j标准来开发的,所以log4j需要一个中间适配器。
- logging: logging是jdk提供的一个日志框架,也不是按照slf4j标准来的,所以也需要一个总结适配器。才能兼容slf4j。
因为logback的使用不需要适配器,讲道理logback比其他需要中间适配器的日志框架要快。
二 logback配置文件
logback使用最关键在配置文件的使用。因为在logbakc(包括其他的日志框架)的使用过程中,有很大一部分工作都是在配置文件上做文章的,比如需要输出什么级别的日志,日志文件怎么归档,打印日志文件的时候需要打印哪些信息等等。这些个东西都是通过logback的配置文件来定义的。
logback的配置文件是一个xml格式的文件logback-test.xml或者logback.xml,读取配置文件的步骤:
- (1)尝试classpath下查找文件logback-test.xml
- (2)如果文件不存在,尝试查找logback.xml
- (3)如果两个文件都不存在,LogBack用BasicConfiguration自动对自己进行最小化配置,这样既实现了上面我们不需要添加任何配置就可以输出到控制台日志信息。
logback配置文件是一个xml文件,根节点是configuration标签。如下就是一个完成的logback配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<!--
说明:
1、日志级别及文件
日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中
例如:error级别记录到xxx-error-xxx.log(该文件为当前记录的日志文件),而xxx-error-xxx.x.log为归档日志,
日志文件按日期记录,同一天内,若日志文件大小等于或大于2M,则按0、1、2...顺序分别命名
例如xxx-error-2013-12-21.0.log
其它级别的日志也是如此。
2、文件路径
若本地开发,以绝对路径指定,如:/Users/zhangboqing/Downloads/logs。
若部署到服务器,则各个服务器约定一个固定的日志路径如/data/home/logs/【项目名】/
3、Appender
FILE-ALL对应所有级别,文件名以xxx-all-xxx.log形式命名
FILE-ERROR对应error级别,文件名以xxx-error-xxx.log形式命名
FILE-WARN对应warn级别,文件名以xxx-warn-xxx.log形式命名
FILE-INFO对应info级别,文件名以xxx-info-xxx.log形式命名
FILE-DEBUG对应debug级别,文件名以xxx-debug-xxx.log形式命名
STDOUT将日志信息输出到控制上,为方便开发测试使用
-->
<!--
根节点<configuration>,包含下面三个属性
1.scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
2.scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
3.debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="10 seconds">
<!--
子节点<property name="" value=""> :用来定义变量值,它有两个属性name和value,通过<property>定义的值会被插入到logger上下文中,可以使“${}”来使用变量。
-->
<!--
子节点<property resource=""/> :用来引入外部属性文件,可以使“${}”来使用变量。
-->
<property name="APP_NAME" value="IoServer4J"/>
<property name="LOG_DIR" value="./logs/${APP_NAME}"/>
<property name="LOG_FILE_NAME" value="sys"/>
<property name="ERROR_LOG_FILE_NAME" value="error"/>
<property name="DB_LOG_FILE_NAME" value="db"/>
<property name="logFileNamePattern" value="${LOG_FILE_NAME}_%d{yyyy-MM-dd}_%i"/>
<property name="errorLogFileNamePattern" value="${ERROR_LOG_FILE_NAME}_%d{yyyy-MM-dd}_%i"/>
<property name="dbLogFileNamePattern" value="${DB_LOG_FILE_NAME}_%d{yyyy-MM-dd}_%i"/>
<!-- 注册转换器,颜色转化器 -->
<!-- 彩色日志依赖的渲染类 -->
<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"/>
<!-- 日志输出格式 -->
<!--
日志输出格式:
%d: 表示日期时间,
%5p: 级别从左显示5个字符宽度,
${PID:- }: pid
%15.20t: 线程名字(如果宽度不足15,左侧补空白;如果宽度超过20,从左侧截断)
%logger{50}: 表示logger名字最长50个字符,否则按照句点分割
%%-4L: 行号,保留后面四位字符宽度
%m: 日志消息
%n: 换行符
${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}:
-->
<property name="consoleLayoutPattern"
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.20t]){faint} %clr(%-40.40logger{60} Line:%-4L){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<property name="fileLayoutPattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.20t] %-40.40logger{60} Line:%-4L : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!--
子节点<contextName>:用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
-->
<contextName>${APP_NAME}</contextName>
<!--
子节点<appender>:负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名
class为ch.qos.logback.core.ConsoleAppender 把日志输出到控制台
class为ch.qos.logback.core.FileAppender 把日志添加到文件
class为ch.qos.logback.core.rolling.RollingFileAppender 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件
-->
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${consoleLayoutPattern}</pattern>
</encoder>
</appender>
<appender name="SYS_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${LOG_FILE_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${logFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${ERROR_LOG_FILE_NAME}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${errorLogFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory><!-- days -->
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
<appender name="DB_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${DB_LOG_FILE_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${dbLogFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory><!-- days -->
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
<!--
子节点<logger>:用来设置某一个包或者具体的某一个类的日志打印级别,以及指定<appender>,
logger 仅有一个name属性,两个可选属性 level/additivity
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关,TRACE,DEBUG,INFO,WARE,ERROR,ALL和OFF,还有一个特俗值INHERITED
或者 同义词NULL,代表强制执行上级的级别。
additivity:是否向上级logger传递打印信息。默认是true。
-->
<!-- db/sql logger -->
<logger name="java.sql.Connection" level="warn" additivity="true">
<appender-ref ref="DB_LOG"/>
</logger>
<logger name="java.sql.PreparedStatement" level="warn" additivity="true">
<appender-ref ref="DB_LOG"/>
</logger>
<logger name="java.sql.Statement" level="warn" additivity="true">
<appender-ref ref="DB_LOG"/>
</logger>
<!-- sql -->
<logger name="com.pilot.ioserver.basic.biz.pbl.core.db.mapper" level="warn" additivity="true">
<appender-ref ref="DB_LOG"/>
</logger>
<!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
<!--
<root>元素也是<logger>元素,logger。只有一个level属性。
root 元素配置根 logger。该元素有一个 level 属性。没有 name 属性,因为已经被命名为“root”
<root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。
-->
<root level="warn">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
<!-- 文件输出 -->
<appender-ref ref="SYS_LOG"/>
<!-- 错误日志 -->
<appender-ref ref="ERROR_LOG"/>
</root>
</configuration>
2.1 configuration
configuration标签是logback文件的根目录。
2.1.1 configuration属性
configuration属性 | 默认值 | 解释 |
---|---|---|
scan | true | 当设置为true时,如果配置文件发生改变,将会被重新加载 |
scanPeriod | 1分钟 | 默认单位是毫秒,当scan为true时,此属性生效。作用:检测配置文件是否有修改时间间隔 |
debug | false | 当此属性为true时,将打印出logback内部日志信息,实时查看logback运行状态 |
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--其他配置省略-->
</configuration>
上述配置代码每隔60毫秒会检查logback配置文件是否有修改,如果有修改就重写加载。并且不会输出logback的内部日志。
2.1.2 configuration子节点
configuration子节点 | 含义 |
---|---|
contextName | 设置日志上下文名称,后面输出格式中可以通过定义 %contextName 来打印日志上下文名称 |
property | 用来设置相关变量,通过key-value的方式配置,然后在后面的配置文件中通过 ${key}来访问 |
timestamp | 用于获取时间戳字符串 |
conversionRule | 注册转换器,颜色转化器 |
appender | 负责写日志的组件,主要负责日志的输出以及格式化日志 |
logger | 用来设置某一个包或者具体的某一个类的日志输出级别,以及指定<appender> |
root | 用来指定最基础的日志输出级别 |
filter | 通过使用该标签指定过滤策略 |
encoder | 使用该标签下的标签指定日志输出格式 |
rollingPolicy | 指定收集策略,比如基于时间进行收集 |
2.2 contextName
contextName标签用于设置日志上下文名称,后面输出格式中可以通过定义%contextName来打印日志上下文名称。每个logger都关联到logger上下文,默认上下文名称为default。可以使用<contextName>设置成其他名字,用于区分不同的应用程序的记录。一旦设置,不能修改。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>myAppName</contextName>
<!--其他配置省略-->
</configuration>
2.3 property
property标签用来设置相关变量,通过key-value的方式配置,然后在后面的配置文件中通过 ${key}来访问。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_Name" value="myAppName"></property>
<contextName>${APP_Name}</contextName>
<!--其他配置省略-->
</configuration>
2.4 timestamp
timestamp标签用于获取时间戳字符串,有两个属性key和datePattern。
timestamp属性 | 解释 |
---|---|
key | 标识此<timestamp>的名字 |
datePattern | 设置将当前时间(即解析配置文件的时间)转换为字符串,遵循java.txt.SimpleDateFormat的格式 |
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<timestamp key="bySecond"datePattern="yyyyMMdd'T'HHmmss"></timestamp>
<contextName>${bySecond}</contextName>
</configuration>
2.5 appender
appender标签负责主要负责日志的输出以及格式化日志。当一个日志记录被触发的时候,logback会根据我们的配置信息把这个事件交给appender处理。appender有两个必要属性name和class。
appender属性
appender属性 | 解释 |
---|---|
name | 指定appender名称 |
class | 指定appender的全限定名 |
append属性class设置的不同,append子节点也不同,所以这里我们直接看appender对应的class类型有哪些。
appender class 类型
appender类型 | class全限定名 | 解释 |
---|---|---|
ConsoleAppender | ch.qos.logback.core.ConsoleAppender | 把日志输出到控制台 |
FileAppender | ch.qos.logback.core.FileAppender | 把日志输出到文件 |
RollingFileAppender | ch.qos.logback.core.rolling.RollingFileAppender | 滚动记录文件,先将日志文件指定到文件,当符合某个条件是,将日志记录到其他文件 |
SocketAppender | ch.qos.logback.classic.net.SocketAppender | 输出日志到远程实例中,明文 |
SSLSocketAppender | ch.qos.logback.classic.net.SSLSocketAppender | 输出日志到远程实例中,加密 |
SMTPAppender | ch.qos.logback.classic.net.SMTPAppender | 将日志以邮件的形式发出 |
DBAppender | ch.qos.logback.classic.db.DBAppender | 将日志保存在数据库中 |
SyslogAppender | ch.qos.logback.classic.net.SyslogAppender | 将日志发送给远程的receiver |
SiftingAppender | ch.qos.logback.classic.sift.SiftingAppender | SiftingAppender提供过滤筛选日志的功能。你可以通过用户的sessions的数据来筛选日志,然后分发到不同日志文件 |
AsyncAppender | ch.qos.logback.classic.AsyncAppender | 记录ILoggingEvents的方式是异步的。它仅仅相当于一个event分配器,因此需要配合其他appender才能有所作为 |
ConsoleAppender、FileAppender、RollingFileAppender。这几个appender是最常用的,我们对他们的使用做一个简单的介绍。
2.5.1 ConsoleAppender
ConsoleAppender用于把日志输出到控制台。
如下配置会把DEBUG级别的日志输出到控制台。
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
ConsoleAppender节点介绍。
ConsoleAppender子节点 | 解释 |
---|---|
encoder | 对日志进行格式化 |
target | 字符串System.out(默认)或者System.err |
filter | 对某些日志做过滤 |
2.5.2 FileAppender
FileAppender用于把日志添加到文件。
比如如下的配置会把DEBUG级别的日志输出到log-${bySecond}.txt文件。
<configuration>
<!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
the key "bySecond" into the logger context. This value will be
available to all subsequent configuration elements. -->
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- use the previously created timestamp to create a uniquely
named log file -->
<file>log-${bySecond}.txt</file>
<encoder>
<pattern>%logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
FileAppender节点介绍。
FileAppender子节点 | 解释 |
---|---|
file | 被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值 |
append | 默认为true。如果是true,日志被追加到文件结尾,如果是false,清空现存文件 |
encoder | 对记录事件进行格式化 |
prudent | 默认为false。如果是true,日志会被安全的写入文件,即其他的FileAppender也在向此文件做写入操作,效率低 |
filter | 对某些日志做过滤 |
2.5.3 RollingFileAppender
RollingFileAppender是对FileAppender的一个扩展。相较于它的父类,它的主要作用是滚动记录日志。先将日志文件指定到文件,当符合某个条件时,将日志记录到其他文件。所以这里有两个重要的点,一是什么时候滚动(触发triggeringPolicy)、二是发生滚动的时候怎么去保存文件(动作,策略rollingPolicy)。
RollingFileAppender节点介绍。
RollingFileAppender子节点
RollingFileAppender子节点 | 解释 |
---|---|
file | 被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值,就说说日志会先保存在这个文件里面 |
append | 默认为true。如果是true,日志被追加到文件结尾,如果是false,清空现存文件 |
encoder | 对记录事件进行格式化 |
rollingPolicy | 发送滚动是,RollingFileAppender的行为。例如日志文件名的修改 |
triggeringPolicy | 决定什么时候发送日志滚动,例如日期,日志文件大小到达一定值 |
prudent | 当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空 |
filter | 对某些日志做过滤 |
2.5.3.1 rollingPolicy介绍
rollingPolicy节点用于定义当发生日志切换时(发生日志滚动是),RollingFileAppender的切换行为。例如日志文件名的修改。(RollingPolicy实际上就是负责日志文件的切换以及重命名的)。logback里面已经给我们提供个多种切换的实现类。下面我们对这些实现类做一个简单的介绍。
rollingPolicy类型 | 解释 |
---|---|
TimeBasedRollingPolicy | 是最受欢迎的日志滚动策略。它的滚动策略是基于时间的,例如根据天数,月份 |
SizeAndTimeBasedRollingPolicy | 有时候你不仅想通过时间来规定滚动策略,还希望同时限制每个日志文件的大小。在TimeBasedRoolingPolicy中已经提供限制总日志文件的大小的功能,而SizeAndTimeBasedRollingPolicy提供了更为强大的,针对单个日志文件的大小限制能力 |
FixedWindowRollingPolicy | 固定窗口的日志滚动策略 |
2.5.3.1.1 TimeBasedRollingPolicy
是最受欢迎的日志滚动策略。它的滚动策略是基于时间的。根据时间触发滚动(fileNamePattern属性会解析到),同时可以设置保留的文件的最大大小(超过最大大小就会把之前的覆盖掉),以及最大保留的粒度(如果是触发保存是按天来的,可以设置最大保留多少天的日志。如果是月,可以设置最多保留多少月等等)。
注意,TimeBasedRollingPolicy已经包含了triggeringPolicy节点的功能。所以设置了rollingPolicy为TimeBasedRollingPolicy就不需要在设置triggeringPolicy了。
比如如下的配置,会每天保存一个日志文件,并且最大保存30天的日志,同时限制所以日志文件的最大大小为3G。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
TimeBasedRollingPolicy属性介绍。
TimeBasedRollingPolicy属性 | 类型 | 解释 |
---|---|---|
fileNamePattern | String | 必要节点,包含文件名及"%d"转换符,"%d"可以包含一个java.text.SimpleDateFormat指定的时间格式,默认格式是yyyy-MM-dd。也可以设置其他格式,如:%d{yyyy-MM} |
maxHistory | int | 可选参数,声明归档日志最大保留时间。如果你是基于月份的日志滚动,则当maxHisory为6时,说明会保留6个月的日志。大于6个月的就会被删除。日志所存在的目录也会被合适的删除掉 |
totalSizeCap | String | 可选参数,声明归档日志的最大存储量。当超过这个值,最老的归档日志文件也会被删除 |
cleanHistoryOnStart | boolean | 可选参数,声明归档日志的最大存储量。当超过这个值,最老的归档日志文件也会被删除 可选参数,默认为false,如果设置为true,则当appender启动时,会删除所有归档日志文件 |
旧版本的logback里可以在TimeBasedRollingPolicy这个rollingPolicy下配置一个timeBasedFileNamingAndTriggeringPolicy(实现类为SizeAndTimeBasedFNATP)达到同时配置时间和文件大小的滚动策略;而在新版本里可以使用SizeAndTimeBasedRollingPolicy替代。
2.5.3.1.2 SizeAndTimeBasedRollingPolicy
有时候你不仅想通过时间来规定滚动策略,还希望同时限制每个日志文件的大小。在TimeBasedRoolingPolicy中已经提供限制总日志文件的大小的功能,而SizeAndTimeBasedRollingPolicy提供了更为强大的针对单个日志文件的大小限制能力。
比如如下的配置,按天触发日志的保存,同时限制了单个文件的大小。所以每天可能有多个日志文件。关于fileNamePattern的使用我们会在下文中讲到。
<configuration>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="ROLLING" />
</root>
</configuration>
SizeAndTimeBasedRollingPolicy属性介绍,SizeAndTimeBasedRollingPolicy继承TimeBasedRollingPolicy就额外的多一个属性maxFileSize
SizeAndTimeBasedRollingPolicy属性 | 类型 | 解释 |
---|---|---|
fileNamePattern | String | 必要节点,包含文件名及"%d"转换符,"%d"可以包含一个java.text.SimpleDateFormat指定的时间格式,默认格式是yyyy-MM-dd。也可以设置其他格式,如:%d{yyyy-MM} |
maxHistory | int | 可选参数,声明归档日志最大保留时间。如果你是基于月份的日志滚动,则当maxHisory为6时,说明会保留6个月的日志。大于6个月的就会被删除。日志所存在的目录也会被合适的删除掉 |
totalSizeCap | String | 可选参数,声明归档日志的最大存储量。当超过这个值,最老的归档日志文件也会被删除 |
cleanHistoryOnStart | boolean | 可选参数,声明归档日志的最大存储量。当超过这个值,最老的归档日志文件也会被删除 可选参数,默认为false,如果设置为true,则当appender启动时,会删除所有归档日志文件 |
maxFileSize | String | 限定单个日志文件的大小 |
2.5.3.1.3 FixedWindowRollingPolicy
基于窗口大小的滚动策略。这个听起来可能有点难理解,其实说白了就是将归档日志文件到最大了就写到下一个文件里,而窗口大小就是最多允许多少份日志文件。要特别注意FixedWindowRollingPolicy是没有告知什么时候触发日志的保存的。所以FixedWindowRollingPolicy的使用需要配合triggeringPolicy标签一起使用,而且一般triggeringPolicy标签会设置SizeBasedTriggeringPolicy。
比如如下的配置,保存DEBUG级别的日志,并且每5MB保存一个文件,窗口大小是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>
FixedWindowRollingPolicy属性属性介绍。
FixedWindowRollingPolicy属性 | 类型 | 解释 |
---|---|---|
minIndex | int | 这个参数指定窗口索引的最小值 |
maxIndex | int | 这个参数指定窗口索引的最大值 |
fileNamePattern | String | 这个参数与之前的fileNamePattern没什么差别,唯一需要注意的是必须包含%i标识符,这个标识符的作用是指明当前窗口索引的值。例如将fileNamePattern设置成 "MyLogFile%i ",minIndex为1,maxIndex为3,则会创建MyLogFile1.log, MyLogFile2.log and MyLogFile3.log.这三个归档日志文件。 |
特别要注意,如果rollingPolicy标签设置为FixedWindowRollingPolicy。一定要设置triggeringPolicy标签的内容。要不然是没办法触发保存日志的。
2.5.3.2 triggeringPolicy介绍
triggeringPolicy标签设置的值用于告知RollingFileAppender什么时候触发滚动操作。上面rollingPolicy介绍的各种rollingPolicy类型里面,其实TimeBasedRollingPolicy和SizeAndTimeBasedRollingPolicy已经包含了triggeringPolicy的功能(会通过fileNamePattern属性解析出来),只有FixedWindowRollingPolicy是没有triggeringPolicy功能的,所以FixedWindowRollingPolicy要设置triggeringPolicy。一般都是设置SizeBasedTriggeringPolicy。
SizeBasedTriggeringPolicy只有一个属性,就是文件大小。当到达了设置的大小的时候RollingFileAppender就触发一次滚动操作。
SizeBasedTriggeringPolicy属性 | 类型 | 解释 |
---|---|---|
maxFileSize | String | 默认10MB, 当到达这个容量,就开启日志滚动 |
2.6 filter
logback的过滤器可以过滤记录日志的内容,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一。从而将不符合条件的日志信息过滤掉。
- DENY: 日志将立即被抛弃不再经过其他过滤器。
- NEUTRAL: 有序列表里的下个过滤器过接着处理日志。
- ACCEPT: 日志会被立即处理,不再经过剩余过滤器。
过滤器被添加到<Appender>中,为<Appender>添加一个或多个过滤器后,可以用任意条件对日志进行过滤。<Appender>有多个过滤器时,按照配置顺序执行。
关于Filter的实现类有多种,这里我们主要讲两种:LevelFilter以及ThresholdFilter.
2.6.1 LevelFilter
级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。
LevelFilter子节点 | 解释 |
---|---|
level | 设置过滤级别 |
onMatch | 用于配置符合过滤条件的操作 |
onMismatch | 用于配置不符合过滤条件的操作 |
比如以下的配置,只接受ERROR级别的日志,非ERROR级别的日志都会被过滤掉。
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${ERROR_LOG_FILE_NAME}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${errorLogFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory><!-- days -->
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
2.6.2 ThresholdFilter
临界值过滤器,过滤掉低于指定临界值的日志。ThresholdFilter只有一个level子节点可以设置。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。
比如如下的配置,过滤掉TRACE和DEBUG级别的日志。
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${ERROR_LOG_FILE_NAME}.log</file>
<!-- 过滤掉 TRACE 和 DEBUG 级别的日志-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${errorLogFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory><!-- days -->
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
2.6.3 EvaluatorFilter
求值过滤器,评估、鉴别日志是否符合指定条件。需要额外的两个JAR包,commons-compiler.jar和janino.jar。
EvaluatorFilter子节点 | 解释 |
---|---|
evaluator | 鉴别器,常用的鉴别器是JaninoEventEvaluato,也是默认的鉴别器,它以任意的java布尔值表达式作为求值条件,求值条件在配置文件解释过成功被动态编译,布尔值表达式返回true就表示符合过滤条件。evaluator有个子标签<expression>,用于配置求值条件 |
onMatch | 用于配置符合过滤条件的操作 |
onMismatch | 用于配置不符合过滤条件的操作 |
这里注意下evaluator子节点的使用,。evaluator有个子标签<expression>,用于配置求值条件。求值表达式作用于当前日志,logback向求值表达式暴露日志的各种字段如下:
expression可以使用字段 | 类型 | 含义 |
---|---|---|
event | LoggingEvent | 与记录请求相关联的原始记录事件,下面所有变量都来自event,例如,event.getMessage()返回下面"message"相同的字符串 |
message | String | 日志的原始消息,例如,设有logger mylogger,"name"的值是"AUB",对于 mylogger.info("Hello {}",name); "Hello {}"就是原始消息。 |
formatedMessage | String | 日志被各式话的消息,例如,设有logger mylogger,"name"的值是"AUB",对于 mylogger.info("Hello {}",name); "Hello Aub"就是格式化后的消息。 |
logger | String | logger 名。 |
loggerContext | LoggerContextVO | 日志所属的logger上下文。 |
level | int | 级别对应的整数值,所以 level > INFO 是正确的表达式。 |
timeStamp | long | 创建日志的时间戳。 |
marker | Marker | 与日志请求相关联的Marker对象,注意“Marker”有可能为null,所以你要确保它不能是null |
mdc | Map | 包含创建日志期间的MDC所有值得map。访问方法是:mdc.get("myKey") 。mdc.get()返回的是Object不是String,要想调用String的方法就要强转,例如,((String) mdc.get("k")).contains("val") .MDC可能为null,调用时注意。 |
throwable | java.lang.Throwable | 如果没有异常与日志关联"throwable" 变量为 null. 不幸的是, "throwable" 不能被序列化。在远程系统上永远为null,对于与位置无关的表达式请使用下面的变量throwableProxy |
throwableProxy | IThrowableProxy | 与日志事件关联的异常代理。如果没有异常与日志事件关联,则变量"throwableProxy" 为 null. 当异常被关联到日志事件时,"throwableProxy" 在远程系统上不会为null |
比如如下的配置,过滤掉所有日志消息中不包含“billing”字符串的日志。
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${ERROR_LOG_FILE_NAME}.log</file>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("billing");</expression>
</evaluator>
<OnMatch>ACCEPT </OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${errorLogFileNamePattern}.log.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory><!-- days -->
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>${fileLayoutPattern}</pattern>
</encoder>
</appender>
2.7 logger,root
2.7.1 logger
用来设置某一个包或者具体某一个类的日志打印级别,以及指定<appender>。什么意思。
logger属性 | 解释 |
---|---|
name | 用来指定受此loger约束的某一个包或者具体的某一个类 |
level | 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前loger将会继承上级(root标签)的级别 |
addtivity | 是否向上级loger传递打印信息。默认是true |
关于addtivity。如果addtivity设置为true,那么当前logger标签作用完之后,logger标签对应类或者包的父类,继续作用一直到root标签。如果addtivity设置为false,那么当前logger标签作用完之后就直接掐断了,不在继续往上走了。
<loger>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个loger。<appender-ref>标签就是去指定日志的相应操作,不管是控制台输出,还是保存到文件,还是滚动日志输出啥的。
2.7.2 root
<root>也是<loger>元素,但是它是根loger。只有一个level属性。用来设置打印级别。
root是不用指定包或者类的,我们可以简单的认为root指定了所有的包.
这里要重点说下logger和root的关系。怕有些同学搞混掉.我们通过几个例子来说明。
2.7.3 root,logger关系
关于root和logger之间的关系要重点讲下。当root和logger同时存在的时候。要特别注意logger和root标签两者最终的level;和logger标签是否设置了向上传递的属性。
- logger没有设置level,那么logger直接继承root的level(如果有多个logger并且logger直接有上下级关系的话,就一层一层往上)。
- logger设置了level,同时如果logger设置了向上传递的话(additivity="true")。那么root标签和logger相同的包也使用logger的level。
2.7.3.1 情况一
<logger name="com.tuacy.logback"/>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
因为logger没有设置等级,直接继承root的等级.addtivity默认就是true向上传递.可以认为当com.tuacy.logback包里面某个类打印日志的时候使用的配置为.
<logger name="com.tuacy.logback" level="info" additivity="true"/>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
logger没有设置appender-ref所以logger没啥用,不打印,这个时候只有root设置起作用,com.tuacy.logback包下面的类info,warn,error的日志都会打印出来。
2.7.3.2 情况二
<logger name="com.tuacy.logback" additivity="false"/>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
logger没有设置等级,继承root的等级,additivity为false,不往上传递,root不作用。配置相当于
<logger name="com.tuacy.logback" additivity="false"/>
如果这个时候有com.tuacy.logback包或者子包有打印的时候,不会有任何打印信息。
2.7.3.3 情况三
<logger name="com.tuacy.logback" level="error"/>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
logger和root都有设置等级取两者等级较高的。所以上述配置等价于
<logger name="com.tuacy.logback" level="error" additivity="true"/>
<root level="error">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
这个时候只有error级别的信息会打印出来,root也使用logger的level。注意,只是针对com.tuacy.logback包和他的子包root的等级改变了。其他的包root还是保持原来的level。
2.7.3.4 情况四
<logger name="com.tuacy.logback" level="error" additivity="false"/>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
上述配置等价于
<logger name="com.tuacy.logback" level="error" additivity="false"/>
不会有打印的
2.7.3.5 情况五
<logger name="com.tuacy.logback" level="error">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</logger>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
上述配置等价于
<logger name="com.tuacy.logback" level="error">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
会打印error级别的日志,而且会打印两次。logger的一次,root的一次。
2.7.3.6 情况六
<logger name="com.tuacy.logback" level="error" additivity="false">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</logger>
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</root>
上述配置等价于
<logger name="com.tuacy.logback" level="error" additivity="false">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
</logger>
所以只会打印一次error级别的日志信息。
2.8 日志模板配置
日志模板配置,使用%为前缀让解析器识别特殊输出模式,然后以{}后缀结尾,内部指定相应的参数设置。
2.8.1 模板输入参数
模板输入参数 | 对应的类 | 对应输出 |
---|---|---|
d | DateConverter | 输出logger时间 |
date | DateConverter | 输出logger时间 |
r | RelativeTimeConverter | 输出应用启动到日志时间触发时候的毫秒数 |
relative | RelativeTimeConverter | 输出应用启动到日志时间触发时候的毫秒数 |
level | LevelConverter | 输出logger对应的等级 |
le | LevelConverter | 输出logger对应的等级 |
p | LevelConverter | 输出logger对应的等级 |
t | ThreadConverter | 输出logger对应线程名字 |
thread | ThreadConverter | 输出logger对应线程名字 |
lo | LoggerConverter | 输出logger对应的名字 |
logger | LoggerConverter | 输出logger对应的名字 |
c | LoggerConverter | 输出logger对应的名字 |
m | MessageConverter | 输出logger对应的信息 |
msg | MessageConverter | 输出logger对应的信息 |
message | MessageConverter | 输出logger对应的信息 |
C | ClassOfCallerConverter | 输出调用方发布日志事件的完整类名 |
class | ClassOfCallerConverter | 输出调用方发布日志事件的完整类名 |
M | MethodOfCallerConverter | 输出发布日志请求的方法名 |
method | MethodOfCallerConverter | 输出发布日志请求的方法名 |
L | LineOfCallerConverter | 输出log请求的行数 |
line | LineOfCallerConverter | 输出log请求的行数 |
F | FileOfCallerConverter | 输出发布日志请求的java源码的文件名 |
file | FileOfCallerConverter | 输出发布日志请求的java源码的文件名 |
X | MDCConverter | 输出和发布日志事件关联的线程的MDC |
mdc | MDCConverter | 输出和发布日志事件关联的线程的MDC |
ex | ThrowableProxyConverter | 输出和日志事件关联的异常的堆栈信息 |
exception | ThrowableProxyConverter | 输出和日志事件关联的异常的堆栈信息 |
rEx | RootCauseFirstThrowableProxyConverter | 输出和日志事件关联的异常的堆栈信息 |
rootException | RootCauseFirstThrowableProxyConverter | 输出和日志事件关联的异常的堆栈信息 |
throwable | ThrowableProxyConverter | 输出和日志事件关联的异常的堆栈信息 |
xEx | ExtendedThrowableProxyConverter | 和上面一样,此外增加类的包信息 |
xException | ExtendedThrowableProxyConverter | 和上面一样,此外增加类的包信息 |
xThrowable | ExtendedThrowableProxyConverter | 和上面一样,此外增加类的包信息 |
nopex | NopThrowableInformationConverter | 当我们想不输出异常信息时,使用这个。其假装处理异常,其实无任何输出 |
nopexception | NopThrowableInformationConverter | 当我们想不输出异常信息时,使用这个。其假装处理异常,其实无任何输出 |
cn | ContextNameConverter | 输出在类附加到日志上的上下文名字 |
contextName | ContextNameConverter | 输出在类附加到日志上的上下文名字 |
caller | CallerDataConverter | 输出产生日志事件的调用者的位置信息 |
marker | MarkerConverter | 输出和日志请求关联的marker |
property | PropertyConverter | 输出属性对应的值,一般为System.properties中的属性 |
n | LineSeparatorConverter | 输出依赖系统的行分隔符 |
black | BlackCompositeConverter | 颜色格式black |
red | RedCompositeConverter | 颜色格式red |
green | GreenCompositeConverter | 颜色格式green |
yellow | YellowCompositeConverter | 颜色格式yellow |
blue | BlueCompositeConverter | 颜色格式blue |
magenta | MagentaCompositeConverter | 颜色格式magenta |
cyan | CyanCompositeConverter | 颜色格式cyan |
white | WhiteCompositeConverter | 颜色格式white |
gray | GrayCompositeConverter | 颜色格式gray |
boldRed | BoldRedCompositeConverter | 颜色格式boldRed |
boldGreen | BoldGreenCompositeConverter | 颜色格式boldGreen |
boldYellow | BoldYellowCompositeConverter | 颜色格式boldYellow |
boldBlue | BoldBlueCompositeConverter | 颜色格式boldBlue |
boldMagenta | BoldMagentaCompositeConverter | 颜色格式boldMagenta |
boldCyan | BoldCyanCompositeConverter | 颜色格式boldCyan |
boldWhite | BoldWhiteCompositeConverter | 颜色格式boldWhite |
highlight | HighlightingCompositeConverter | 颜色格式highlight |
lsn | LocalSequenceNumberConverter | 颜色格式lsn |
d,data可以配置额外的参数,用来确定日期格式。输出日志的打印日志,模式语法与java.text.SimpleDateFormat 兼容。
c、lo、logger输出日志的logger名,可有一个整形参数,功能是缩短logger名,设置为0表示只输入logger最右边点符号之后的字符串
模板 | 数据源 | 结果 |
---|---|---|
%logger | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar |
%logger{0} | mainPackage.sub.sample.Bar | Bar |
%logger{5} | mainPackage.sub.sample.Bar | m.s.s.Bar |
%logger{10} | mainPackage.sub.sample.Bar | m.s.s.Bar |
%logger{15} | mainPackage.sub.sample.Bar | m.s.sample.Bar |
%logger{16} | mainPackage.sub.sample.Bar | m.sub.sample.Bar |
%logger{26} | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar |
2.8.2 模板长度设置
每个模板配置都是可以限制模长度的,上面介绍了模块可以设置那么多的输入参数,其实每个输入参数都是可以限制长度的。
日志模板配置 | 解释 |
---|---|
%5p | 级别从左显示5个字符宽度(从左到右) |
%-4L | 行号,保留后面四位字符宽度(从右到左) |
%15.20t | 线程名字(如果宽度不足15,左侧补空白;如果宽度超过20,从左侧截断) |
三 spring boot项目使用logback
3.1 pom依赖
在Spring Boot项目中要使用logback原则上是要添加spring-boot-starter-logging依赖的。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
但是因为我们使用Spring Boot肯定会添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
又因为spring-boot-starter里面已经包含了对于spring-boot-starter-logging的依赖,所以我们一般在项目中不用显示的添加spring-boot-starter-logging。
3.1 logback配置文件
spring boot项目中使用logback.关于配置文件官方推荐使用的xml名字的格式为:logback-spring.xml而不是logback.xml(当然了,你也可以使用logback.xml),因为带spring后缀的可以使用<springProfile>这个标签来控制比如生成环境还是调试环境。比如如下的配置分了对生成环境和开发环境做了一个简单的区分.
<configuration scan="true" scanPeriod="10 seconds">
...
<!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
<!--
<root>元素也是<logger>元素,logger。只有一个level属性。
root 元素配置根 logger。该元素有一个 level 属性。没有 name 属性,因为已经被命名为“root”
<root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。
-->
<springProfile name="dev">
<root level="info">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
<!-- 文件输出 -->
<appender-ref ref="SYS_LOG"/>
<!-- 错误日志 -->
<appender-ref ref="ERROR_LOG"/>
</root>
</springProfile>
<springProfile name="pro">
<root level="warn">
<!-- 控制台输出 -->
<appender-ref ref="CONSOLE"/>
<!-- 文件输出 -->
<appender-ref ref="SYS_LOG"/>
<!-- 错误日志 -->
<appender-ref ref="ERROR_LOG"/>
</root>
</springProfile>
</configuration>