Appender负责将LogEvents传递到其目的地。 每个Appender必须实现Appender接口。 大多数Appender都会扩展AbstractAppender,从而增加Lifecycle和Filterable支持。 Lifecycle允许组件在配置完成后完成初始化,并在关闭期间执行清理。 Filterable允许组件添加过滤器,这些过滤器将在事件处理期间进行执行。
Appender通常仅负责将事件数据写入目标地址。 在大多数情况下,他们将格式化委托给 layout。 一些Appender会嵌套Appender,以便它们可以修改LogEvent、处理Appender中的异常事件、根据高级Filter将事件传递给下游Appender或提供不会直接格式化事件以进行查看的类似功能。
每一个Appender都有一个name,可以让Looger通过name进行引用。
AsyncAppender
AsyncAppender接受对其他Appender的引用,并使LogEvents在单独的线程上写入它们。 请注意,写入这些Appender时的异常将从应用程序中隐藏。 应该在引用的附加程序之后配置AsyncAppender,以使其能够正常关闭。
默认情况下,AsyncAppender使用java.util.concurrent.ArrayBlockingQueue,它不需要任何外部库。 请注意,以这种方式使用此附加程序时,多线程的应用很容易容易发生锁争用,并且测试表明,当同时记录多个线程时,性能可能会变差。
所以,我们一般在常见的web项目中不使用这个Appender用于日志打印,更多地考虑使用无锁异步记录器以获得最佳性能。。
Parameter Name | Type | Description |
---|---|---|
AppenderRef | String | 引用的Appender |
blocking | boolean | 是否阻塞等待(这里指队列满后的处理) |
shutdownTimeout | integer | appender关闭时等待的超时时间 |
bufferSize | integer | 阻塞队列的最大容量,默认1024 |
errorRef | String | 队列满后如果不阻塞时配置的errorAppender,如果不指定,错误江北忽略 |
filter | Filter | 过滤器 |
name | String | 名称 |
ignoreExceptions | boolean | 用于决定是否需要记录在日志事件处理过程中出现的异常,默认true |
includeLocation | boolean | Buffer的种类(默认ArrayBlockingQueue,能够支持DisruptorBlockingQueue,JCToolsBlockingQueue,LinkedTransferQueue) |
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<File name="MyFile" fileName="logs/app.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<Async name="Async">
<AppenderRef ref="MyFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Async"/>
</Root>
</Loggers>
</Configuration>
ConsoleAppender
顾名思义,ConsoleAppender将通过System.out或System.err将日志打印在控制台,默认为System.out。 该Appender必须提供一个layout以格式化LogEvent。
Parameter Name | Type | Description |
---|---|---|
filter | Filter | 过滤器 |
layout | Layout | 格式化 LogEvent ,默认“%m%n” |
name | String | 名称 |
target | String | "SYSTEM_OUT" 或者 "SYSTEM_ERR",默认为"SYSTEM_OUT". |
(还有一些其他不常见属性见官方文档)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
FileAppender
FileAppender是一个OutputStreamAppender,它写入fileName参数中命名的File。 FileAppender使用FileManager(扩展了OutputStreamManager)来实际执行文件I / O。
虽然无法共享来自不同配置的FileAppender,但是如果可访问Manager,则可以使用FileManager。 例如,如果Log4j在两个容器都使用公共的ClassLoader,则Servlet容器中的两个Web应用程序可以使用不同的配置,还可以安全地写入同一文件。
Parameter Name | Type | Description |
---|---|---|
append | boolean | 默认true,新的日志附加在结尾,如果为false,则在新日志写入之前清空日志 |
bufferedIO | boolean | 默认true,记录将被写入缓冲区,当缓冲区已满时,数据将被写入磁盘;不能与locking一起使用 |
bufferSize | int | 当 bufferedIO 为 true 时,缓冲区大小,默认为 8192 字节 |
createOnDemand | boolean | 默认false,按需创建文件 |
filter | Filter | 过滤器 |
fileName | String | 文件名 |
immediateFlush | boolean | 默认true,每次写入后都会刷新,保证数据写入磁盘,对性能有影响 |
layout | Layout | 格式化 LogEvent ,默认“%m%n” |
locking | boolean | 默认false。设置为 true 时,I / O操作仅在保持文件锁定的同时发生,以允许多个JVM和可能的多个主机中的FileAppenders同时写入同一文件。 |
name | String | 名称 |
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<File name="MyFile" fileName="logs/app.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
RandomAccessFileAppender
RandomAccessFileAppender与FileAppender相似,但是它总是通过写入缓冲区再写入文件的方式,且不能配置关闭。在内部它使用ByteBuffer + RandomAccessFile而不是BufferedOutputStream。 在性能测试中,与FileAppender相比,bufferedIO = true
的性能提高了20-200%。 与FileAppender相似,RandomAccessFileAppender使用RandomAccessFileManager实际执行文件I / O。
虽然不能共享来自不同配置的RandomAccessFileAppender,但是如果可以访问Manager,则可以使用RandomAccessFileManagers。 例如,如果Log4j在两个容器都使用公共的ClassLoader,则Servlet容器中的两个Web应用程序可以使用不同的配置,还可以安全地写入同一文件。
Parameter Name | Type | Description |
---|---|---|
append | boolean | 默认true,新的日志附加在结尾,如果为false,则在新日志写入之前清空日志 |
fileName | String | 文件名 |
filters | Filter | 过滤器 |
immediateFlush | boolean | 默认true,每次写入后都会刷新,保证数据写入磁盘,对性能有影响 |
bufferSize | int | 缓冲区大小,默认 262,144 字节(256 * 1024). |
layout | Layout | 格式化 LogEvent ,默认“%m%n” |
name | String | 名称 |
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RandomAccessFile name="MyFile" fileName="logs/app.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
RollingFileAppender
这个是生产环境常用的Appender。RollingFileAppender是一个OutputStreamAppender,它写入fileName参数中命名的File并根据TriggeringPolicy和RolloverPolicy将文件滚动。 RollingFileAppender使用RollingFileManager(扩展了OutputStreamManager)来实际执行文件I / O并执行过渡。
RollingFileAppender需要一个TriggeringPolicy和一个RolloverStrategy。TriggeringPolicy为触发策略,其决定了何时触发日志文件的rollover,RolloverStrategy为滚动更新策略,其决定了当触发了日志文件的rollover时,如何进行文件的rollover。
如果未配置RolloverStrategy,则RollingFileAppender将使用DefaultRolloverStrategy。 从log4j-2.5开始,可以在DefaultRolloverStrategy中将自定义删除操作配置为在轮转时运行。 从2.8开始,如果未配置任何文件名,则将使用DirectWriteRolloverStrategy代替DefaultRolloverStrategy。
RollingFileAppender不支持文件锁定。
Parameter Name | Type | Description |
---|---|---|
append | boolean | 默认true,新的日志附加在结尾,如果为false,则在新日志写入之前清空日志 |
bufferedIO | boolean | 默认true,记录将被写入缓冲区,当缓冲区已满时,数据将被写入磁盘;不能与locking一起使用 |
bufferSize | int | 当 bufferedIO 为 true 时,缓冲区大小,默认为 8192 字节 |
createOnDemand | boolean | 默认false,按需创建文件 |
filter | Filter | 过滤器 |
fileName | String | 文件名 |
filePattern | String | 归档日志文件的文件名的格式。 格式取决于所使用的RolloverPolicy。 DefaultRolloverPolicy将接受与SimpleDateFormat兼容的日期/时间模式和/或代表整数计数器的%i。 该模式还支持在运行时进行插值,因此任何查询(例如DateLookup)都可以包含在该模式中 |
immediateFlush | boolean | 默认true,每次写入后都会刷新,保证数据写入磁盘,对性能有影响 |
layout | Layout | 格式化 LogEvent ,默认“%m%n” |
name | String | 名称 |
policy | TriggeringPolicy | 用于确定是否应进行轮转的策略 |
strategy | RolloverStrategy | 用于确定存档文件的名称和位置的策略。 |
Triggering Policies(触发策略)
Composite Triggering Policy(组合触发策略)
CompositeTriggeringPolicy组合了多个触发策略,如果任何已配置的策略返回true,则返回true。 通过将其他策略包装在Policies元素中,即可简单地配置CompositeTriggeringPolicy。
例如,以下XML片段定义了以下策略:在JVM启动时,日志大小达到20兆字节以及当前日期与日志的开始日期不匹配时,对日志进行轮转。
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="20 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
Cron Triggering Policy(定时触发策略)
CronTriggeringPolicy基于cron表达式触发轮转。 此策略由计时器控制,并且与处理日志事件异步,因此上一个或下一个时间段的日志事件可能会出现在日志文件的开头或结尾。 Appender的filePattern属性应包含一个时间戳,否则目标文件将在每次轮转时被覆盖。
Parameter Name | Type | Description |
---|---|---|
schedule | String | cron表达式 |
evaluateOnStartup | boolean | 启动时,将根据文件的最后修改时间戳评估cron表达式。 如果cron表达式表示在该时间和当前时间之间应该发生rollover ,则文件将立即rollover 。 |
OnStartup Triggering Policy
如果日志文件比当前jvm启动时间更早以及满足或者超过最小文件的大小就会触发rollover
Parameter Name | Type | Description |
---|---|---|
minSize | long | 文件必须rollover 的最小大小。 大小为零将导致rollover ,无论文件大小如何。 默认值为1,这将防止将空文件rollover 。 |
SizeBased Triggering Policy(基于大小的触发策略)
文件达到指定大小后,SizeBasedTriggeringPolicy会触发rollover
。 大小可以字节为单位指定,后缀为KB,MB或GB,例如20MB。 与基于时间的触发策略结合使用时,文件模式必须包含%i,否则目标文件将在每次rollover
时均被覆盖,因为基于大小的触发策略不会导致文件名中的时间戳值更改。 如果不使用基于时间的触发策略,则基于大小的触发策略将导致时间戳值发生更改。
TimeBased Triggering Policy(基于时间的触发策略)
一旦时间达到配置的date/time pattern,则TimeBasedTriggeringPolicy会产生rollover
。
Parameter Name | Type | Description |
---|---|---|
interval | integer | 多久发生一次rollover ,默认为1,单位小时 |
modulate | boolean | 表示是否调整时间间隔以使在时间间隔边界发生下一个rollover 。例如,当前时间是凌晨3点,间隔是4h,则第一次翻转将在凌晨4点发生,然后下一个rollover 将在早上8点,中午12点,下午4点等发生。 |
maxRandomDelay | integer | 表示随机延迟过渡的最大秒数。默认为0,无延迟。 此设置在配置了多个应用程序以同时滚动日志文件的服务器上很有用,并且可以在整个时间上分散这样做的负担。 |
Rollover Strategies(轮转策略)
Default Rollover Strategy
default rollover strategy接受一个日期/时间pattern和一个整数,其中这个整数,是RollingFileAppender本身指定的filePattern属性。如果date/time模式存在的话,它将会替换当前日期和时间的值。如果这个模式包含整数的话,它将会在每次发生rollover时,进行递增。如果模式同时包含date/time和整数,那么在模式中,整数会递增直到结果中的data/time模式发生改变。如果文件模式是以".gz", ".zip", ".bz2", ".deflate", ".pack200", or ".xz"结尾的,将会与后缀相匹配的压缩方案进行压缩文件。格式为:bzip2, Deflate, Pack200 和 XZ需要Apache Commons Compress,此外,XZ需要XZ for Java
该模式还可以包含可以在运行时解析的查找引用,如下面的示例所示:
Parameter Name | Type | Description |
---|---|---|
fileIndex | String | 默认为max,文件名的index越大,文件则越新,设置为min则相反 |
min | integer | 默认为1,计数器最小值 |
max | integer | 默认为7,计数器最大值,一旦达到此值,较旧的归档文件将在以后的转换中被删除。 |
compressionLevel | integer | 压缩级别,范围为0-9,其中0 =无,1 =最佳速度,直到9 =最佳压缩。 仅针对ZIP文件实现 |
tempCompressedFilePattern | String | 压缩期间归档日志文件的文件名的模式 |
DirectWrite Rollover Strategy
DirectWriteRolloverStrategy让日志事件直接写入由文件模式表示的文件。 使用此策略文件不会执行重命名。 如果基于大小的触发策略导致在指定的时间段内写入多个文件,则它们将从一个开始编号,并不断递增直到发生基于时间的rollover
。
警告:如果filePattern的后缀表示应该进行压缩,则在关闭应用程序时不会压缩当前文件。 此外,如果时间更改使得文件模式不再与当前文件匹配,则启动时也不会对其进行压缩。
Parameter Name | Type | Description |
---|---|---|
maxFiles | String | 同一时间段内与filePattern匹配的最大文件数。 如果超出文件数量,则最早的文件将被删除。 如果指定,则该值必须大于1。如果该值小于零或省略,则文件数量将不受限制。 |
compressionLevel | integer | 压缩级别,范围为0-9,其中0 =无,1 =最佳速度,直到9 =最佳压缩。 仅针对ZIP文件实现 |
tempCompressedFilePattern | String | 压缩期间归档日志文件的文件名的Pattern |
示例:
该配置使用具有基于时间和大小的触发策略的RollingFileAppender,将在同一天(1-7)最多创建20个归档文件,并根据当前年份和月份存储在目录中,并且 使用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{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>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
基于cron和大小的触发策略,每小时保存的文件数限制为10。 当文件大小限制为250MB时,cron触发器每小时导致一次翻转,:
<?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>
归档日志删除策略
在2.5版本之后加入了一个删除策略,你可以自定义删除旧日志存档的策略。
Parameter Name | Type | Description |
---|---|---|
basePath | String | 必选。要删除的路径 |
maxDepth | int | 要访问的目录的最大级别数。 值为0表示仅访问起始文件(基本路径本身),除非安全管理器拒绝。 Integer.MAX_VALUE的值指示应访问所有级别。 默认值为1,表示仅指定基本目录中的文件。 |
followLinks | boolean | 是否遵循符号链接。 默认false。 |
testMode | boolean | 如果为true,则不会删除文件,而是在INFO级别将一条消息打印到status logger。 使用此功能可以进行空运行以测试配置是否按预期工作。 默认为false。 |
pathSorter | PathSorter | 一个实现PathSorter接口的插件,用于在选择要删除的文件之前对文件进行排序。 默认设置是首先对最近修改的文件进行排序。 |
pathConditions | PathCondition[] | 如果未指定ScriptCondition,则为必需。 一个或多个PathCondition元素。见官方文档 |
scriptCondition | ScriptCondition | 如果未指定PathConditions,则为必需。 指定脚本的ScriptCondition元素。见官方文档 |
示例
该配置使用RollingFileAppender和cron触发策略,该策略配置为每天午夜触发。 存档存储在基于当前年份和月份的目录中。 基本目录下与 */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>
示例2
该配置使用具有基于时间和大小的触发策略的RollingFileAppender,将在同一天(1-100)上创建多达100个归档文件,这些归档文件基于当前年份和月份存储在目录中,并且使用gzip压缩每个归档文件,并将每小时滚动一次。 在每次轮转期间,此配置都将删除与 * / app-*.log.gz
匹配且早于30天的文件,但保留最新的100 GB或最新的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>
RollingRandomAccessFileAppender
RollingRandomAccessFileAppender与RollingFileAppender相似,但是它总是通过写入缓冲区再写入文件的方式,且不能配置关闭。在内部它使用ByteBuffer + RandomAccessFile而不是BufferedOutputStream。 在性能测试中,与FileAppender相比,bufferedIO = true
的性能提高了20-200%。
Parameter Name | Type | Description |
---|---|---|
append | boolean | 默认true,新的日志附加在结尾,如果为false,则在新日志写入之前清空日志 |
bufferSize | int | 缓冲区大小,默认 262,144 字节(256 * 1024) |
filter | Filter | 过滤器 |
fileName | String | 文件名 |
filePattern | String | 归档日志文件的文件名的格式。 格式取决于所使用的RolloverPolicy。 DefaultRolloverPolicy将接受与SimpleDateFormat兼容的日期/时间模式和/或代表整数计数器的%i。 该模式还支持在运行时进行插值,因此任何查询(例如DateLookup)都可以包含在该模式中 |
immediateFlush | boolean | 默认true,每次写入后都会刷新,保证数据写入磁盘,对性能有影响 |
layout | Layout | 格式化 LogEvent ,默认“%m%n” |
name | String | 名称 |
policy | TriggeringPolicy | 用于确定是否应进行轮转的策略 |
strategy | RolloverStrategy | 用于确定存档文件的名称和位置的策略。 |
示例:
该配置使用具有基于时间和大小的触发策略的RollingRandomAccessFileAppender,将在同一天(1-7)创建最多20个归档文件,这些归档文件基于当前年份和月份存储在目录中,并且 使用gzip压缩每个档案:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingRandomAccessFile name="RollingRandomAccessFile" 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"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingRandomAccessFile"/>
</Root>
</Loggers>
</Configuration>