一、Appenders

Log4j Core 提供了两种滚动文件追加器:

  • RollingFile Appender,该追加器使用 FileOutputStream 访问日志文件。
  • RollingRandomAccessFile Appender,该追加器使用 RandomAccessFile 访问日志文件。

注意:即使来自不同的日志记录器上下文,两个追加器也可以共享一个共同的 RollingFileManager,前提是:

  • 它们具有相同的非空 fileName 属性值。
  • 它们没有 fileName 属性,但具有相同的 filePattern 属性值。

共享 RollingFileManager 可以保证滚动操作只发生一次,但要求大多数其余配置参数也必须相同。

1、通用配置

1.1 必须属性

filePattern

Path 类型

定义了滚动后归档日志文件的命名模式。

如果 fileName 属性为 null,则 filePattern 也将用于当前文件

name

String 类型,Appender 的名称

1.2 可选属性

bufferSize

int 类型,默认值为 8192

Appender 内部的 ByteBuffer 的大小。

bufferedIo

boolean 类型,默认值为 true

如果设置为 true,Log4j Core 将在内部缓冲区中格式化每个日志事件,然后将其发送到底层资源。

RandomAccessRollingFile 附加器始终启用内部缓冲区。

createOnDemand

boolean 类型,默认值为 false

appender 按需创建文件。只有当日志事件通过所有过滤器并被路由到此附加器时,附加器才会创建文件。

fileName

Path 类型,默认值为 null

当前日志文件的路径可以为空。如果包含该文件的文件夹不存在,则将创建该文件夹。

此属性不应包含任何运行时查找器或模式转换器。

filePermissions

PosixFilePermissions 类型,默认值为 null

如果不为 null,则指定应用于每个创建的文件的 POSIX 文件权限。权限必须以 PosixFilePermissions.fromString() 使用的格式提供,例如 rw-rw----

底层文件系统应支持 POSIX 文件属性视图。

fileOwner

String 类型,默认值为 null

如果不为 null,则指定要应用于每个创建文件的文件所有者。

底层文件系统应支持文件所有者属性视图。

fileGroup

String 类型,默认值为 null

如果不为 null,则指定要应用于每个创建文件的文件组所有者。

底层文件系统应支持 POSIX 文件属性视图。

ignoreExceptions

如果为 false,则日志异常将被转发给日志语句的调用者。否则,它们将被忽略。

日志异常也始终记录到 Status Logger 中

immediateFlush

boolean 类型,默认值为 true

如果设置为 true,则 appender 将在每次事件后刷新其内部缓冲区。

1.3 嵌套子元素

Filter

0 个或 1 个

允许在格式化和发送日志事件之前对其进行过滤。

Layout

0 个或 1 个

格式化日志事件。

TriggeringPolicy

1 个

确定何时存档当前日志文件。

RolloverStrategy

0 个或 1 个

确定滚动期间执行的操作。

2、Conversion patterns

filePattern 属性接受以下模式说明符:

  • runtime lookups,这些查找在全局上下文中进行评估。
  • %d{...} 模式,功能上与同名的 PatternLayout 模式相同,但它使用前一次滚动的实际或推断的时间戳。
  • %i 模式,扩展为存档文件的计算索引。

所有模式还接受格式说明符,例如 %03i 会将索引打印为三位数的零填充数字。

$${date:...} runtime lookups 和 %d{...} 转换模式的区别:

  • $${date:...}:格式化当前日期。
  • %d{...}:格式化前一次滚动的日期。

filePattern 属性设置为:

1
$${date:yyyy-MM}/%d{yyyy-MM-dd}.log

将会把 2024-06-30.log 日志文件写入 2024-07 目录。建议使用:

1
%d{yyyy-MM}/%d{yyyy-MM-dd}.log

因此,使用 %d{yyyy-MM}/%d{yyyy-MM-dd}.log 可以确保日志文件的目录和文件名都基于前一次滚动的时间戳,而不是当前时间。

3、RollingFile 配置

RollingFile Appender 除了通用的配置选项外,还提供以下配置选项:

3.1 append

boolean 类型,默认值为 true

如果为 true,日志文件将以 APPEND 模式打开。

在大多数系统中,即使文件被多个应用程序打开,这也保证了对文件末尾的原子写入。

3.2 locking

boolean 类型,默认值为 false

如果为 true,Log4j 将在每个日志事件时锁定日志文件。

请注意,此设置的效果取决于操作系统:一些系统(如大多数POSIX操作系统)不提供强制锁定,而只提供咨询文件锁定。

此设置也会降低附加器的性能。

4、RollingRandomAccessFile 配置

RollingRandomAccessFile 除了通用的配置选项外,还提供以下配置选项:

4.1 append

boolean 类型,默认值为 true

如果为 true,appender 将在文件末尾开始写入。

此设置不会提供与 RollingFile 附加器相同的原子性保证。日志文件不能由多个应用程序同时打开。

二、触发策略(Triggering Policies)

触发策略是实现了 TriggeringPolicy 接口的 Log4j 插件,用于决定何时滚动当前日志文件。

1、常见问题

触发策略通常基于两个参数来决定是否滚动文件:

当前文件的大小:尽管所有 JVM 都可以可靠地检查文件大小,但 Log4j 仅在启动时和每次滚动时检查文件大小,并根据已交付的日志大小推断所有文件大小变化。如果多个管理器写入同一文件,文件大小计算可能会不准确。

当前文件的创建时间戳:并非所有文件系统都支持创建时间戳。特别是,POSIX 没有规定这样的时间戳,因此 Log4j 使用的时间戳可能依赖于文件系统的类型和 JVM。如果创建时间戳不可用,将使用最后修改时间戳,这可能相差整个滚动周期。第一次滚动后,Log4j 使用滚动时间戳作为创建时间戳。

2、OnStartupTriggeringPolicy

OnStartupTriggeringPolicy 策略在整个 JVM 生命周期内只触发一次滚动。如果日志文件是在当前 JVM 启动时间之前创建的,并且文件大小达到或超过最小文件大小,将发生滚动。

属性 类型 默认值 描述
minSize long 1 文件必须达到的最小大小才能滚动

OnStartupTriggeringPolicy 使用 JMX 获取 JVM 的启动时间。

在没有 JMX 或 JMX 被禁用的平台上(如 Android 或 Google App Engine),OnStartupTriggeringPolicy 将使用其类加载时的时间戳。

1
<OnStartupTriggeringPolicy minSize="" />

参考 Plugin reference for OnStartupTriggeringPolicy :: Apache Log4j

3、CronTriggeringPolicy

CronTriggeringPolicy 基于 CRON 表达式触发滚动。

追加器的 filePattern 属性应包含一个 %d{...} 时间戳,否则每次滚动时目标文件将被覆盖。

此策略由定时器控制,异步处理日志事件,因此可能会出现上一个或下一个时间段的日志事件出现在日志文件的开头或结尾。

属性 类型 默认值 描述
evaluateOnStartup boolean false 启动时将 CRON 表达式与当前文件的创建时间戳进行评估。如果在该时间和当前时间之间应该发生滚动,文件将立即滚动。
schedule CronExpression 0 0 0 * * ? CRON 表达式,使用与 Quartz 调度器相同的语法。支持的字段顺序如下:秒,分钟,小时,月份中的日期,月份,星期几
1
<CronTriggeringPolicy evaluateOnStartup="" schedule=""/>

参考 Plugin reference for CronTriggeringPolicy :: Apache Log4j

4、SizeBasedTriggeringPolicy

SizeBasedTriggeringPolicy 在文件达到指定大小时触发滚动。

大小可以以字节为单位指定,并带有 KB、MB、GB 或 TB 等后缀,例如 20MB。大小也可以包含带分数的值,如 1.5 MB。大小评估使用 Java 根区域设置,因此分数单位必须始终使用小数点。

与基于时间的触发策略结合使用时,追加器的 filePattern 属性应包含一个 %i 转换模式。否则,每次滚动时目标文件将被覆盖。

属性 类型 默认值 描述
size FileSize 10 MB 当前日志文件的最大大小。达到此大小后将发生滚动。

size 属性的语法为:

1
<number>[ " " ][<unit>]
  • 一个由 NumberFormat 识别的数字
  • 后跟可选的空白字符
  • 后跟可选的单位:k、kB、M、MB、G、GB、T、TB。

参考 Plugin reference for SizeBasedTriggeringPolicy :: Apache Log4j

5、TimeBasedTriggeringPolicy

TimeBasedTriggeringPolicyfilePattern 中最具体的 %d{...} 模式的时间单位发生变化时触发滚动。因此,滚动可能在每月末、每周末、午夜、每小时末等时间发生。

追加器的 filePattern 属性应包含一个 %d{...} 时间戳,否则每次滚动时目标文件将被覆盖。可以使用多个 %d 模式。滚动频率的时间单位由最后一个 %d 模式确定。

属性 类型 默认值 描述
interval int 1 基于 filePattern 中最具体的 %d{...} 模式的时间单位,滚动发生的频率。

比如,filePattern 属性值为 %d{yyyy-MM-dd_HH-mm}.%03i.log,最具体的时间单位为分,如果 interval 属性为 2,则两分钟文件发生一次滚动
modulate boolean false 如果为 true,滚动将对齐到间隔时间单位的边界。

例如,如果滚动频率为每小时一次,间隔为 4,并且应用程序在 3:14 启动:

- false:将在每天的 3:00、7:00、11:00、15:00、19:00 和 23:00 发生滚动。
- true:将在每天的 0:00、4:00、8:00、12:00、16:00 和 20:00 发生滚动。

仅在 interval 大于 1 时适用。
maxRandomDelay int 0 指定滚动的最大随机延迟秒数。

此设置在服务器上非常有用,在这些服务器上,多个应用程序被配置为同时滚动日志文件,并且可以跨时间分散这样做的负载。

当滚动频率为每日或更低时,滚动文件追加器将在服务器默认时区的午夜滚动文件。

可以通过在 %d 模式中指定不同的时区来修改滚动时间。有关详细信息,请参阅 日期转换器语法

参考 Plugin reference for TimeBasedTriggeringPolicy :: Apache Log4j

6、多个触发策略

滚动文件附加器只允许一个嵌套的触发策略。如果要使用多个策略,则需要将它们包装在 policies 元素中,该元素本身没有配置属性。

例如,以下 XML 片段定义了滚动日志的策略:

  • 在 JVM 启动时
  • 当日志文件大小达到 10 MB 时
  • 当地时间午夜
1
2
3
4
5
6
7
8
9
10
<RollingFile name="FILE"
fileName="app.log"
filePattern="app.%d{yyyy-MM-dd}.%i.log">
<JsonTemplateLayout/>
<Policies>
<OnStartupTriggeringPolicy/>
<SizeBasedTriggeringPolicy/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>

参考 Plugin reference for Multiple policies :: Apache Log4j

7、触发策略示例

1
2
3
4
5
6
7
8
9
<RollingFile name="FULL_FILE_OUT_ASYNC"
fileName="${LOG_HOME}/${APP_NAME}.log"
filePattern="${LOG_HOME}/%d{yyyy-MM}/${APP_NAME}.%d{yyyy-MM-dd}.%03i.log.gz">
<PatternLayout pattern="${FILE_LOG_PATTERN}" charset="${CHARSET}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>

三、滚动策略(Rollover strategies)

滚动策略决定了旧的归档文件如何被轮换或删除,以腾出空间给新的日志文件。在滚动过程中执行的动作包括:

  • 循环重命名文件
  • 压缩归档的日志文件
  • 删除旧的归档日志文件
  • 更改归档日志文件的 POSIX 权限

内置提供了两种不同的滚动策略:

DefaultRolloverStrategy(默认滚动策略)

这是当指定了 fileName 配置属性时使用的默认策略。它将当前的日志文件存储在 fileName 指定的位置,并将归档的日志文件存储在 filePattern 指定的位置。

DirectWriteRolloverStrategy(直接写入滚动策略)

这是当 fileName 配置属性为 null 时使用的默认策略。它直接将当前的日志文件存储在其由 filePattern 指定的滚动位置。

注意:不建议在 fileName 配置属性中使用 runtime lookups,因为这会破坏 DefaultRolloverStrategy 的逻辑。相反,可以通过省略配置中的 fileName 属性来使用 DirectWriteRolloverStrategy

1、通用配置

两种滚动策略都支持以下配置参数:

属性 类型 默认值 描述
compressionLevel int 7 确定归档日志文件的压缩级别。
tempCompressedFilePattern Path 存储压缩文件的临时位置。
stopCustomActionsOnError boolean true 如果为true,则如果其中一个自定义操作失败,则将停止这些操作。

2、DefaultRolloverStrategy 配置

DefaultRolloverStrategy 属性支持日志文件索引增量相关的额外属性:

属性 类型 默认值 描述
fileIndex 枚举 max 决定当前日志文件的 %i 转换模式值的策略。
支持的值有:

- min:使用 min 属性的值。
- max:使用 min 和 max 属性之间的第一个未使用的整数。
- nomax:使用不低于 min 属性值的第一个未使用的整数。
min 整数 1 %i 转换模式的最小值。
max 整数 7 %i 转换模式的最大值。
如果 fileIndex 设置为 nomax,则忽略此属性。

根据上述配置,当您配置日志记录器以滚动创建新日志文件时,您可以控制这些新文件的索引如何递增。例如,如果您设置 fileIndexmax,它将会在指定范围内寻找一个尚未被使用的最大可能索引号作为新的日志文件名的一部分。如果 fileIndex 设置为 nomax,那么它将不会考虑 max 属性,而是只确保索引不低于 min 属性所指定的值,并且是未被使用的。

在滚动时,DefaultRolloverStrategy 根据以下描述的算法重命名文件。

DefaultRolloverStrategy 是基于时间策略和固定窗口策略的组合。当文件名模式包含日期格式时,则将使用滚动时间间隔来计算用于文件模式的时间。当文件模式中包含整数替换标记(token)时,则会使用其中一种计数技术。

ascending 属性设置为 true(默认值)时,计数器将会递增,并且当前的日志文件会被重命名为包含计数值。如果计数器达到了最大值,那么最旧的文件(即具有最小计数值的文件)将被删除,所有其他文件将被重命名以使其计数减一,然后当前文件将被重命名为具有最大计数值。请注意,使用这种计数策略时,指定一个较大的最大值可能会完全避免重命名文件。

ascending 属性设置为 false 时,则会使用“正常”的固定窗口策略。

假设 maxmin 分别代表 MaxIndexMinIndex 选项的值。设 “foo.log” 是 ActiveFile 选项的值,而 “foo.%i.log” 是 FileNamePattern 的值。那么,在滚动时,文件 “foo.max.log” 将被删除,文件 “foo.max-1.log” 将被重命名为 “foo.max.log”,文件 “foo.max-2.log” 将被重命名为 “foo.max-1.log”,以此类推,文件 “foo.min+1.log” 将被重命名为 “foo.min+2.log”。最后,活动文件 “foo.log” 将被重命名为 “foo.min.log”,并创建一个新的活动文件名为 “foo.log” 的文件。

鉴于此滚动算法需要与窗口大小相等数量的文件重命名操作,因此不建议使用较大的窗口大小。

1
2
3
4
5
6
7
<DefaultRolloverStrategy compressionLevel=""
fileIndex=""
max=""
min=""
stopCustomActionsOnError=""
tempCompressedFilePattern="">
</DefaultRolloverStrategy>

Plugin reference :: Apache Log4j

3、DirectWriteRolloverStrategy 配置

DirectWriteRolloverStrategy 拥有一套更少的配置选项用于递增文件索引:

  • 最小文件索引始终为 1。
  • 递增策略始终为 max(即使用 min 和 max 之间的第一个未使用的整数)。

可以通过以下配置属性来设置最大文件索引:

属性 类型 默认值 描述
maxFiles 整数 7 %i 转换模式的最大值。
1
2
3
4
5
<DirectWriteRolloverStrategy compressionLevel=""
maxFiles=""
stopCustomActionsOnError=""
tempCompressedFilePattern="">
</DirectWriteRolloverStrategy>

根据上述配置,DirectWriteRolloverStrategy 简化了文件索引的管理方式,最小索引固定为 1,并且在寻找下一个可用索引时总是采用 max 策略,即在 1 到由 maxFiles 属性定义的最大值之间查找第一个未被使用的索引。默认情况下,最大文件索引数量是 7,但可以通过配置 maxFiles 属性来更改这个数值。

Plugin reference :: Apache Log4j

4、文件名称递增规则

在滚动事件期间,当前的日志文件会被移动到通过评估 filePattern 确定的位置,并使用 min 作为 %i 转换模式的值。如果该位置已经存在旧的日志文件,则滚动文件追加器(rolling file appender)会:

  • 尝试根据 fileIndex 配置属性指定的策略递增 %i 的值。
  • 如果上述操作失败,则它会移除最旧的日志文件,并将剩余的日志文件进行轮转,以为新的日志归档腾出空间。

这段描述说明了当发生日志滚动时,系统如何处理现有日志文件,以确保新日志文件能够被正确命名和存储,同时管理旧日志文件的数量和命名,避免冲突。

有三个策略可用:

min

使用 min 策略,最新的日志文件将具有索引 min,最旧的日志文件具有索引 max。

这是传统 UNIX 工具和 Log4j 1 使用的日志轮换策略。这不是 Log4j 2 的默认策略。

假设 min 为 1,max 为 3,日志文件的旋转如下图所示:

max

使用 max 策略,最旧的日志文件将具有索引 min,最新的日志文件具有索引 max。

这是 Log4j 2 以来的默认策略。

假设 min 为 1,max 为 3,日志文件的旋转如下图所示:

nomax

使用 normax 策略,将永远不会删除任何文件,并且将从最小值开始为较新的存档文件分配递增的索引号。

5、压缩归档文件

当前日志文件被归档时,滚动文件追加器可以对其进行压缩。压缩功能是根据归档文件名的扩展名来激活的。以下是识别的扩展名及其说明:

扩展名 支持 compressionLevel 描述
.zip 使用 DEFLATE 算法的 ZIP 归档
.gz 使用 DEFLATE 算法的 GZIP 归档
.bz2 BZip2 算法(需要额外依赖)
.deflate DEFLATE 算法(需要额外依赖)
.pack200 Pack200 算法(需要额外依赖)
.xz XZ 算法(需要额外依赖)
.zst ZStandard 算法(需要额外依赖)

如果设置了 tempCompressedFilePattern 属性,当前的日志文件将会:

  • 被压缩并存储在由 tempCompressedFilePattern 指定的位置,
  • 然后它将被移动到由 filePattern 指定的位置。

要使用这些压缩算法中的某些需要额外依赖的算法,需要额外的依赖项:

1
2
3
4
5
6
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.27.1</version>
<scope>runtime</scope>
</dependency>

.xz.zst 扩展名需要额外的依赖项。更多详情请参阅 Commons Compress 文档

四、Optional actions

五、Configuration recipes

其他问题

1、RollingFile Appender 中 fileName 属性和 filePattern 属性的联系与区别

fileName:指定了当前日志文件的名称和路径。这是应用程序正在写入的日志文件的位置。通常这个文件是最近的日志文件,直到触发了滚动条件(例如达到一定大小或到了指定的时间点),这时当前日志文件会被归档,新的日志文件会以 fileName 指定的名字创建并开始写入。

filePattern:定义了滚动后归档日志文件的命名模式。它包含了归档日志文件的路径以及它们如何根据滚动策略进行命名。filePattern 可以包含占位符,这些占位符会在滚动发生时被实际的值替换,比如日期、时间、序列号等。

相关链接

Plugin reference for TriggeringPolicy :: Apache Log4j

Plugin reference for OnStartupTriggeringPolicy :: Apache Log4j

Plugin reference for CronTriggeringPolicy :: Apache Log4j

Plugin reference for SizeBasedTriggeringPolicy :: Apache Log4j

Plugin reference for TimeBasedTriggeringPolicy :: Apache Log4j

Plugin reference for Multiple policies :: Apache Log4j

Plugin reference :: Apache Log4j

Commons Compress 文档

OB tags

#日志 #未完待续