一、Appenders 概述
Appenders 负责将日志事件(LogEvents)发送到其目标位置。每个 Appender 必须实现 Appender
接口,大多数 Appender 会扩展 AbstractAppender
,它增加了生命周期(Lifecycle)和可过滤(Filterable)支持。生命周期允许组件在配置完成后完成初始化,并在关闭时进行清理。可过滤性允许组件附加过滤器,在事件处理过程中对事件进行评估。
Appenders 通常只负责将事件数据写入目标位置,在大多数情况下,它们将事件的格式化责任委托给布局(layout)。一些 Appender 会包装其他 Appender,以便可以修改日志事件、处理 Appender 中的故障、基于高级过滤条件将事件路由到从属 Appender 或提供类似的功能,但不直接格式化事件以供查看。
Appenders 总是有一个名称,以便可以从日志记录器(Loggers)中引用它们。
二、各种 Appender 类型介绍
1. AsyncAppender
- 功能:接受对其他 Appender 的引用,并在单独的线程上异步地将日志事件写入这些 Appender。注意,在写入这些 Appender 时发生的异常将对应用程序隐藏。
- 配置参数:
AppenderRef
:要异步调用的 Appender 的名称,可以配置多个。blocking
:如果为true
,当队列已满时,Appender 将等待直到有空闲位置。如果为false
,当队列已满时,事件将被写入错误 Appender(如果配置了)。默认是true
。shutdownTimeout
:在关闭时,Appender 应等待多长时间(以毫秒为单位)来刷新队列中的未完成日志事件。默认是 0,表示永远等待。bufferSize
:指定可以排队的最大事件数。默认是 1024。注意,当使用中断器风格的阻塞队列时,这个缓冲区大小必须是 2 的幂。errorRef
:如果由于 Appender 中的错误或队列已满而无法调用任何 Appender 时,要调用的 Appender 的名称。如果未指定,则错误将被忽略。filter
:过滤器,用于确定事件是否应由此 Appender 处理。可以使用CompositeFilter
使用多个过滤器。name
:Appender 的名称。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。includeLocation
:提取位置是一个昂贵的操作(它可以使日志记录速度慢 5 - 20 倍)。为了提高性能,默认情况下,在将日志事件添加到队列时不包括位置。可以通过设置includeLocation="true"
来更改此设置。BlockingQueueFactory
:此元素覆盖要使用的BlockingQueue
的类型。
- 系统属性:有一些系统属性可以在底层 Appender 无法跟上日志记录速率且队列已满时维持应用程序的吞吐量。例如
log4j2.AsyncQueueFullPolicy
和log4j2.DiscardThreshold
。 - 自定义阻塞队列:从 Log4j 2.7 开始,可以使用
BlockingQueueFactory
插件指定自定义的BlockingQueue
或TransferQueue
的实现。 - 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp">
<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>
2. CassandraAppender
扫描二维码关注公众号,回复:
17526694 查看本文章

- 功能:将输出写入到 Apache Cassandra 数据库。必须提前配置键空间(keyspace)和表,并且该表的列在配置文件中进行映射。
- 配置参数:
batched
:是否使用批处理语句将日志消息写入 Cassandra。默认是false
。batchType
:使用批处理写入时的批处理类型。默认是LOGGED
。bufferSize
:在写入之前要缓冲或批处理的日志消息数量。默认不进行缓冲。clusterName
:要连接的 Cassandra 集群的名称。columns
:列映射配置列表。每个列必须指定列名,可以指定转换类型,如果配置的类型与ReadOnlyStringMap
/ThreadContextMap
或ThreadContextStack
兼容,则该列将分别用 MDC 或 NDC 填充。如果配置的类型与java.util.Date
兼容,则日志时间戳将转换为该配置的日期类型。如果给出了literal
属性,则其值将在INSERT
查询中按原样使用,无需转义。否则,指定的布局或模式将转换为配置的类型并存储在该列中。contactPoints
:Cassandra 节点的主机和端口列表。这些必须是有效的主机名或 IP 地址。默认情况下,如果未为主机指定端口或设置为 0,则将使用默认的 Cassandra 端口 9042。默认使用localhost:9042
。filter
:过滤器。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。keyspace
:包含要写入日志消息的表的键空间的名称。name
:Appender 的名称。password
:用于连接 Cassandra 的密码(与用户名一起使用)。table
:要写入日志消息的表的名称。useClockForTimestampGenerator
:是否使用配置的org.apache.logging.log4j.core.util.Clock
作为时间戳生成器。默认是false
。username
:用于连接 Cassandra 的用户名。默认情况下,不使用用户名和密码。useTls
:是否使用 TLS/SSL 连接到 Cassandra。默认是false
。
- 代码示例:
<Configuration name="CassandraAppenderTest">
<Appenders>
<Cassandra name="Cassandra" clusterName="Test Cluster" keyspace="test" table="logs" bufferSize="10" batched="true">
<SocketAddress host="localhost" port="9042"/>
<ColumnMapping name="id" pattern="%uuid{TIME}" type="java.util.UUID"/>
<ColumnMapping name="timeid" literal="now()"/>
<ColumnMapping name="message" pattern="%message"/>
<ColumnMapping name="level" pattern="%level"/>
<ColumnMapping name="marker" pattern="%marker"/>
<ColumnMapping name="logger" pattern="%logger"/>
<ColumnMapping name="timestamp" type="java.util.Date"/>
<ColumnMapping name="mdc" type="org.apache.logging.log4j.spi.ThreadContextMap"/>
<ColumnMapping name="ndc" type="org.apache.logging.log4j.spi.ThreadContextStack"/>
</Cassandra>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.cassandra" level="DEBUG">
<AppenderRef ref="Cassandra"/>
</Logger>
<Root level="ERROR"/>
</Loggers>
</Configuration>
3. ConsoleAppender
- 功能:如预期的那样,将输出写入到
System.out
或System.err
,默认目标是System.out
。必须提供布局(Layout)来格式化日志事件。 - 配置参数:
filter
:过滤器。layout
:用于格式化日志事件的布局。如果未提供布局,则使用默认的模式布局%m%n
。follow
:标识 Appender 是否在配置后通过System.setOut
或System.setErr
重新分配System.out
或System.err
时进行响应。注意,在 Windows 上使用 Jansi 时不能使用follow
属性。不能与direct
一起使用。direct
:直接写入java.io.FileDescriptor
,绕过java.lang.System.out/.err
。当输出重定向到文件或其他进程时,可以提高高达 10 倍的性能。在 Windows 上使用 Jansi 时不能使用。不能与follow
一起使用。输出将不尊重java.lang.System.setOut()/.setErr()
,并且在多线程应用程序中可能与其他输出到java.lang.System.out/.err
的输出交织在一起。从 2.6.2 版本开始新增。请注意,这是一个新添加的功能,目前仅在 Linux 和 Windows 上的 Oracle JVM 上进行了测试。name
:Appender 的名称。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。target
:可以是"SYSTEM_OUT"
或"SYSTEM_ERR"
。默认是"SYSTEM_OUT"
。
- 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
4. FailoverAppender
- 功能:包装一组 Appender。如果主 Appender 失败,则将按顺序尝试辅助 Appender,直到一个成功或没有更多的辅助 Appender 可供尝试。
- 配置参数:
filter
:过滤器。primary
:主 Appender 的名称。failovers
:辅助 Appender 的名称列表。name
:Appender 的名称。retryIntervalSeconds
:在重试主 Appender 之前应经过的秒数。默认是 60。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。target
:可以是"SYSTEM_OUT"
或"SYSTEM_ERR"
。默认是"SYSTEM_ERR"
。
- 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz"
ignoreExceptions="false">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
<Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
<PatternLayout pattern="%m%n"/>
</Console>
<Failover name="Failover" primary="RollingFile">
<Failovers>
<AppenderRef ref="Console"/>
</Failovers>
</Failover>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Failover"/>
</Root>
</Loggers>
</Configuration>
5. FileAppender
- 功能:是一个
OutputStreamAppender
,它将写入到在fileName
参数中指定的文件。使用FileManager
(扩展OutputStreamManager
)来实际执行文件 I/O。虽然来自不同配置的FileAppender
不能共享,但FileManagers
可以在管理器可访问的情况下共享。 - 配置参数:
append
:当为true
(默认)时,记录将追加到文件末尾。当设置为false
时,在写入新记录之前,文件将被清空。bufferedIO
:当为true
(默认)时,记录将被写入缓冲区,并且当缓冲区已满或(如果immediateFlush
设置为true
)在写入记录时,数据将被写入磁盘。性能测试表明,使用缓冲 I/O 可以显著提高性能,即使启用了立即刷新。bufferSize
:当bufferedIO
为true
时,这是缓冲区大小,默认是 8192 字节。createOnDemand
:Appender 在需要时创建文件。只有当日志事件通过所有过滤器并被路由到此 Appender 时,Appender 才会创建文件。默认是false
。filter
:过滤器。fileName
:要写入的文件的名称。如果文件或其任何父目录不存在,它们将被创建。immediateFlush
:当设置为true
(默认)时,每次写入后将进行刷新。这将保证数据传递给操作系统进行写入;但它不保证数据实际上被写入物理设备(如磁盘驱动器)。如果此标志设置为false
,并且日志记录活动稀疏,则数据最终到达操作系统可能会有无限期的延迟,因为它被保存在缓冲区中。这可能会导致意外的效果,例如在写入日志后,日志不会立即出现在文件的尾部输出中。对于同步日志记录器和 Appender,每次写入后刷新是有用的。异步日志记录器和 Appender 将在一批事件结束时自动刷新,即使immediateFlush
设置为false
。这也保证了数据传递给操作系统,但更高效。layout
:用于格式化日志事件的布局。如果未提供布局,则使用默认的模式布局%m%n
。locking
:当设置为true
时,I/O 操作仅在持有文件锁时发生,允许在多个 JVM 中甚至可能在多个主机上的FileAppender
同时写入同一文件。这将显著影响性能,因此应谨慎使用。此外,在许多系统上,文件锁是“建议性的”,这意味着其他应用程序可以在不获取锁的情况下对文件执行操作。默认值是false
。name
:Appender 的名称。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。filePermissions
:以 POSIX 格式指定的文件属性权限,在创建文件时应用。底层文件系统必须支持 POSIX 文件属性视图。例如:rw-------
或rw-rw-rw-
等。fileOwner
:在创建文件时定义的文件所有者。更改文件所有者可能出于安全原因受到限制,并抛出Operation not permitted IOException
。只有具有有效用户 ID 等于文件的用户 ID 或具有适当权限的进程才能在_POSIX_CHOWN_RESTRICTED
对路径生效时更改文件的所有权。底层文件系统必须支持文件所有者属性视图。fileGroup
:在创建文件时定义的文件组。底层文件系统必须支持 POSIX 文件属性视图。
- 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp">
<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>
6. FlumeAppender
- 功能:这是一个在单独的 jar 中提供的可选组件。Apache Flume 是一个分布式、可靠且可用的系统,用于从许多不同的源高效地收集、聚合和移动大量日志数据到集中式数据存储。
FlumeAppender
接受日志事件并将它们作为序列化的 Avro 事件发送到 Flume 代理以供消费。 - 操作模式:
- 作为远程 Flume 客户端,通过 Avro 将 Flume 事件发送到配置有 Avro 源的 Flume 代理。
- 作为嵌入式 Flume 代理,Flume 事件直接传递到 Flume 进行处理。
- 将事件持久化到本地 BerkeleyDB 数据存储,然后异步地将事件发送到 Flume,类似于嵌入式 Flume 代理,但没有大多数 Flume 依赖项。
- 配置参数:
agents
:要将日志事件发送到的代理数组。如果指定了多个代理,第一个代理将是主代理,后续代理将在主代理失败时按指定顺序用作辅助代理。每个代理定义提供代理的主机和端口。指定agents
和properties
是互斥的。如果两者都配置,将导致错误。agentRetries
:在失败到辅助代理之前,代理应重试的次数。当type="persistent"
指定时,此参数将被忽略(代理在失败到下一个之前只尝试一次)。batchSize
:应作为一批发送的事件数量。默认是 1。此参数仅适用于FlumeAppender
。compress
:当设置为true
时,消息体将使用 gzip 压缩。connectTimeoutMillis
:Flume 等待连接超时的毫秒数。dataDir
:当embedded
设置为true
且使用Agent
元素而不是Property
元素时,Flume 预写日志应写入的目录。filter
:过滤器。eventPrefix
:要添加到每个事件属性前面的字符串,以便与 MDC 属性区分开来。默认是空字符串。flumeEventFactory
:从 Log4j 事件生成 Flume 事件的工厂。默认工厂是FlumeAvroAppender
本身。layout
:用于格式化日志事件的布局。如果未指定布局,则使用RFC5424Layout
。lockTimeoutRetries
:在写入 Berkeley DB 时发生LockConflictException
时重试的次数。默认是 5。maxDelayMillis
:在发布批处理之前等待batchSize
个事件的最大毫秒数。mdcExcludes
:以逗号分隔的 MDC 键列表,应从FlumeEvent
中排除。这与mdcIncludes
属性互斥。mdcIncludes
:以逗号分隔的 MDC 键列表,应包含在FlumeEvent
中。MDC 中不在列表中的任何键将被排除。此选项与mdcExcludes
属性互斥。mdcRequired
:以逗号分隔的 MDC 键列表,必须存在于 MDC 中。如果一个键不存在,将抛出LoggingException
。mdcPrefix
:应添加到每个 MDC 键前面的字符串,以便与事件属性区分开来。默认字符串是"mdc:"
。name
:Appender 的名称。properties
:用于配置 Flume 代理的一个或多个Property
元素。属性必须在没有代理名称的情况下进行配置(应用程序名称用作此目的),并且不能配置源。可以使用"sources.log4j-source.interceptors"
为源指定拦截器。允许所有其他 Flume 配置属性。同时指定Agent
和Property
元素将导致错误。requestTimeoutMillis
:Flume 等待请求超时的毫秒数。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。type
:可以是"Avro"
、"Embedded"
或"Persistent"
,以指示所需的 Appender 变体。
- 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp">
<Appenders>
<Flume name="eventLogger" compress="true">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="eventLogger"/>
</Root>
</Loggers>
</Configuration>
7. JDBCAppender
- 功能:使用标准 JDBC 将日志事件写入关系数据库表。可以配置为使用 JNDI
DataSource
或自定义工厂方法获取 JDBC 连接。 - 配置参数:
name
:Appender 的名称,必填。ignoreExceptions
:默认是true
,导致在附加事件时遇到的异常被内部记录并然后被忽略。当设置为false
时,异常将被传播给调用者。在将此 Appender 包装在FailoverAppender
中时,必须将此设置为false
。filter
:过滤器。bufferSize
:缓冲大小。connectionSource
:连接源。tableName
:表名。columnConfigs
:列配置。columnMappings
:列映射。immediateFail
:资源不可用时是否立即失败。reconnectIntervalMillis
:重试连接的时间间隔。
- 连接源配置:
<DataSource>
:使用 JNDI。<ConnectionFactory>
:指向类方法对提供连接。<DriverManager>
:快速但无连接池的方式。否则,日志记录性能将受到极大影响。<PoolingDriver>
:使用 Apache Commons DBCP 提供连接池。
- 代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
<Appenders>
<JDBC name="databaseAppender" tableName="dbo.application_log">
<DataSource jndiName="java:/comp/env/jdbc/LoggingDataSource" />
<Column name="eventDate" isEventTimestamp="true" />
<Column name="level" pattern="%level" />
<Column name="logger" pattern="%logger" />
<Column name="message" pattern="%message" />
<Column name="exception" pattern="%ex{full}" />
</JDBC>
</Appenders>
<Loggers>
<Root level="warn">
<AppenderRef ref="databaseAppender"/>
</Root>
</Loggers>
</Configuration>