插件
介绍
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 中。


