插件
介绍
Log4j 1.x 允许通过在大多数配置声明中要求类属性来进行扩展。在某些元素的情况下,特别是 PatternLayout,添加新模式转换器的唯一方法是扩展 PatternLayout 类并通过代码添加它们。Log4j 2 的一个目标是通过使用插件使扩展它变得极其容易。
在 Log4j 2 中,插件通过在类声明中添加 @Plugin 注释来声明。在初始化期间,Configuration 将调用 PluginManager 来加载内置的 Log4j 插件以及任何自定义插件。PluginManager
通过在五个地方查找插件
- 类路径上的序列化插件列表文件。这些文件在构建期间自动生成(更多详细信息见下文)。
- (仅限 OSGi) 每个活动 OSGi 捆绑包中的序列化插件列表文件。在激活时添加一个
BundleListener
以在log4j-core
启动后继续检查新捆绑包。 - (已弃用) 由
log4j.plugin.packages
系统属性指定的以逗号分隔的包列表。 - (已弃用) 传递给静态
PluginManager.addPackages
方法的包(在 Log4j 配置发生之前)。 - (已弃用) 在您的 log4j2 配置文件中声明的 packages。
如果多个插件指定相同的(不区分大小写)name
,则上面的加载顺序决定将使用哪个插件。例如,要覆盖由内置 FileAppender
类提供的 File
插件,您需要将您的插件放在 CLASSPATH 中的 JAR 文件中,该文件位于 log4j-core.jar
之前。不建议这样做;插件名称冲突会导致发出警告。请注意,在 OSGi 环境中,扫描插件的捆绑包的顺序通常与捆绑包安装到框架中的顺序相同。参见 getBundles() 和 SynchronousBundleListener。简而言之,名称冲突在 OSGi 环境中更加不可预测。
序列化插件列表文件由 log4j-core 工件中包含的注释处理器生成,该处理器将自动扫描您的代码以查找 Log4j 2 插件并在您的处理类中输出元数据文件。无需执行任何额外操作来启用此功能;除非您明确禁用它,否则 Java 编译器将自动拾取类路径上的注释处理器。在这种情况下,将重要的一点是向您的构建过程添加另一个编译步骤,该步骤仅使用 Log4j 2 注释处理器类 org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
处理注释处理。要使用 Apache Maven 执行此操作,请将以下执行添加到您的 maven-compiler-plugin(版本 2.2 或更高版本)构建插件中
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <executions> <execution> <id>log4j-plugin-processor</id> <goals> <goal>compile</goal> </goals> <phase>process-classes</phase> <configuration> <proc>only</proc> <annotationProcessors> <annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annotationProcessor> </annotationProcessors> </configuration> </execution> </executions> </plugin>
在处理配置时,将自动配置和初始化相应的插件。Log4j 2 利用几种不同的插件类别,这些类别在以下部分中描述。
核心
核心插件是那些直接由配置文件中的元素表示的插件,例如追加器、布局、记录器或过滤器。符合下一段中概述的规则的自定义插件可能只需在配置中引用,前提是它们已正确配置以由 PluginManager 加载。
每个核心插件都必须声明一个用 @PluginFactory
或 @PluginBuilderFactory
注释的静态方法。前者用于提供所有选项作为方法参数的静态工厂方法,而后者用于构造一个新的 Builder<T>
类,其字段用于注入属性和子节点。为了允许 Configuration
将正确的参数传递给该方法,该方法的每个参数都必须用以下属性类型之一进行注释。每个属性或元素注释都必须包含必须存在于配置中的名称,以便将配置项与其各自的参数匹配。对于插件构建器,如果注释中未指定名称,则将默认使用字段的名称。Log4j Core 中有数十个插件可以用作更复杂场景的示例,包括分层构建器类(例如,参见 FileAppender
)。有关更多详细信息,请参见 使用插件构建器扩展 Log4j。
属性类型
- PluginAttribute
- 参数必须使用 TypeConverter 从字符串转换。大多数内置类型已得到支持,但也可以提供自定义
TypeConverter
插件以提供更多类型支持。请注意,PluginBuilderAttribute
可用作构建器类字段,作为提供默认值的一种更简单方法。 - PluginElement
- 参数可以表示一个复杂对象,该对象本身具有可以配置的参数。这也支持注入元素数组。
- PluginConfiguration
- 当前
Configuration
对象将作为参数传递给插件。 - PluginNode
- 将把正在解析的当前
Node
作为参数传递给插件。 - PluginValue
- 当前
Node
的值或其名为value
的属性。
约束验证器
插件工厂字段和参数可以在运行时使用受 Bean Validation 规范 启发的约束验证器自动验证。Log4j 中捆绑了以下注释,但也可以创建自定义 ConstraintValidators。
- Required
- 此注释验证值是否非空。这涵盖了对
null
的检查以及其他几种情况:空CharSequence
对象、空数组、空Collection
实例和空Map
实例。 - ValidHost
- 此注释验证值是否对应于有效的主机名。这使用与 InetAddress::getByName 相同的验证。
- ValidPort
- 此注释验证值是否对应于 0 到 65535 之间的有效端口号。
转换器
转换器由 PatternLayout 用于呈现由转换模式标识的元素。每个转换器都必须在 @Plugin
注释中指定其类别为“Converter”,具有一个静态 newInstance
方法,该方法接受一个 String
数组作为其唯一参数并返回一个 Converter 实例,并且必须具有一个包含将导致选择 Converter 的转换器模式数组的 @ConverterKeys
注释。旨在处理 LogEvent
的转换器必须扩展 LogEventPatternConverter 类,并且必须实现一个接受 LogEvent
和 StringBuilder
作为参数的格式方法。Converter 应将操作结果追加到 StringBuilder
。
第二种类型的转换器是 FileConverter - 它必须在 @Plugin
注解的 category 属性中指定 "FileConverter"。虽然与 LogEventPatternConverter
类似,但这些转换器没有单个格式方法,而是有两个变体;一个接受 Object
,另一个接受 Object
数组,而不是 LogEvent
。两者都以与 LogEventPatternConverter
相同的方式追加到提供的 StringBuilder
。这些转换器通常由 RollingFileAppender
用于构建要记录到的文件的名称。
如果多个转换器指定相同的 ConverterKeys
,则上面的加载顺序决定了将使用哪一个。例如,要覆盖由内置 DatePatternConverter
类提供的 %date
转换器,您需要将您的插件放在 CLASSPATH 中的 JAR 文件中,该文件位于 log4j-core.jar
之前。不建议这样做;模式 ConverterKeys 冲突会导致发出警告。尝试为您的自定义模式转换器使用唯一的 ConverterKeys。
密钥提供者
Log4j 中的一些组件可能提供执行数据加密的功能。这些组件需要一个密钥来执行加密。应用程序可以通过创建一个实现 SecretKeyProvider 接口的类来提供密钥。
查找
查找可能是最简单的插件。它们必须在插件注解中声明其类型为 "Lookup",并且必须实现 StrLookup 接口。它们将有两个方法;一个查找方法,它接受一个字符串键并返回一个字符串值,以及第二个查找方法,它接受一个 LogEvent 和一个字符串键并返回一个字符串。查找可以通过指定 ${name:key} 来引用,其中 name 是在 Plugin 注解中指定的名称,key 是要查找的项目的名称。
类型转换器
TypeConverter 是一种元插件,用于将字符串转换为插件工厂方法参数中的其他类型。其他插件可以通过 @PluginElement
注解注入;现在,类型转换系统支持的任何类型都可以在 @PluginAttribute
参数中使用。枚举类型的转换按需支持,不需要自定义 TypeConverter
类。大量内置的 Java 类已经支持;有关更详尽的列表,请参阅 TypeConverters。
与其他插件不同,TypeConverter
的插件名称纯粹是装饰性的。合适的类型转换器是通过 Type
接口而不是通过 Class<?>
对象查找的。请注意,TypeConverter
插件必须具有默认构造函数。当多个转换器匹配一个类型时,将返回第一个。如果任何扩展自 Comparable<TypeConverter<?>>
,它将用于确定顺序。
开发者说明
如果插件类实现了 Collection 或 Map,则不使用工厂方法。相反,该类使用默认构造函数实例化,所有子配置节点都添加到 Collection
或 Map
中。