Description
Description
I'm trying to plug in a new RecyclerFactoryConverter
following https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#extending-recycler. The factory is using a pool to cache the objects, hence it is using a new spec string like pool
or pool:capacity=123
, which is unknown to the default RecyclerFactories
class called by RecyclerFactoryConverter
.
The class gets loaded properly, the log contains:
WARN Ignoring TypeConverter [org.apache.logging.log4j.layout.template.json.util.RecyclerFactoryConverter@21ca139c] for type [interface org.apache.logging.log4j.layout.template.json.util.RecyclerFactory] that conflicts with [com.XXX.messaging.log4j.ExtRecycleFactoryConverter@226f885f], since they are not comparable.
To configure the converter I use
-Dlog4j.layout.jsonTemplate.recyclerFactory=pool
However, when initializing log4j2, it fails with
2025-01-14T14:47:01.370078759Z main ERROR Could not create plugin of type class org.apache.logging.log4j.layout.template.json.JsonTemplateLayout for element JsonTemplateLayout: java.lang.IllegalArgumentException: invalid recycler factory: pool java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.createBuilder(PluginBuilder.java:167)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:121)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1164)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1085)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1077)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:681)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:264)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:313)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:631)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:713)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:735)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:260)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:154)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:46)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:197)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:136)
at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:58)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:46)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:32)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:432)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:457)
at com.XXX.messaging.startup.Messaging$Starter.<clinit>(Messaging.java:111)
at com.XXX.messaging.startup.Messaging.main(Messaging.java:56)
Caused by: java.lang.IllegalArgumentException: invalid recycler factory: pool
at org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.ofSpec(RecyclerFactories.java:84)
at org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults.getRecyclerFactory(JsonTemplateLayoutDefaults.java:118)
at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$Builder.<init>(JsonTemplateLayout.java:361)
at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$Builder.<init>(JsonTemplateLayout.java:316)
at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.newBuilder(JsonTemplateLayout.java:312)
... 28 more
i.e. it's not using the replacement at all, potentially due to the hardcoded reference in
Replacing it with
public static RecyclerFactory getRecyclerFactory()
{
final String recyclerFactorySpec = PROPERTIES.getStringProperty("log4j.layout.jsonTemplate.recyclerFactory");
return TypeConverters.convert(recyclerFactorySpec, RecyclerFactory.class, null);
}
helps, but I'm not sure if this is correct.
Configuration
Version: 2.23.1
Operating system: Ubuntu 24.04
JDK: OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7)
Logs
See above.
Reproduction
Due to customized build systems here a bit complicated. In general it should be sufficient to
- create something like
ExampleRecyclerFactory
(from https://logging.apache.org/log4j/2.x/manual/json-template-layout.html#extending-recycler) and returnThreadLocalRecyclerFactory.INSTANCE
just to return something working - make sure the plugin can be found (
annotationProcessor("org.apache.logging.log4j", "log4j-core")
in gradle) - configure log4j to use
JsonTemplateLayout
- set
-Dlog4j.layout.jsonTemplate.recyclerFactory=pool
system property to let the defaultRecyclerFactories
class fail if it gets called despite of the configuration