这里主要说一下log4j和logback的日志配置,其实他俩的配置差不多,只是写法上略有不同,log4j可以使用properties文件配置也可以使用xml进行配置,这里先分别抛出log4j.xml和logback.xml的配置,混个脸熟,方便下面各个组件内容的说明。
- log4j.xml
- logback.xml
${contextName}
%date [%contextName] [%thread] %-3level %logger{36} - %msg%n
logs/${contextName}.log-%d{yyyy-MM-dd}.log
%date [%contextName] %level [%thread] %logger{36} [%file:%line] %msg%n
false
false
logs/${contextName}-error.log-%d{yyyy-MM-dd}.log
%date [%contextName] %level [%thread] %logger{36} [%file:%line] %msg%n
false
false
ERROR
ACCEPT
DENY
根节点
根节点包含以下几个属性:
- scan
当此属性设置为true时,配置文件如果发生改变,将会被重新加载。
默认值为true。 - scanPeriod:
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。
默认的时间间隔为1分钟。 - debug
当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。
默认值为false。
设置上下文名称:
根节点
myAppName
设置变量:
根节点
- name:变量的名称
- value:变量定义的值
通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
${APP_Name}
获取时间戳字符串:
根节点
- key:此
的名字 - datePattern:设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循java.txt.SimpleDateFormat的格式。
例如将解析配置文件的时间作为上下文名称:
${bySecond}
Appender(输出源)
appender可以指定我们的日志输出的目的地,可以输出到控制台,也可以输出到指定文件。
常用的类有:
- org.apache.log4j.ConsoleAppender(输出到控制台)
- org.apache.log4j.FileAppender(输出到指定文件)
- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
- org.apache.log4j.RollingFileAppender(输出到指定文件,并根据滚动策略滚动)
- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
ConsoleAppender
把日志添加到控制台,有以下子节点:
:对日志进行格式化 :字符串 System.out 或者 System.err ,默认 System.out
%-4relative [%thread] %-5level %logger{35} - %msg %n
FileAppender
把日志添加到指定文件,有以下子节点:
:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 :如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。 :对记录事件进行格式化。 :如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。
testFile.log
true
%-4relative [%thread] %-5level %logger{35} - %msg%n
RollingFileAppender
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:
:被写入的文件路径(实时日志文件路径及名称),可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 :如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。 :对记录事件进行格式化 :滚动策略,当发生滚动时决定RollingFileAppender的行为,涉及文件移动和重命名。 : 告知RollingFileAppender何时激活滚动。 :当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy。
但是有两个限制:1.不支持也不允许文件压缩,2.不能设置file属性,必须留空。
关于子节点
- TimeBasedRollingPolicy
最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责触发滚动。有以下子节点:
1.(必要节点)
该属性定义了过渡(存档)日志文件的路径及名称,应包含文件名及“%d”转换符,注意其中“%d”可以包含一个java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。如果直接使用%d,默认格式是 yyyy-MM-dd,logback通过从fileNamePattern的值推断出过渡期(根据%d)。
RollingFileAppender的子节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置:
如果设置了,当前日志总是记录到 指定的文件(活动文件),活动文件的名字不会改变。
如果没设置,活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。
更通俗的理解就是:
1.RollingFileAppender的file属性可以设置,也可以忽略。
2.如果设置了FileAppender包含的属性file,系统实时生成的日志和根据日期生成的日志可以存储在不同的目录文件下。在这种情况下,系统实时生成的日志内容都会记录在file属性指定的文件中。因此,该日志文件名称不会随着时间的移动而更改。
3.如果忽略了FileAppender包含的属性file,活动文件的名字会根fileNamePattern的值,每隔一段时间改变一次,即每隔一段时间会生成一个日志文件
例如:
log/check.log
log/check.%d{yyyy-MM-dd}.log
30
%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n
UTF-8
以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设置为6,则将保留6个月的归档文件,并删除6个月以上的文件。
请注意,由于删除了旧的归档日志文件,将适当删除为日志文件归档而创建的所有文件夹。
又例如设置滚动策略为每天滚动
注意删除旧文件时那些为了归档而创建的目录也会被删除
- FixedWindowRollingPolicy
根据固定窗口算法重命名文件的滚动策略。有以下子节点:
1.:窗口索引最小值
2.:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。
3.:必须包含“%i”,例如:假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如:mylog%i.log.gz 或者 没有log%i.log.zip
关于子节点
- SizeBasedTriggeringPolicy: 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动。只有一个节点:
:这是活动文件的大小,默认值是10MB。
关于子节点
负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。
目前PatternLayoutEncoder 是唯一有用的且默认的encoder,有一个
%-4relative [%thread] %-5level %logger{35} - %msg%n
具体配置示例:假设我们想每天生成一个日志文件,按级别输出,每天的日志文件进行压缩归档,归档的文件最多保留30天:
${log.pattern}
${log.filePath}/debug.log
${log.filePath}/debug/debug.%d{yyyy-MM-dd}.log.gz
${log.maxHistory}
${log.pattern}
DEBUG
ACCEPT
DENY
${log.filePath}/info.log
${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz
${log.maxHistory}
${log.pattern}
INFO
ACCEPT
DENY
${log.filePath}/error.log
${log.filePath}/error/error.%d{yyyy-MM-dd}.log.gz
${log.maxHistory}
${log.pattern}
ERROR
ACCEPT
DENY
2.按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。
test.log
tests.%i.log.zip
1
3
5MB
%-4relative [%thread] %-5level %logger{35} - %msg%n
Logger(记录器)
- name
用来指定受此loger约束的某一个包或者具体的某一个类。 - level
用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前loger将会继承上级的级别。 - additivity
是否向上级loger传递打印信息。默认是true。
可以包含零个或多个 元素,标识这个appender将会添加到这个loger。
特别注意:无论
所以如果你在
例如: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种:只配置
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
其中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
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
因为没有设置打印级别,所以会继承他的上级
因为没有设置additivity,默认为true,将此loger的打印信息向上级传递
因为没有设置appender,此loger本身不打印任何信息
当执行com.chainfin.ssmdemo.logback.LogbackTest类的main方法时,因为LogbackTest在包com.chainfin中,所以首先执行
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
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
因为
因为没有设置additivity,默认为true,loger的打印信息会向上级传递给
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的配置,指定级别且
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
因为
因为没有设置additivity,默认为true,loger的打印信息会向上级传递给
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"
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
可以看到输出日志如下:
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"
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
因为
而子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"
${contextName}
%date [%contextName] [%thread] %-3level %logger{80} - %msg%n
输出结果:
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(包含日志产生的时间、线程、类别等信息)