这里主要说一下log4j和logback的日志配置,其实他俩的配置差不多,只是写法上略有不同,log4j可以使用properties文件配置也可以使用xml进行配置,这里先分别抛出log4j.xml和logback.xml的配置,混个脸熟,方便下面各个组件内容的说明。
- log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >
<appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] {%p} %c %L - %m%n" />
</layout>
<param name="Encoding" value="UTF-8"/>
</appender>
<appender name="myFile" class="org.apache.log4j.RollingFileAppender">
<!-- 设置日志输出文件名 -->
<param name="File" value="D:/pandora.log" />
<!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
<param name="Append" value="true" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
</layout>
</appender>
<appender name="activexAppender" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="E:/pandora.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
</layout>
</appender>
<!-- 指定logger的设置,additivity指示是否遵循缺省的继承机制-->
<logger name="com.tp.pandora" additivity="false">
<level value ="info"/>
<appender-ref ref="activexAppender" />
</logger>
<!-- 根logger的设置,其他的logger会继承此logger-->
<root>
<level value="DEBUG" />
<appender-ref ref="myConsole"/>
<appender-ref ref="myFile"/>
</root>
</log4j:configuration>
- logback.xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径以当前所在的路径为.路径,例如在tomcat/bin/下以./start.sh启动,那么
logs在tomcat/logs下,如果当下路径在/usr 执行/usr/{tomcat}/bin/start.sh那么日志在/usr下的logs中-->
<fileNamePattern>logs/${contextName}.log-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%date [%contextName] %level [%thread] %logger{36} [%file:%line] %msg%n</pattern>
</encoder>
<append>false</append>
<prudent>false</prudent>
<!--<filter class="ch.qos.logback.classic.filter.LevelFilter">-->
<!--<level>ERROR</level>-->
<!--<onMatch>DENY</onMatch>-->
<!--<onMismatch>ACCEPT</onMismatch>-->
<!--</filter>-->
</appender>
<!--错误日志打印文件-->
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/${contextName}-error.log-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%date [%contextName] %level [%thread] %logger{36} [%file:%line] %msg%n</pattern>
</encoder>
<append>false</append>
<prudent>false</prudent>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!--只打印错误日志-->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="com.ibatis" level="DEBUG"></logger>
<logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG"></logger>
<logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"></logger>
<logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="DEBUG"></logger>
<logger name="java.sql.Connection" level="DEBUG"></logger>
<logger name="java.sql.Statement" level="DEBUG"></logger>
<logger name="java.sql.PreparedStatement" level="DEBUG"></logger>
<!--去掉org包的日志打印,防止日志淹没-->
<logger name="org" level="ERROR"/>
<logger name="us.codecraft" level="ERROR"/>
<!--<logger name="org.apache.shiro" level="DEBUG"/>-->
<!--<logger name="org.crazycake.shiro" level="DEBUG"/>-->
<!--返回数据不需要打印-->
<!--<logger name="org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor" level="DEBUG"/>-->
<!--所有日志打印级别及打印方式-->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="logFile"/>
</root>
</configuration>
根节点<configuration>
根节点包含以下几个属性:
- scan
当此属性设置为true时,配置文件如果发生改变,将会被重新加载。
默认值为true。 - scanPeriod:
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。
默认的时间间隔为1分钟。 - debug
当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。
默认值为false。
设置上下文名称:<contextName>
根节点<configuration>下的子节点<contextName>标签可以设置上下文名称,默认上下文名称为“default”,用于区分不同应用程序的记录。一旦设置,不能修改。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>myAppName</contextName>
<!-- 其他配置省略-->
</configuration>
设置变量:<property>
根节点<configuration>下的子节点<property>标签可以设置自定义变量,<property>有两个属性:
- name:变量的名称
- value:变量定义的值
通过<property>定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_Name" value="myAppName" />
<contextName>${APP_Name}</contextName>
<!-- 其他配置省略-->
</configuration>
获取时间戳字符串:<timestamp>
根节点<configuration>下的子节点<timestamp>标签可以获取时间戳,<timestamp>有两个属性:
- key:此<timestamp>的名字
- datePattern:设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循java.txt.SimpleDateFormat的格式。
例如将解析配置文件的时间作为上下文名称:
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<contextName>${bySecond}</contextName>
<!-- 其他配置省略-->
</configuration>
Appender(输出源)
appender可以指定我们的日志输出的目的地,可以输出到控制台,也可以输出到指定文件。
常用的类有:
- org.apache.log4j.ConsoleAppender(输出到控制台)
- org.apache.log4j.FileAppender(输出到指定文件)
- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
- org.apache.log4j.RollingFileAppender(输出到指定文件,并根据滚动策略滚动)
- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
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>
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>
RollingFileAppender
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:
- <file>:被写入的文件路径(实时日志文件路径及名称),可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
- <append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
- <encoder>:对记录事件进行格式化
- <rollingPolicy>:滚动策略,当发生滚动时决定RollingFileAppender的行为,涉及文件移动和重命名。
- <triggeringPolicy >: 告知RollingFileAppender何时激活滚动。
- <prudent>:当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy。
但是有两个限制:1.不支持也不允许文件压缩,2.不能设置file属性,必须留空。
关于子节点<rollingPolicy>
-
TimeBasedRollingPolicy
最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责触发滚动。有以下子节点:
1.<fileNamePattern>(必要节点)
该属性定义了过渡(存档)日志文件的路径及名称,应包含文件名及“%d”转换符,注意其中“%d”可以包含一个java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。如果直接使用%d,默认格式是 yyyy-MM-dd,logback通过从fileNamePattern的值推断出过渡期(根据%d)。
RollingFileAppender的<file>子节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置:
如果设置了<file>,当前日志总是记录到<file>指定的文件(活动文件),活动文件的名字不会改变。
如果没设置<file>,活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。
更通俗的理解就是:
1.RollingFileAppender的file属性可以设置,也可以忽略。
2.如果设置了FileAppender包含的属性file,系统实时生成的日志和根据日期生成的日志可以存储在不同的目录文件下。在这种情况下,系统实时生成的日志内容都会记录在file属性指定的文件中。因此,该日志文件名称不会随着时间的移动而更改。
3.如果忽略了FileAppender包含的属性file,活动文件的名字会根fileNamePattern的值,每隔一段时间改变一次,即每隔一段时间会生成一个日志文件
例如:
<appender name="emergencyLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 写入日志内容的文件名称(目录) -->
<File>log/check.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次
因为配置的是yyyy-MM-dd所以会每天归档一次
-->
<fileNamePattern>log/check.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 每产生一个归档日志文件,该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<!-- pattern节点,用来设置日志的输入格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
以2019-06-04输出的日志为例,来解释下设置、忽略File属性的不同。
设置File属性
1.系统会将日志内容全部写入log/check.log中
2.在2019-06-05凌晨,check.log
会被重命名为log/check.2019-06-04.log
3.然后再生成新的check.log文件
4.后续同理,按照上面的步骤生成log/check.2019-06-05.log、log/check.2019-06-06.log等日志
忽略File属性
1.系统会将日志内容直接写入log/check.2019-06-04.log
中。
2.在2019-06-05凌晨,系统会将日志内容直接写入log/check.2019-06-05.log
。
总结:
仍以2019-06-04为例,如果你设置了File属性,当天你只能看到check.log日志文件,2019-06-05才会看到check.201-06-04.log文件,并且会生成新的check.log记录2019-06-05的日志。
但是如果你忽略了,你当天就能看到check.2019-06-04.log文件,但你始终看不到check.log文件。
2.<maxHistory>(可选节点)
该属性控制要保留的归档文件的最大数量,以异步方式删除较旧的文件。
例如,如果您指定每月滚动,并将maxHistory设置为6,则将保留6个月的归档文件,并删除6个月以上的文件。
请注意,由于删除了旧的归档日志文件,将适当删除为日志文件归档而创建的所有文件夹。
又例如设置滚动策略为每天滚动<maxHistory>是6,则只保存最近6天的纪录。
注意删除旧文件时那些为了归档而创建的目录也会被删除
-
FixedWindowRollingPolicy
根据固定窗口算法重命名文件的滚动策略。有以下子节点:
1.<minIndex>:窗口索引最小值
2.<maxIndex>:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。
3.<fileNamePattern>:必须包含“%i”,例如:假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如:mylog%i.log.gz 或者 没有log%i.log.zip
关于子节点<triggeringPolicy>
- SizeBasedTriggeringPolicy: 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动。只有一个节点:
<maxFileSize>:这是活动文件的大小,默认值是10MB。
关于子节点<encoder>
负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。
目前PatternLayoutEncoder 是唯一有用的且默认的encoder,有一个<pattern>节点,用来设置日志的输入格式。使用“%”加“转换符”方式,如果要输出“%”,则必须用“\”对“%”进行转义。
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder
具体配置示例:假设我们想每天生成一个日志文件,按级别输出,每天的日志文件进行压缩归档,归档的文件最多保留30天:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志级别
trace<debug<info<warn<error
若定义的日志级别为info,则不会打印出 trace和debug的相关日志。
-->
<!-- 定义全局参数常量 -->
<property name="log.level" value="debug"/>
<property name="log.maxHistory" value="30"/><!-- 30表示30个 -->
<!-- 日志的存放位置 --> <!--catalina.base表示tomcat的根路径 -->
<property name="log.filePath" value="${catalina.base}/logs/webapps"/>
<!-- 日志的展现格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd : HH:mm:ss.SSS}[%thread]%-5level%logger{50}-%msg%n"/>
<!-- 定义appender (日志的输出和存放位置等). -->
<!-- 控制台设置 -->
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern> <!-- 控制台日志输出格式 -->
</encoder>
</appender>
<!-- DEBUG -->
<appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 日志文件会滚动 -->
<!-- 文件路径 -->
<file>${log.filePath}/debug.log</file><!-- 当前的日志文件存放路径 -->
<!-- 日志滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 历史日志文件的存放路径和名称 -->
<fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- 日志文件最大的保存历史 数量-->
<maxHistory>${log.maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern> <!-- 日志文件中日志的格式 -->
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch> <!-- 用过滤器,只接受DEBUG级别的日志信息,其余全部过滤掉 -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- INFO -->
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 日志文件会滚动 -->
<!-- 文件路径 -->
<file>${log.filePath}/info.log</file><!-- 当前的日志文件存放路径 -->
<!-- 日志滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 历史日志文件的存放路径和名称 -->
<fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- 日志文件最大的保存历史 数量-->
<maxHistory>${log.maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern> <!-- 日志文件中日志的格式 -->
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch> <!-- 用过滤器,只接受INFO级别的日志信息,其余全部过滤掉 -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- ERROR-->
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 日志文件会滚动 -->
<!-- 文件路径 -->
<file>${log.filePath}/error.log</file><!-- 当前的日志文件存放路径 -->
<!-- 日志滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- TimeBased默认是一天更新一次 -->
<!-- 历史日志文件的存放路径和名称 -->
<fileNamePattern>${log.filePath}/error/error.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- 日志文件最大的保存历史 数量-->
<maxHistory>${log.maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern> <!-- 日志文件中日志的格式 -->
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch> <!-- 用过滤器,只接受ERROR级别的日志信息,其余全部过滤掉 -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- logger标签用于和appender进行绑定,并告诉logback哪些包(name属性)的日志信息需要记录 -->
<!--logger将会继承root标签,在加上additivity="true"的属性后 root标签中的level将会被logger的level覆盖-->
<logger name="com.me" level="${log.level}" additivity="true">
<!-- level表示只记录哪一个级别以上的日志 -->
<!-- 与appender进行绑定 -->
<appender-ref ref="debugAppender"/>
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</logger>
<root level="info">
<appender-ref ref="consoleAppender"/>
</root>
</configuration>
2.按照固定窗口模式生成日志文件,当文件大于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>
Logger(记录器)
<logger>标签用来声明一个记录器,并且可以指定使用哪个appender,日志级别可分为5个级别:DEBUG < INFO < WARN < ERROR < FATAL,Log4j有一个规则:只输出级别不低于设定级别的日志信息,假设Loggers级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。
<loger>仅有一个name属性,一个可选的level和一个可选的additivity属性。
-
name
用来指定受此loger约束的某一个包或者具体的某一个类。 -
level
用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前loger将会继承上级的级别。 -
additivity
是否向上级loger传递打印信息。默认是true。
<loger>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个loger。
<root>
<root>其实也是<loger>元素,但是它是根loger,其他的logger会继承<root>
<root>的level属性用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL,默认是DEBUG。
<root>可以包含零个或多个<appender-ref>元素
特别注意:无论<logger>还是<root>只要配置了<appender-ref ref="xxxx"/>就会按照级别输出日志且互不影响,也就是说只有你在<logger>中配置了<appender-ref ref="xxxx"/>,这个logger本身才会输出日志。
所以如果你在<logger>中配置了<appender-ref ref="xxxx"/>,同时<root>中也配置了<appender-ref ref="xxxx"/>,那么日志将会输出2次,这时候你需要在<logger>中设置additivity为false取消向上传递(默认为true,会向上传递,造成<logger>和<root>分别打印一次)。
例如:Java代码
package com.chainfin.ssmdemo.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* FileName: LogbackTest
* Author: TP
* Date: 2019-06-23 17:33
* Description:
*/
public class LogbackTest {
private static Logger log = LoggerFactory.getLogger(LogbackTest.class);
public static void main(String[] args) {
log.trace("======trace");
log.debug("======debug");
log.info("======info");
log.warn("======warn");
log.error("======error");
}
}
第1种:只配置<root>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
其中appender的配置表示打印到控制台。
<root level="INFO">将root的打印级别设置为“INFO”,指定了名字为“STDOUT”的appender。
当执行com.chainfin.ssmdemo.logback.LogbackTest类的main方法时,root将级别为“INFO”及大于“INFO”的日志信息交给已经配置好的名为“STDOUT”的appender处理,“STDOUT”的appender将信息打印到控制台:
2019-06-23 17:44:19,318 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 17:44:19,320 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 17:44:19,320 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第2种:带有loger的配置,不指定级别,不指定appender
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" />
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
<logger name="com.chainfin"" />将控制logback包下的所有类的日志打印
因为没有设置打印级别,所以会继承他的上级<root>的日志级别“DEBUG”
因为没有设置additivity,默认为true,将此loger的打印信息向上级传递
因为没有设置appender,此loger本身不打印任何信息
<root level="DEBUG">将root的打印级别设置为“DEBUG”,指定了名字为“STDOUT”的appender。
当执行com.chainfin.ssmdemo.logback.LogbackTest类的main方法时,因为LogbackTest在包com.chainfin中,所以首先执行<logger name="com.chainfin" />,将级别为“DEBUG”及大于“DEBUG”的日志信息传递给root,本身并不打印,root接到下级传递的信息,交给已经配置好的名为“STDOUT”的appender处理,“STDOUT”的appender将信息打印到控制台:
2019-06-23 17:48:52,721 [MIR] [main] DEBUG com.chainfin.ssmdemo.logback.LogbackTest - ======debug
2019-06-23 17:48:52,722 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 17:48:52,723 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 17:48:52,723 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第3种:带有loger的配置,指定级别且>root中的日志级别,指定appender
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" level="INFO" >
<appender-ref ref="STDOUT"/>
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
因为<logger>中指定了appender,所以<logger name="com.chainfin" level="INFO" >本身会打印一次INFO及以上级别的日志
因为没有设置additivity,默认为true,loger的打印信息会向上级传递给<root>,所以<root>也会打印1次INFO及以上级别的日志
2019-06-23 18:00:58,968 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:00:58,968 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:00:58,970 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:00:58,970 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:00:58,970 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
2019-06-23 18:00:58,970 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第4种:带有loger的配置,指定级别且<root中的日志级别,指定appender
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" level="INFO" >
<appender-ref ref="STDOUT"/>
</logger>
<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
因为<logger>中指定了appender,所以<logger name="com.chainfin" level="INFO" >本身会打印一次INFO及以上级别的日志
因为没有设置additivity,默认为true,loger的打印信息会向上级传递给<root>,所以<root>也会打印1次INFO及以上级别的日志,注意这里传递给root,root仍然使用<logger>的级别进行输出,可以看到仍然是2次
2019-06-23 18:13:03,828 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:13:03,828 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:13:03,830 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:13:03,830 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:13:03,830 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
2019-06-23 18:13:03,830 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第5种:带有loger的配置,指定级别,指定appender,设置additivity="false"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
可以看到输出日志如下:
2019-06-23 18:17:13,094 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:17:13,096 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:17:13,096 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第6种:带有多个loger的配置,指定级别,指定appender,设置父logger的additivity="false"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com.chainfin.ssmdemo" level="INFO" >
<appender-ref ref="STDOUT"/>
</logger>
<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
因为<logger name="com.chainfin.ssmdemo" level="INFO" >这个logger的父logger是<logger name="com.chainfin" level="INFO" additivity="false">
而子logger自己指定了appender,所以自己打印一次,子logger又会向上传递日志信息给父logger,所以父logger也会打印一次(使用子logger的日志级别)
2019-06-23 18:29:08,300 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:29:08,300 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:29:08,302 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:29:08,302 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:29:08,302 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
2019-06-23 18:29:08,302 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
第7种:带有多个loger的配置,指定级别,指定appender,设置子logger的additivity="false"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="contextName" value="MIR"/>
<contextName>${contextName}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%contextName] [%thread] %-3level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.chainfin" level="ERROR" >
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com.chainfin.ssmdemo" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
输出结果:
2019-06-23 18:35:01,428 [MIR] [main] INFO com.chainfin.ssmdemo.logback.LogbackTest - ======info
2019-06-23 18:35:01,430 [MIR] [main] WARN com.chainfin.ssmdemo.logback.LogbackTest - ======warn
2019-06-23 18:35:01,430 [MIR] [main] ERROR com.chainfin.ssmdemo.logback.LogbackTest - ======error
总结:
- 所有自定义的logger均继承root,如果自定义logger没有指定日志级别,则继承root的日志级别
- logger中指定了自己的appender,那么这个logger才会输出日志,不指定不会输出日志
- 自定义logger如果没有关闭向上传递(未设置additivity="false"),则会将打印信息传递给root,并且root使用该自定义logger的级别进行日志输出(输出级别覆盖)
Layout(布局)
格式化自己的日志输出,Log4j可以在Appenders的后面附加Layouts来完成这个功能。
Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。
常使用的类有:
- org.apache.log4j.HTMLLayout(以HTML表格形式布局)
- org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
- org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
- org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)