一、什么是RollingFile
RollingFileAppender
是Log4j2中的一种能够实现日志文件滚动更新(rollover
)的Appender
。rollover
的意思是当满足一定条件(如文件达到了指定的大小,达到了指定的时间)后,就重命名原日志文件进行归档,并生成新的日志文件用于log写入。如果还设置了一定时间内允许归档的日志文件的最大数量,将对过旧的日志文件进行删除操作。RollingFile
实现日志文件滚动更新,依赖于TriggeringPolicy
和RolloverStrategy
。
其中,TriggeringPolicy
为触发策略,其决定了何时触发日志文件的rollover
,即When。RolloverStrategy
为滚动更新策略,其决定了当触发了日志文件的rollover
时,如何进行文件的rollover
,即How。
Log4j2提供了默认的rollover
策略DefaultRolloverStrategy
。
下面通过一个log4j2.xml文件配置简单了解RollingFile
的配置。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH}.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="250MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
上述配置文件中配置了一个RollingFile
,日志写入logs/app.log文件中,每经过1小时或者当文件大小到达250M时,按照app-2017-08-01 12.log的格式对app.log进行重命名并归档,并生成新的文件用于写入log。
其中,fileName
指定日志文件的位置和文件名称(如果文件或文件所在的目录不存在,会创建文件。)filePattern
指定触发rollover
时,文件的重命名规则。filePattern
中可以指定类似于SimpleDateFormat
中的date/time pattern
,如yyyy-MM-dd HH,或者%i指定一个整数计数器。
TimeBasedTriggeringPolicy
指定了基于时间的触发策略。SizeBasedTriggeringPolicy
指定了基于文件大小的触发策略。二、
TriggeringPolicy
RollingFile的触发rollover的策略有
CronTriggeringPolicy
(Cron表达式触发)OnStartupTriggeringPolicy
(JVM启动时触发)SizeBasedTriggeringPolicy
(基于文件大小)TimeBasedTriggeringPolicy
(基于时间)CompositeTriggeringPolicy
(多个触发策略的混合,如同时基于文件大小和时间)
其中,SizeBasedTriggeringPolicy
(基于日志文件大小)、TimeBasedTriggeringPolicy
(基于时间)或同时基于文件大小和时间的混合触发策略最常用。
SizeBasedTriggeringPolicy
SizeBasedTriggeringPolicy
规定了当日志文件达到了指定的size
时,触发rollover
操作。size
参数可以用KB、MB、GB等做后缀来指定具体的字节数,如20MB。
<SizeBasedTriggeringPolicy size="250MB"/>
TimeBasedTriggeringPolicy
TimeBasedTriggeringPolicy
规定了当日志文件名中的date/time pattern
不再符合filePattern
中的date/time pattern
时,触发rollover
操作。
比如,filePattern
指定文件重命名规则为app-%d{yyyy-MM-dd HH}.log
,文件名为app-2017-08-25 11.log
,当时间达到2017年8月25日中午12点(2017-08-25 12),将触发rollover
操作。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH}-%i.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
上述配置文件中,filePattern
中yyyy-MM-dd HH最小时间粒度为小时,TimeBasedTriggeringPolicy
中interval
使用默认值1,将每1小时触发一次rollover
。
若将filePattern
改为filePattern=“logs/app-%d{yyyy-MM-dd HH-mm}-%i.log”,yyyy-MM-dd HH-mm
最小时间粒度为分钟,将每1分钟触发一次rollover
。
CompositeTriggeringPolicy
将多个TriggeringPolicy
放到Policies
中表示使用复合策略
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
如上,同时使用了TimeBasedTriggeringPolicy
、SizeBasedTriggeringPolicy
,有一个条件满足,就会触发rollover
。
三、DefaultRolloverStrategy
DefaultRolloverStrategy
指定了当触发rollover
时的默认策略。DefaultRolloverStrategy
是Log4j2提供的默认的rollover
策略,即使在log4j2.xml中没有显式指明,也相当于为RollingFile
配置下添加了如下语句。DefaultRolloverStrategy
默认的max为7。
<DefaultRolloverStrategy max="7"/>
max
参数指定了计数器的最大值。一旦计数器达到了最大值,过旧的文件将被删除。
:::tips
注意:不要认为max参数是需要保留的日志文件的最大数目。
:::
max
参数是与filePattern
中的计数器%i
配合起作用的,其具体作用方式与filePattern
的配置密切相关。
- 如果
filePattern
中仅含有date/time pattern
,每次rollover
时,将用当前的日期和时间替换文件中的日期格式对文件进行重命名。max参数将不起作用。
如,filePattern="logs/app-%d{yyyy-MM-dd}.log"
- 如果
filePattern
中仅含有整数计数器(即%i),每次rollover
时,文件重命名时的计数器将每次加1(初始值为1),若达到max
的值,将删除旧的文件。
如,filePattern="logs/app-%i.log"
- 如果
filePattern
中既含有date/time pattern
,又含有%i
,每次rollover
时,计数器将每次加1,若达到max的值,将删除旧的文件,直到data/time pattern
不再符合,被替换为当前的日期和时间,计数器再从1开始。
如,filePattern="logs/app-%d{yyyy-MM-dd HH-mm}-%i.log"
假设fileName
为logs/app.log
,SizeBasedTriggeringPolicy
的size为10KB,DefaultRolloverStrategy
的max为3。
根据filePattern
配置的不同分为以下几种情况:
情况1:filePattern
中仅含有date/time pattern
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10KB"/>
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
filePattern="logs/app-%d{yyyy-MM-dd}.log"
,指定当发生rollover
时,将按照app-%d{yyyy-MM-dd}.log
的格式对文件进行重命名。
每次触发rollover
时,将按照如下方式对文件进行rollover
。
情况2:filePattern
中仅含有整数计数器(%i
)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%i.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10KB"/>
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
filePattern="logs/app-%i.log"
,其余配置同上。
每次触发rollover
时,将按照如下方式对文件进行rollover
。
情况3:如果filePattern
中既含有date/time pattern
,又含有%i
计数器
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH-mm}-%i.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10KB"/>
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
filePattern="logs/app-%d{yyyy-MM-dd HH-mm}-%i.log"
,同时指定了TimeBasedTriggeringPolicy
和SizeBasedTriggeringPolicy
的触发策略,每1分钟或者文件大小达到10KB,将触发rollover
。
每次触发rollover
时,将按照如下方式对文件进行rollover
。
总结:
max
参数是与filePattern
中的计数器%i
配合起作用的,若filePattern为filePattern="logs/app-%d{yyyy-MM-dd}.log">
,由于没有设置%i
计数器,max
参数将不起作用。max
参数不是需要保留的文件的最大个数。如情况3,日志文件date/time pattern
不再符合filePattern
时,计算器将被重置为1,日志总个数超过了max的指定值。
四、DeleteAction
DefaultRolloverStrategy
制定了默认的rollover
策略,通过max
参数可控制一定时间范围内归档的日志文件的最大个数。
Log4j 2.5 引入了DeleteAction
,使用户可以自己控制删除哪些文件,而不仅仅是通过DefaultRolloverStrategy
的默认策略。
注意:通过DeleteAction
可以删除任何文件,而不仅仅像DefaultRolloverStrategy
那样,删除最旧的文件,所以使用的时候需要谨慎!
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz" />
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
上述配置文件中,Delete
部分便是配置DeleteAction
的删除策略,指定了当触发rollover
时,删除baseDir
文件夹或其子文件下面的文件名符合app-*.log.gz且距离最后的修改日期超过60天的文件。
其中,basePath
指定了扫描开始路径,为baseDir
文件夹。maxDepth
指定了目录扫描深度,为2表示扫描baseDir
文件夹及其子文件夹。IfFileName
指定了文件名需满足的条件,IfLastModified
指定了文件修改时间需要满足的条件。DeleteAction
常用参数如下:
五、程序测试demo
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
try{
//通过打印i,日志文件中数字越小代表越老
for(int i = 0; i < 50000; i++) {
logger.info("{}", i);
logger.info("logger.info\n");
Thread.sleep(100);//为了防止50000条很快跑完,sleep一段时间
}
} catch (InterruptedException e) {}
}
}
1.测试基于时间触发
filePattern
最小时间粒度为秒,将每5秒触发一次rollover
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<!--<RollingFile name="RollingFile" fileName="logs/app.log"-->
<!--filePattern="logs/app-%d{yyyy-MM-dd HH}-%i.log">-->
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH-mm-ss}.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<!--当经过了interval时间后,将根据filePattern对文件进行重命名,并生成新的文件用于日志写入-->
<TimeBasedTriggeringPolicy interval="5"/>
<!--当日志文件大小大于size时,将根据filepattern对文件进行重命名,并生成新的文件用于日志写入-->
<!--<SizeBasedTriggeringPolicy size="30KB"/>-->
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
2.测试基于文件大小的触发
日志文件达到5KB,将触发rollover
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<!--<RollingFile name="RollingFile" fileName="logs/app.log"-->
<!--filePattern="logs/app-%d{yyyy-MM-dd HH}-%i.log">-->
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH-mm-ss}.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<!--当经过了interval时间后,将根据filePattern对文件进行重命名,并生成新的文件用于日志写入-->
<!--<TimeBasedTriggeringPolicy interval="5"/>-->
<!--当日志文件大小大于size时,将根据filepattern对文件进行重命名,并生成新的文件用于日志写入-->
<SizeBasedTriggeringPolicy size="5KB"/>
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
3.测试DefaultRolloverStrategy
的max
参数和%i
计数器的搭配使用
注意filePattern
最小时间粒度为分钟,且含%i
计数器
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd HH-mm}-%i.log">
<!--<RollingFile name="RollingFile" fileName="logs/app.log"-->
<!--filePattern="logs/app-%d{yyyy-MM-dd HH-mm-ss}.log">-->
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<!--当经过了interval时间后,将根据filePattern对文件进行重命名,并生成新的文件用于日志写入-->
<!--<TimeBasedTriggeringPolicy interval="5"/>-->
<!--当日志文件大小大于size时,将根据filepattern对文件进行重命名,并生成新的文件用于日志写入-->
<SizeBasedTriggeringPolicy size="5KB"/>
</Policies>
<DefaultRolloverStrategy max="3"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>