Log4j2中RollingFile的檔案滾動更新機制 一、什麼是RollingFile RollingFileAppender是Log4j2中的一種能夠實現日誌檔案滾動更新(rollover)的
一、什麼是RollingFile
RollingFileAppender是Log4j2中的一種能夠實現日誌檔案滾動更新(rollover)的Appender。
rollover的意思是當滿足一定條件(如檔案達到了指定的大小,達到了指定的時間)後,就重新命名原日誌檔案進行歸檔,並生成新的日誌檔案用於log寫入。如果還設定了一定時間內允許歸檔的日誌檔案的最大數量,將對過舊的日誌檔案進行刪除操作。
RollingFile實現日誌檔案滾動更新,依賴於TriggeringPolicy和RolloverStrategy。
其中,TriggeringPolicy為觸發策略,其決定了何時觸發日誌檔案的rollover,即When。
RolloverStrategy為滾動更新策略,其決定了當觸發了日誌檔案的rollover時,如何進行檔案的rollover,即How。
Log4j2提供了預設的rollover策略DefaultRolloverStrategy。
下面通過一個log4j2.xml檔案配置簡單瞭解RollingFile的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<? 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操作。
引數名 | 型別 | 描述 |
---|---|---|
interval | integer |
此引數需要與filePattern結合使用,規定了觸發rollover的頻率,預設值為1。假設interval為4,若filePattern的date/time pattern的最小時間粒度為小時(如yyyy-MM-dd HH),則每4小時觸發一次rollover;若filePattern的date/time pattern的最小時間粒度為分鐘(如yyyy-MM-dd HH-mm),則每4分鐘觸發一次rollover。 |
modulate | boolean |
指明是否對interval進行調節,預設為false。若modulate為true,會以0為開始對interval進行偏移計算。例如,最小時間粒度為小時,當前為3:00,interval為4,則以後觸發rollover的時間依次為4:00,8:00,12:00,16:00,...。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<? 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引數指定了計數器的最大值。一旦計數器達到了最大值,過舊的檔案將被刪除。
注意:不要認為max引數是需要保留的日誌檔案的最大數目。
max引數是與filePattern中的計數器%i配合起作用的,其具體作用方式與filePattern的配置密切相關。
1.如果filePattern中僅含有date/time pattern,每次rollover時,將用當前的日期和時間替換檔案中的日期格式對檔案進行重新命名。max引數將不起作用。
如,filePattern="logs/app-%d{yyyy-MM-dd}.log"
2.如果filePattern中僅含有整數計數器(即%i),每次rollover時,檔案重新命名時的計數器將每次加1(初始值為1),若達到max的值,將刪除舊的檔案。
如,filePattern="logs/app-%i.log"
3.如果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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<? 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。
第X次rollover | 當前用於寫入log的檔案 | 歸檔的檔案 | 描述 |
---|---|---|---|
0 | app.log | - | 所有的log都寫進app.log中。 |
1 | app.log | app-2017-08-17.log |
當app.log的size達到10KB,觸發第1次rollover,app.log被重新命名為app-2017-08-17.log。新的app.log被創建出來,用於寫入log。 |
2 | app.log |
app-2017-08-17.log |
當app.log的size達到10KB,觸發第2次rollover,原來的app-2017-08-17.log將刪除。app.log被重新命名為app-2017-08-17.log。新的app.log檔案被創建出來,用於寫入log。 |
情況2:filePattern中僅含有整數計數器(%i)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<? 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。
第X次rollover | 當前用於寫入log的檔案 | 歸檔的檔案 | 描述 |
---|---|---|---|
0 | app.log | - | 所有的log都寫進app.log中。 |
1 | app.log | app-1.log |
當app.log的size達到10KB,觸發第1次rollover,app.log被重新命名為app-1.log。新的app.log被創建出來,用於寫入log。 |
2 | app.log |
app-1.log app-2.log |
當app.log的size達到10KB,觸發第2次rollover,app.log被重新命名為app-2.log。新的app.log被創建出來,用於寫入log。 |
3 | app.log |
app-1.log app-2.log app-3.log |
當app.log的size達到10KB,觸發第3次rollover,app.log被重新命名為app-3.log。新的app.log被創建出來,用於寫入log。 |
4 | app.log |
app-1.log app-2.log app-3.log |
當app.log的size達到10KB,觸發第4次rollover,app-1.log被刪除(即最初的、最舊的app.log)。app-2.log被重新命名為app-1.log,app-3.log被重新命名為app-2.log,app.log被重新命名為app-3.log。新的app.log被創建出來,用於寫入log。 |
情況3:如果filePattern中既含有date/time pattern,又含有%i計數器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<? 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。
第X次rollover | 當前用於寫入log的檔案 | 歸檔的檔案 | 描述 |
---|---|---|---|
0 | app.log | - | 所有的log都寫進app.log中。 |
1 | app.log | app-2017-08-17 20-52-1.log |
當app.log的size達到10KB,觸發第1次rollover,app.log被重新命名為app-2017-08-17 20-52-1.log。新的app.log被創建出來,用於寫入log。 |
2 | app.log |
app-2017-08-17 20-52-1.log app-2017-08-17 20-52-2.log |
當app.log的size達到10KB,觸發第2次rollover,app.log被重新命名為app-2017-08-17 20-52-2.log。新的app.log被創建出來,用於寫入log。 |
3 | app.log |
app-2017-08-17 20-52-1.log app-2017-08-17 20-52-2.log app-2017-08-17 20-52-3.log |
當app.log的size達到10KB,觸發第3次rollover,app.log被重新命名為app-2017-08-17 20-52-3.log.log。新的app.log被創建出來,用於寫入log。 |
4 | app.log |
app-2017-08-17 20-52-1.log app-2017-08-17 20-52-2.log app-2017-08-17 20-52-3.log |
當app.log的size達到10KB,觸發第4次rollover,因計數器的值到達max值,app-2017-08-17 20-52-1.log被刪除(即最初的、最舊的app.log)。app-2017-08-17 20-52-2.log被重新命名為app-2017-08-17 20-52-1.log,app-2017-08-17 20-52-3.log被重新命名為app-2017-08-17 20-52-2.log,app.log被重新命名為app-2017-08-17 20-52-3.log。新的app.log被創建出來,用於寫入log。 |
5 | app.log |
app-2017-08-17 20-52-1.log app-2017-08-17 20-52-2.log app-2017-08-17 20-52-3.log |
當前時間變為app-2017-08-17 20-53,觸發第5次rollover,app-2017-08-17 20-52-1.log被刪除。app-2017-08-17 20-52-2.log被重新命名為app-2017-08-17 20-52-1.log,app-2017-08-17 20-52-3.log被重新命名為app-2017-08-17 20-52-2.log,app.log被重新命名為app-2017-08-17 20-52-3.log。新的app.log被創建出來,用於寫入log。 |
6 | app.log |
app-2017-08-17 20-52-1.log app-2017-08-17 20-52-2.log app-2017-08-17 20-52-3.log app-2017-08-17 20-53-1.log |
當app.log的size達到10KB,觸發第6次rollover,app.log被重新命名為app-2017-08-17 20-53-1.log。新的app.log被創建出來,用於寫入log。 |
總結:
1.max引數是與filePattern中的計數器%i配合起作用的,若filePattern為filePattern="logs/app-%d{yyyy-MM-dd}.log">,由於沒有設定%i計數器,max引數將不起作用。
2.max引數不是需要保留的檔案的最大個數。如情況3,日誌檔案date/time pattern不再符合filePattern時,計算器將被重置為1,日誌總個數超過了max的指定值。
可認為max引數規定了一定時間範圍內歸檔檔案的最大個數。
四、DeleteAction
DefaultRolloverStrategy制定了預設的rollover策略,通過max引數可控制一定時間範圍內歸檔的日誌檔案的最大個數。
Log4j 2.5 引入了DeleteAction,使使用者可以自己控制刪除哪些檔案,而不僅僅是通過DefaultRolloverStrategy的預設策略。
注意:通過DeleteAction可以刪除任何檔案,而不僅僅像DefaultRolloverStrategy那樣,刪除最舊的檔案,所以使用的時候需要謹慎!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<? 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常用引數如下:
引數名 | 型別 | 描述 |
---|---|---|
basePath | String |
必填。目錄掃描開始路徑。 |
maxDepth | int |
掃描的最大目錄深度。0表示basePath指定的檔案自身。Integer.MAX_VALUE表示掃描所有的目錄層。預設值為1,表示僅掃描basePath下的檔案。 |
testMode | boolean |
如果為true,實際的檔案不會被刪除,刪除檔案的資訊會列印到log4j2的INFO級別的log中。可使用此引數測試配置是否符合預測。預設為false。 |
pathConditions | PathCondition[] |
刪除檔案的過濾條件,滿足指定條件的檔案將會被刪除,可以指定一個或多個。 如果指定多個pathCondition,需要同時滿足。Conditions可以巢狀,當巢狀配置時,只有當滿足了外部的contion時,才能對內部的condition進行判斷。如果Conditions不是巢狀的,會可能以任意順序進行判斷。 Conditions也可以通過使用IfAll,IfAny,IfNot等類似於AND,OR,NOT的condition,實現複雜的condition。
|
五、程式測試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 < |