Log4j Appender之RollingFileAppender

本文翻译自log4j官方文档(有些细节属于个人理解):https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingFileAppender

RollingFileAppender是一种OutputStreamAppender,该appender会将日志写入名称为配置项fileName的文件中,并且还会根据TriggeringPolicy和RolloverPolicy对日志文件进行回滚操作,它依赖RollingFileManager(继承自OutputStreamManager)来实际执行文件读写(I/O)和回滚。尽管通过不同配置初始化的RollingFileAppender不能共享,但是RollingFileManagers却是可以共享的。比如,在同一个servlet容器中的两个web应用,虽然各自有他们自己的配置,但是如果log4j是通过公用的ClassLoader 加载的话,就可以同时写入到同一个日志文件。
RollingFileAppender依赖于一个 TriggeringPolicy 和一个RolloverStrategy,triggering policy决定了是否执行回滚,而RolloverStrategy决定了如何进行回滚。如果没有配置RolloverStrategy,就会使用DefaultRolloverStrategy。从log4j 2.5版本开始,可以在DefaultRolloverStrategy中配置一个custom delete action,以便在回滚时完成自定义的删除操作。从log4j 2.8版本开始,如果没有配置file name,则会默认使用 DirectWriteRolloverStrategy ,而不是DefaultRolloverStrategy。从log4j 2.9版本开始,可以在DefaultRolloverStrategy中配置一个custom POSIX file attribute view action ,如果没有定义,则会使用继承自RollingFileAppender的POSIX file。
RollingFileAppender不支持日志文件锁定。
{\mathbf{RollingFileAppender Parameters}}

Parameter Name Type Description
append boolean 默认true。如果设置为true,新记录会追加到文件末尾。如果为false,则会在新记录写入之前清空文件。
bufferedIO boolean 默认值true。如果为true,记录会先写入buffer,当buffer满了或者在打印日志时设置了immediateFlush参数,才会写入到日志文件。为true时,不能使用文件锁。通过性能测试结果可以看出,使用了bufferIO对于性能有显著的提升,哪怕在写日志时开启了immediateFlush。
bufferSize int bufferedIO为true时,用于指定buffer的大小。默认8192 字节。
createOnDemand boolean 是否在后台创建日志文件。仅当一个事件通过了所有的过滤器并到达该appender时才会创建文件。默认值为false
filter Filter 用于判断该appender是否需要处理某个事件的过滤器,多个过滤器可以使用CompositeFilter来实现。
fileName String 写入日志的文件名称。如果文件或者其任意一个父目录不存在,都会被创建
filePattern String 压缩文件的文件名称规则,规则制定的格式取决于使用的RolloverPolicy 。DefaultRolloverPolicy可以使用兼容SimpleDateFormat格式的date/time参数并且可以使用%i来表示一个数字计数器。同时支持动态插值,所以任意的Lookups (比如DateLookup) 都可以包含在规则中。
immediateFlush boolean 默认值true。当设置为true时,每次的写入都会进行flush,这可以保证数据被写入文件,但是可能会影响性能。

仅当使用同步的logger时,配置成true才有效。异步logger或者appender会在batch events结束时自动flush,哪怕immediateFlush设置为了false。这同样可以保证数据写入了文件,但是性能更高。
layout Layout 用于格式化LogEvent的样式,如果没有设置则默认使用"%m%n"。
name String Appender的名称
policy TriggeringPolicy 用于决定是否进行回滚的策略器。
strategy RolloverStrategy 用于决定压缩包存放位置和压缩包名称的策略器。
ignoreExceptions boolean 默认值true,在写入日志时遇到异常会只打印日志然后忽略掉异常。当设置为false时,异常会被传递到调用方法。当该Appender被包装在FailoverAppender中时,必须设置为false。
filePermissions String POSIX格式的文件属性权限,以便在创建文件时应用。

系统必须要支持 POSIX

举例: rw------- or rw-rw-rw- etc...
fileOwner String 创建文件是,指定文件所属的owne。

出于安全原因,可能会限制更改文件的所有者,不允许操作,并且抛出IOException。只有当_POSIX_CHOWN_RESTRICTED 对path有效时,具有与文件的用户ID相等的有效用户ID或具有适当特权的进程才可以更改文件的所有权。

操作系统必须要支持 owner属性。
fileGroup String 创建文件时,指定文件所属的group。

操作系统必须要支持 POSIX

Triggering Policies

复合Triggering Policy

CompositeTriggeringPolicy用于组合多个triggering policies,如果有一个返回true,则CompositeTriggeringPolicy就返回true。
如下的xml片段,组合了三个triggering policies:1.当JVM启动时;2.当日志文件达到20MB时;3.当前日期与日志文件的起始日期不匹配时(按天分文件);

<Policies>
  <OnStartupTriggeringPolicy />
  <SizeBasedTriggeringPolicy size="20 MB" />
  <TimeBasedTriggeringPolicy />
</Policies>

Cron Triggering Policy

基于cron表达式进行回滚。这个策略通过一个timer来控制,并且是异步去处理log event的,因此可能会出现来自上一个或下一个时间段的日志出现在下一个日志文件的开头或结尾。配置项filePattern中需要包含一个timestamp,否则在每次回滚的时候,目标文件都会被覆盖。
{\mathbf{CronTriggeringPolicyParameters}}

arameter Name Type Description
schedule String cron表达式。该表达式与Quartz库中的表达式语法一致,参见CronExpression ,以获取详细信息。
evaluateOnStartup boolean 默认值false。在启动时,将评估文件的最后修改时间。如果在最后修改时间和当前时间之间的某个时间,满足cron表达式,则会立即触发回滚。

OnStartup Triggering Policy

如果文件的创建时间小于JVM启动的时间,并且日志文件的大小大约等于了最小文件大小,则会在JVM启动时触发回滚。
{\mathbf{OnStartupTriggeringPolicy Parameters}}

Parameter Name Type Description
minSize long 指定文件回滚的最小大小,如果为0,则每次启动时都会回滚。默认值为1,以防止回滚空文件。

注意:Google App Engine
当应用运行于Google App Engine中时, 该策略只能使用Log4J的初始时间来做判断依据。 (Google App Engine限制了访问具体class,所以Log4J不能通过方法java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime() 获取到JVM的启动时间,只能降级为使用Log4J的初始时间。)

SizeBased Triggering Policy

当文件大小达到指定值时,SizeBasedTriggeringPolicy会触发回滚。大小可以指定不同的单位,包括:默认的bytes、包含后缀的 KB, MB or GB,比如:2048表示2048个字节,20MB表示20兆比。当与时间类型的策略组合使用时,filePattern参数必须包含%i,不然文件将会被覆盖,因为SizeBased Triggering Policy不会变更文件名中的时间参数。当不与时间类型的回滚策略组合使用时,SizeBased Triggering Policy会变更文件名中的时间参数。

TimeBased Triggering Policy

当当前时间(date/time)规则不再与当前文件名中的date/time一致时,TimeBasedTriggeringPolicy会触发回滚。该策略接受一个interval属性,用于指定基于time和modulate的回滚频率。
{\mathbf{TimeBasedTriggeringPolicy Parameters}}

Parameter Name Type Description
interval integer 回滚的频率,根据filePattern中的最小时间单位决定。比如,filePattern的最小时间单位是小时(%d{yyyy-MM-dd-HH}.log),则每小时就会滚动一次。默认值为1。
modulate boolean 下一次回滚,是否需要在internal边界上发生。比如,最小时间单位为小时,internal=4,modulate=false,当前时间是3点,那么下一次回滚时间将会是3+4=7,下下一次为3+4*2=11。而如果modulate=true,那么下一次回滚将会是3+(3 - 3%4)=4,下下一次为3+(3 - 3%4)+4=8,以此类推。默认true。
maxRandomDelay integer 指定回滚发生的最大随机延迟时间,比如:设置为60,则延迟时间可能为1到60秒,但是不能超过60秒。默认为0,表示没有延迟。在一台服务器上存在多个服务时,可能会同时发生回滚,如果设置了该项就可以将几个服务的回滚时机随机分散,避免在同一时刻对磁盘进行I/O。

Rollover Strategies

Default Rollover Strategy

默认的回滚策略支持RollingFileAppender的属性filePattern中配置的date/time规则以及一个数字计数器。filePattern中的date/time规则会被设置为当前时间,而计数器会在每次回滚时递增。如果同时包含date/time和计数器,则计数器会在date/time规则的值发生变更时重新开始计数。如果filePattern以".gz", ".zip", ".bz2", ".deflate", ".pack200", or ".xz" 结尾,回滚后的文件就会以对应的格式进行压缩。使用bzip2, Deflate, Pack200 and XZ需要引入Apache Commons Compress库,并且XZ还需要多引入XZ for Java。The pattern may also contain lookup references that can be resolved at runtime such as is shown in the example below.
默认的回滚策略支持三种形式的计数器,为了表述清楚它是怎么工作的,我们假设计数器最小值为1,最大值为3,文件名称为foo.log,filePattern为foo-%i.log。

Number of rollovers Active output target Archived log files Description
0 foo.log - 所有日志都输出到foo.log
1 foo.log foo-1.log 在第一次回滚的过程中,foo.log会重命名为foo-1.log,并且会新创建一个foo.log文件,并将后续的日志输出到该文件。
2 foo.log foo-2.log, foo-1.log 在第二次回滚的过程中,foo.log会重命名为foo-2.log。并且新建foo.log文件,用于后续日志输出。
3 foo.log foo-3.log, foo-2.log, foo-1.log 在第三次回滚的过程中,foo.log会重命名为foo-3.log。并且新建foo.log文件,用于后续日志输出。
4 foo.log foo-3.log, foo-2.log, foo-1.log 在第四次和后续的回滚过程中,foo-1.log会被删除,foo-2.log会重命名为foo-1.log,foo-3.log会重命名为foo-2.log,foo.log会重命名为foo-3.log。并且新建foo.log文件,用于后续日志输出。

为了对照配置项fileIndex设置为"min"时的效果,基于上表的假设,会出现如下现象。

Number of rollovers Active output target Archived log files Description
0 foo.log - 所有日志都输出到foo.log
1 foo.log foo-1.log 在第一次回滚的过程中,foo.log会重命名为foo-1.log。并且新建foo.log文件,用于后续日志输出。
2 foo.log foo-2.log, foo-1.log 在第二次回滚的过程中,foo-1.log会重命名为foo-2.log,foo.log会重命名为foo-1.lo。并且新建foo.log文件,用于后续日志输出。
3 foo.log foo-3.log, foo-2.log, foo-1.log 在第三次回滚的过程中,foo-2.log会重命名为foo-3.log,foo-1.log会重命名为foo-2.log,foo.log会重命名为foo-1.log。并且新建foo.log文件,用于后续日志输出。
4 foo.log foo-3.log, foo-2.log, foo-1.log 在第四次和后续的回滚过程中,foo-3.log会被删除,foo-2.log会重命名为foo-3.log,foo-1.log会重命名为foo-2.log,foo.log会重命名为foo-1.log。并且新建foo.log文件,用于后续日志输出。

最后,在2.8版本中,如果fileIndex 设置为了"nomax",这时就会忽略配置项max和min。所以每一次回滚时都会递增计数器,不再有最大回滚文件数量的限制。
{\mathbf{DefaultRolloverStrategy Parameters}}

Parameter Name Type Description
fileIndex String 默认值max,如果设置为max,计数器值更高的回滚文件比计数器值低的文件更新。如果设置为min,文件的保留和计数器的值会与上方的表格保持一致。
min integer 计数器的最小值,默认为1.
max integer 计数器的最大值。如果计数器达到这个值,老的回滚文件将被删除。默认值为7。
compressionLevel integer 压缩级别,0=不压缩,1=最大速度,9=最大压缩比。仅支持ZIP文件。
tempCompressedFilePattern String 压缩过程中的回滚文件的名称规则。

DirectWrite Rollover Strategy

DirectWriteRolloverStrategy会将日志直接输出到filePattern指定的文件,这个规则在回滚时不会重命名文件。如果在时间回滚策略未生效的过程中,基于大小的策略产生了多次回滚,回滚文件名会自动添加计数器(但文件中的时间不变),并不断增长,直到基于时间的回滚策略生效,又会重新开始新一轮的计数器增长。
注意:如果filePattern中指定需要压缩的规则(比如zip后缀名),当前写入文件不会被压缩,除非程序关闭。另外,如果按照时间规则进行了回滚,新的写入文件同样不会被压缩。
{\mathbf{DirectWriteRolloverStrategy Parameters}}

Parameter Name Type Description
maxFiles String 在匹配filePattern规则的时间范围内,允许的最大回滚文件数量。如果超过了该值,最老的文件将会被删除。该值必须要大于1,如果值小于0或者忽略不设置该项,就不会限制文件的数量。
compressionLevel integer 压缩级别,0=不压缩,1=最大速度,9=最大压缩比。仅支持ZIP文件。
tempCompressedFilePattern String 压缩过程中的回滚文件的名称规则。

下方是一个即使用时间触发策略又使用大小触发策略的事例,它每天将创建最多7个回滚文件,回滚文件将会被保存在名称为年和月的目录中,每个回滚文件将会使用gzip格式进行压缩:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
      <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>

第二个事例,指定最大的回滚文件数量,当大于20个回滚文件时,就会被移除:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="250 MB"/>
      </Policies>
      <DefaultRolloverStrategy max="20"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

下面的事例,同样是一个即使用时间触发策略又使用大小触发策略的事例。同样,每天最多只会保留7个回滚文件,回滚文件放在以当前年和月为名称的目录中,也将会使用gzip进行压缩。特殊的是,本次我们就要求文件6小时回滚一次,并且回滚需要发生在能被6整除的小时。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
        <SizeBasedTriggeringPolicy size="250 MB"/>
      </Policies>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

下方的事例使用cron和大小触发策略,回滚文件没有数量限制。cron策略会在每个小时0分触发回滚,同时大小回滚策略会在文件等于250MB时触发回滚:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <RollingFile name="RollingFile" filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <CronTriggeringPolicy schedule="0 0 * * * ?"/>
        <SizeBasedTriggeringPolicy size="250 MB"/>
      </Policies>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

下方的事例与上一个类似,只是限制了每小时回滚文件的数量为10个:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <RollingFile name="RollingFile" filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <CronTriggeringPolicy schedule="0 0 * * * ?"/>
        <SizeBasedTriggeringPolicy size="250 MB"/>
      </Policies>
      <DirectWriteRolloverStrategy maxFiles="10"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

回滚文件的保留策略: Delete on Rollover

Log4j-2.5为了弥补DefaultRolloverStrategy只能根据max来删除文件的策略,而引入了Delete action,用户就可以有更多的在回滚时删除文件的手段。Delete action让用户可以配置一个或者多个条件来选择需要删除的文件。
需要注意的是,Delete action可能会删除符合条件的任何文件,不仅仅是回滚文件,所以使用这个特性时需要当心。你可以使用testMode参数来测试你的配置,以防意外的删错了文件。
{\mathbf{Delete Parameters}}

Parameter Name Type Description
basePath String 必须。指定从哪个路径开始扫描待删除文件。
maxDepth int 指定深入目录的最大层数。0表示仅扫描basePath指定的这一个文件或目录。Integer.MAX_VALUE表示扫描所有目录层级。默认值为1,表示仅扫描basePath指定的目录中的文件。
followLinks boolean 是否处理链接文件。默认false
testMode boolean 如果设置为true,将不会真实的删除文件,而是在status logger 中打印INFO级别的日志,一般用来使用该配置项来验证配置项是否正确。默认值false。
pathSorter PathSorter 插件式的实现PathSorter接口,用来在选择文件之前将文件进行排序。默认是将最近修改的文件排序在前。
pathConditions PathCondition[] 如果没有设置ScriptCondition则该项需要设置该项。可以设置一个或多个。

如果不只设置了一个,每一个都需要接收一个path。 可以嵌套使用,内部的条件需要在外部条件满足时,才会被执行。如果没有嵌套,每一个条件的执行顺序是不确定的。还可以使用逻辑运算符AND, OR和NOT,需要调用对应的方法IfAll,IfAny 和IfNot。

用户可以创建自定的条件或者使用内置的条件:
IfFileName - 通过正则表达式 或者glob来指定删除的文件(相对于base path来说)。
IfLastModified - 指定文件修改时间在指定时间之前,指定事件需要使用 duration
IfAccumulatedFileCount - 在文件树遍历过程中超过某个计数阈值后接受路径。
IfAccumulatedFileSize - 在文件树遍历期间超过累积文件大小阈值后接受路径。
IfAll - 如果所有嵌套条件都满足(逻辑与)则接受路劲。嵌套的条件执行顺序随机。
IfAny - 如果嵌套条件有一个满足(逻辑或)则接受路径。嵌套的条件执行顺序随机。
IfNot - 如果嵌套条件不满足(逻辑非)则接受路径。
scriptCondition ScriptCondition 如果没有设置PathConditions则该项需要设置该项。该项可以指定一个script脚本。
该项需要包含一个Script, ScriptRef或者ScriptFile,用来指定执行的逻辑。(See also the ScriptFilter documentation for more examples of configuring ScriptFiles and ScriptRefs.)
脚本将被传递许多parameters,包括在基本路径下扫描的路径列表(最大到maxDepth),并且必须返回一个包含要删除路径的列表。

{\mathbf{IfFileName Condition Parameters}}

Parameter Name Type Description
glob String 如果未指定regex,则需要指定该项。使用类似正则表达式但语法更简单的有限模式语言匹配相对路径(相对于base path).
regex String 如果未指定glob,则需要指定该项。使用一个正则表达式Pattern来匹配相对路劲(相对于base path)
nestedConditions PathCondition[] 可选的嵌套 PathConditions。如果存在嵌套的条件,每一个条件都需要接受一个文件。嵌套条件只有在外层条件满足(文件名满足)时才会被执行。

{\mathbf{IfLastModified Condition Parameters}}

Parameter Name Type Description
age String 必填。指定一个duration。该条件判断文件的最后修改时间是否早于指定的duration。
nestedConditions PathCondition[] 一个可选的嵌套PathConditions。如果存在嵌套条件,则每个条件都必须接受该文件(判定为true),文件才能删除。嵌套条件只有在外层条件满足(文件最后修改时间早于指定的duration)时才会被执行。

{\mathbf{IfAccumulatedFileCount Condition Parameters}}

Parameter Name Type Description
exceeds int 必须。 一个文件数量阀值,如果扫描数量到达该阀值,则后续文件将会被删除。
nestedConditions PathCondition[] 一个可选的嵌套PathConditions。如果存在嵌套的条件,则每一个条件都必须接受该文件(判定为true),才能删除文件。 嵌套条件只有在外层条件满足(文件数量超过了exceeds阀值)时才会被执行。

{\mathbf{IfAccumulatedFileSize Condition Parameters}}

Parameter Name Type Description
exceeds String 必须。 文件大小的阀值,当扫描的文件总大小超过该阀值时,则后续的文件将会被删除。大小可以以字节为单位指定,后缀为KB, MB or GB, 比如20MB。
nestedConditions PathCondition[] 一个可选的嵌套PathConditions。如果存在嵌套条件,则每一个条件都必须接受该文件(判定为true),文件才能被删除。嵌套条件只有在外层条件满足(文件大小超过了exceeds阀值)时才会被执行。

下方的事例,使用一个cron触发策略,每天午夜触发回滚。回滚文件存放在当前年和月的目录中。所有在base path目录下的满足表达式"/app-.log.gz"的文件,且最后修改时间大于等于60天的文件将会在回滚时被删除。

<?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}/$${date:yyyy-MM}/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>

下方的事例,使用时间和大小的触发策略。该策略会在以当前年和月的目录中保存一天最多100个回滚文件,每个回滚文件将使用gzip进行压缩,每个小时会回滚一次。在每次回滚时,删除文件的判断条件为:文件名满足表达式"/app-.log.gz",并且最后修改时间大于等于30天,但是不会删除最近100GB文件(总大小大于100GB)或者最近的10个(文件数大于10)文件。

<?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}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="250 MB"/>
      </Policies>
      <DefaultRolloverStrategy max="100">
        <!--
        Nested conditions: the inner condition is only evaluated on files
        for which the outer conditions are true.
        -->
        <Delete basePath="${baseDir}" maxDepth="2">
          <IfFileName glob="*/app-*.log.gz">
            <IfLastModified age="30d">
              <IfAny>
                <IfAccumulatedFileSize exceeds="100 GB" />
                <IfAccumulatedFileCount exceeds="10" />
              </IfAny>
            </IfLastModified>
          </IfFileName>
        </Delete>
      </DefaultRolloverStrategy>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

{\mathbf{ScriptCondition Parameters}}

Parameter Name Type Description
script Script, ScriptFile或者ScriptRef 指定执行逻辑的script脚本。该脚本接收一个base path下面的路径列表,并且必须返回一个需要删除的路径列表java.util.List<PathWithAttributes>。请查阅ScriptFilter 文档来了解ScriptFiles和ScriptRefs可以怎么配置。

{\mathbf{Script Parameters}}

Parameter Name Type Description
basePath java.nio.file.Path 指定Delete action执行文件扫描的路径。
pathList java.util.List<PathWithAttributes> 在base path下找到的路径列表,最大层级为max depth配置的值,以修改时间逆序排列。脚本可以任意修改并返回该list。
statusLogger StatusLogger 在脚本执行期间可以被用来打印内部事件。
configuration Configuration 拥有该脚本的配置(名称)。
substitutor StrSubstitutor 用于覆盖lookup变量的StrSubstitutor。
? String 配置中指定的任意属性

下方事例,使用cron触发策略,每天的午夜将会触发回滚。回滚文件存放在以当前年和月为名称的目录中。该脚本返回base path目录下的日期为13日(星期五)的回滚文件列表。Delete action将会删除该脚本返回的所有文件。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
  <Properties>
    <Property name="baseDir">logs</Property>
  </Properties>
  <Appenders>
    <RollingFile name="RollingFile" fileName="${baseDir}/app.log"
          filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyyMMdd}.log.gz">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <CronTriggeringPolicy schedule="0 0 0 * * ?"/>
      <DefaultRolloverStrategy>
        <Delete basePath="${baseDir}" maxDepth="2">
          <ScriptCondition>
            <Script name="superstitious" language="groovy"><![CDATA[
                import java.nio.file.*;
 
                def result = [];
                def pattern = ~/\d*\/app-(\d*)\.log\.gz/;
 
                pathList.each { pathWithAttributes ->
                  def relative = basePath.relativize pathWithAttributes.path
                  statusLogger.trace 'SCRIPT: relative path=' + relative + " (base=$basePath)";
 
                  // remove files dated Friday the 13th
 
                  def matcher = pattern.matcher(relative.toString());
                  if (matcher.find()) {
                    def dateString = matcher.group(1);
                    def calendar = Date.parse("yyyyMMdd", dateString).toCalendar();
                    def friday13th = calendar.get(Calendar.DAY_OF_MONTH) == 13 \
                                  && calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY;
                    if (friday13th) {
                      result.add pathWithAttributes;
                      statusLogger.trace 'SCRIPT: deleting path ' + pathWithAttributes;
                    }
                  }
                }
                statusLogger.trace 'SCRIPT: returning ' + result;
                result;
              ]] >
            </Script>
          </ScriptCondition>
        </Delete>
      </DefaultRolloverStrategy>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

回滚文件的属性视图测录:回滚时自定义文件属性

Log4j-2.9引入了PosixViewAttribute action,该action给予用户更多控制回滚文件的对于owner和group的权限。该action孕育用户配置一个或者多个条件来选择符合条件的base path中的文件。
{\mathbf{PosixViewAttribute Parameters}}

Parameter Name Type Description
basePath String 必须。 扫描开始的base path。
maxDepth int 扫描的最大层级。0表示仅扫描base path自己。Integer.MAX_VALUE表示需要扫描所有层级。默认值为1,表示仅扫描base path目录中的一级文件。
followLinks boolean 是否扫描连接文件。默认false。
pathConditions PathCondition[] 参考DeletePathCondition
filePermissions String 执行时使用的POSIX格式的文件属性权限。
底层文件系统需要支持POSIX文件属性视图。
事例:rw------- or rw-rw-rw- etc...
fileOwner String 执行时定义文件的owner。
修改文件owner可能会被安全策略所限制,以至于抛出操作不被允许的IOException。仅在文件的user ID与有效的用户ID相同,或者拥有合适的权限时,才能修改文件的所有关系。if _POSIX_CHOWN_RESTRICTED is in effect for path.
底层文件系统需要支持POSIX文件属性视图。
fileGroup String 执行时定义文件的group。
底层文件系统需要支持POSIX文件属性视图。

下面是一个使用RollingFileAppender的示例配置,它为当前和已滚日志文件定义了不同的POSIX文件属性视图。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
  <Properties>
    <Property name="baseDir">logs</Property>
  </Properties>
  <Appenders>
    <RollingFile name="RollingFile" fileName="${baseDir}/app.log"
                 filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyyMMdd}.log.gz"
                 filePermissions="rw-------">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <CronTriggeringPolicy schedule="0 0 0 * * ?"/>
      <DefaultRolloverStrategy stopCustomActionsOnError="true">
        <PosixViewAttribute basePath="${baseDir}/$${date:yyyy-MM}" filePermissions="r--r--r--">
            <IfFileName glob="*.gz" />
        </PosixViewAttribute>
      </DefaultRolloverStrategy>
    </RollingFile>
  </Appenders>
 
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
 
</Configuration>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 5,046评论 1 13
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,985评论 0 6
  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981阅读 15,911评论 2 11
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,520评论 0 4
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,849评论 0 5