diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
index 5d1e63ccdb8..ca88c35d038 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/PropertyConfigurator.java
@@ -47,6 +47,7 @@
import org.apache.log4j.spi.RendererSupport;
import org.apache.log4j.spi.ThrowableRenderer;
import org.apache.log4j.spi.ThrowableRendererSupport;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
import org.apache.logging.log4j.util.StackLocatorUtil;
@@ -307,7 +308,7 @@ public void doConfigure(final Properties properties, final LoggerRepository logg
Configuration doConfigure(
final Properties properties, final LoggerRepository loggerRepository, final ClassLoader classLoader) {
final PropertiesConfiguration configuration =
- new PropertiesConfiguration(LogManager.getContext(classLoader), properties);
+ new PropertiesConfiguration((LoggerContext) LogManager.getContext(classLoader), properties);
configuration.doConfigure();
repository = loggerRepository;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
index 26edfbc33d8..2eec639e843 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
@@ -16,6 +16,7 @@
*/
package org.apache.log4j.config;
+import java.util.Optional;
import org.apache.log4j.Level;
import org.apache.log4j.builders.BuilderManager;
import org.apache.logging.log4j.core.LoggerContext;
@@ -23,6 +24,9 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.util.PropertiesUtil;
/**
* Base Configuration for Log4j 1.
@@ -49,7 +53,15 @@ public Log4j1Configuration(
final LoggerContext loggerContext,
final ConfigurationSource configurationSource,
final int monitorIntervalSeconds) {
- super(loggerContext, configurationSource);
+ super(
+ loggerContext,
+ configurationSource,
+ Optional.ofNullable(loggerContext)
+ .map(LoggerContext::getEnvironment)
+ .orElseGet(PropertiesUtil::getProperties),
+ Optional.ofNullable(loggerContext)
+ .map(ctx -> (ConfigurableInstanceFactory) ctx.getInstanceFactory())
+ .orElseGet(DI::createInitializedFactory));
initializeWatchers(this, configurationSource, monitorIntervalSeconds);
manager = instanceFactory.getInstance(BuilderManager.class);
}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index 5ee7bc06fa1..3bc29f95870 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -81,12 +81,14 @@ public class PropertiesConfiguration extends Log4j1Configuration {
* Constructs a new instance.
*
* @param loggerContext The LoggerContext.
- * @param source The ConfigurationSource.
+ * @param configurationSource The ConfigurationSource.
* @param monitorIntervalSeconds The monitoring interval in seconds.
*/
public PropertiesConfiguration(
- final LoggerContext loggerContext, final ConfigurationSource source, final int monitorIntervalSeconds) {
- super(loggerContext, source, monitorIntervalSeconds);
+ final LoggerContext loggerContext,
+ final ConfigurationSource configurationSource,
+ final int monitorIntervalSeconds) {
+ this(loggerContext, configurationSource, monitorIntervalSeconds, null);
}
/**
@@ -96,18 +98,16 @@ public PropertiesConfiguration(
* @param properties The ConfigurationSource, may be null.
*/
public PropertiesConfiguration(final LoggerContext loggerContext, final Properties properties) {
- super(loggerContext, ConfigurationSource.NULL_SOURCE, 0);
- this.properties = properties;
+ this(loggerContext, ConfigurationSource.NULL_SOURCE, 0, properties);
}
- /**
- * Constructs a new instance.
- *
- * @param loggerContext The LoggerContext.
- * @param properties The ConfigurationSource.
- */
- public PropertiesConfiguration(org.apache.logging.log4j.spi.LoggerContext loggerContext, Properties properties) {
- this((LoggerContext) loggerContext, properties);
+ private PropertiesConfiguration(
+ final LoggerContext loggerContext,
+ final ConfigurationSource configurationSource,
+ final int monitorIntervalSeconds,
+ final Properties properties) {
+ super(loggerContext, configurationSource, monitorIntervalSeconds);
+ this.properties = properties;
}
@Override
@@ -149,7 +149,7 @@ public Configuration reconfigure() {
/**
* Reads a configuration from a file. The existing configuration is not cleared nor reset. If you require a
- * different behavior, then call {@link LogManager#resetConfiguration resetConfiguration} method before calling
+ * different behavior, then call {@link LogManager#resetConfiguration()} resetConfiguration} method before calling
* doConfigure.
*
* The configuration file consists of statements in the format key=value. The syntax of different
@@ -373,7 +373,7 @@ private void parseLoggers(final Properties props) {
LoggerConfig loggerConfig = getLogger(loggerName);
if (loggerConfig == null) {
final boolean additivity = getAdditivityForLogger(props, loggerName);
- loggerConfig = new LoggerConfig(loggerName, org.apache.logging.log4j.Level.ERROR, additivity);
+ loggerConfig = new LoggerConfig(loggerName, Level.ERROR, additivity, this);
addLogger(loggerName, loggerConfig);
}
parseLogger(props, loggerConfig, key, loggerName, value);
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
index 8f3949b173a..7ca6314c66d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
@@ -61,17 +61,17 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final C
}
@Override
- protected String getTestPrefix() {
+ public String getTestPrefix() {
return TEST_PREFIX;
}
@Override
- protected String getDefaultPrefix() {
+ public String getDefaultPrefix() {
return DEFAULT_PREFIX;
}
@Override
- protected String getVersion() {
+ public String getVersion() {
return LOG4J1_VERSION;
}
}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index daa0903ba03..efe481e4d6f 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -112,8 +112,10 @@ public class XmlConfiguration extends Log4j1Configuration {
private final Properties props = null;
public XmlConfiguration(
- final LoggerContext loggerContext, final ConfigurationSource source, final int monitorIntervalSeconds) {
- super(loggerContext, source, monitorIntervalSeconds);
+ final LoggerContext loggerContext,
+ final ConfigurationSource configurationSource,
+ final int monitorIntervalSeconds) {
+ super(loggerContext, configurationSource, monitorIntervalSeconds);
appenderMap = new HashMap<>();
}
@@ -563,7 +565,7 @@ private void parseCategory(final Element loggerElement) {
final boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
LoggerConfig loggerConfig = getLogger(catName);
if (loggerConfig == null) {
- loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
+ loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity, this);
addLogger(catName, loggerConfig);
} else {
loggerConfig.setAdditive(additivity);
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
index d7822928d7c..78d1cae4639 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
@@ -62,17 +62,17 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final C
}
@Override
- protected String getTestPrefix() {
+ public String getTestPrefix() {
return TEST_PREFIX;
}
@Override
- protected String getDefaultPrefix() {
+ public String getDefaultPrefix() {
return DEFAULT_PREFIX;
}
@Override
- protected String getVersion() {
+ public String getVersion() {
return LOG4J1_VERSION;
}
}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java b/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
index 16b14d84ee2..fbf5ba1d5fb 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
@@ -31,7 +31,7 @@
public class BasicConfigurationFactory extends ConfigurationFactory {
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return new String[] {"*"};
}
diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java
index 8795d5bb174..7737023bda0 100644
--- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java
+++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java
@@ -147,7 +147,10 @@ public void handleException(final ExtensionContext context, final Throwable thro
logger.atLevel(data.getLevel())
.withThrowable(data.getThrowable())
.withLocation(data.getStackTraceElement())
- .log("{} {}", formatter.format(Instant.ofEpochMilli(data.getTimestamp())), data.getMessage());
+ .log(
+ "{} {}",
+ formatter.format(Instant.ofEpochMilli(data.getTimestamp())),
+ data.getMessage().getFormattedMessage());
});
}
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
index aa16353407c..4f98d99c9f4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -23,8 +23,11 @@
import org.apache.logging.log4j.spi.LoggerContext;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.spi.LoggingSystem;
+import org.apache.logging.log4j.spi.LoggingSystemProperty;
import org.apache.logging.log4j.spi.Terminable;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.Strings;
@@ -55,6 +58,28 @@ public class LogManager {
// for convenience
private static final String FQCN = LogManager.class.getName();
+ private static volatile LoggerContextFactory factory;
+
+ /*
+ * Scans the classpath to find all logging implementation. Currently, only one will be used but this could be
+ * extended to allow multiple implementations to be used.
+ */
+ static {
+ // Shortcut binding to force a specific logging implementation.
+ final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+ final String factoryClassName =
+ managerProps.getStringProperty(LoggingSystemProperty.LOGGER_CONTEXT_FACTORY_CLASS);
+ if (factoryClassName != null) {
+ try {
+ factory = LoaderUtil.newCheckedInstanceOf(factoryClassName, LoggerContextFactory.class);
+ } catch (final ClassNotFoundException cnfe) {
+ LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
+ } catch (final Exception ex) {
+ LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
+ }
+ }
+ }
+
/**
* Prevents instantiation
*/
@@ -387,7 +412,7 @@ public static void shutdown(final LoggerContext context) {
* @return The LoggerContextFactory.
*/
public static LoggerContextFactory getFactory() {
- return LoggingSystem.getLoggerContextFactory();
+ return factory != null ? factory : LoggingSystem.getProvider().getLoggerContextFactory();
}
/**
@@ -405,7 +430,7 @@ public static LoggerContextFactory getFactory() {
* @see LoggingSystem
*/
public static void setFactory(final LoggerContextFactory factory) {
- LoggingSystem.getInstance().setLoggerContextFactory(factory);
+ LogManager.factory = factory;
}
/**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index 8a5a6a6b183..61a4750ded6 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -42,7 +42,7 @@
*
* @see Thread Context Manual
*/
-public final class ThreadContext {
+public class ThreadContext {
/**
* An empty read-only ThreadContextStack.
@@ -165,17 +165,15 @@ public ContextStack getImmutableStackOrNull() {
init();
}
- private ThreadContext() {
- // empty
- }
+ protected ThreadContext() {}
/**
* Consider private, used for testing.
*/
@InternalApi
public static void init() {
- contextMap = LoggingSystem.createContextMap();
- contextStack = LoggingSystem.createContextStack();
+ contextMap = LoggingSystem.getProvider().getThreadContextMapFactory();
+ contextStack = LoggingSystem.getProvider().getThreadContextStack();
if (contextMap instanceof ReadOnlyThreadContextMap) {
readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
} else {
@@ -496,6 +494,13 @@ public static void trim(final int depth) {
contextStack.trim(depth);
}
+ /**
+ * @return The underlying context map implementation.
+ */
+ protected static ThreadContextMap getContextMap() {
+ return contextMap;
+ }
+
/**
* The ThreadContext Stack interface.
*/
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
index 01cd966c084..34e57212ce6 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
@@ -55,7 +55,7 @@ default String getName() {
* @return the PropertyEnvironment.
* @since 3.0
*/
- default PropertyEnvironment getProperties() {
+ default PropertyEnvironment getEnvironment() {
return PropertiesUtil.getContextProperties(LoggerContext.class.getClassLoader(), getName());
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
index 02ad1242e77..33e4af2ec4d 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
@@ -18,12 +18,6 @@
import static org.apache.logging.log4j.spi.LoggingSystemProperty.LOGGER_FLOW_MESSAGE_FACTORY_CLASS;
import static org.apache.logging.log4j.spi.LoggingSystemProperty.LOGGER_MESSAGE_FACTORY_CLASS;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_ENABLE;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_GARBAGE_FREE_ENABLED;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_INITIAL_CAPACITY;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_MAP_CLASS;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_MAP_INHERITABLE;
-import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_STACK_ENABLED;
import aQute.bnd.annotation.spi.ServiceConsumer;
import java.io.IOException;
@@ -76,10 +70,8 @@ public class LoggingSystem {
private static final Lazy SYSTEM = Lazy.relaxed(LoggingSystem::new);
- private final Lazy providerLazy = Lazy.relaxed(this::findProvider);
+ private final Lazy providerLazy = Lazy.relaxed(this::findProvider);
private final Lazy environmentLazy = Lazy.relaxed(PropertiesUtil::getProperties);
- private final Lazy loggerContextFactoryLazy =
- environmentLazy.map(environment -> getProvider().createLoggerContextFactory(environment));
private final Lazy messageFactoryLazy = environmentLazy.map(environment -> {
final String className = environment.getStringProperty(LOGGER_MESSAGE_FACTORY_CLASS);
if (className != null) {
@@ -101,24 +93,22 @@ public class LoggingSystem {
return new DefaultFlowMessageFactory();
});
private final Lazy> threadContextMapFactoryLazy =
- environmentLazy.map(environment -> () -> getProvider().createContextMap(environment));
- private final Lazy> threadContextStackFactoryLazy =
- environmentLazy.map(environment -> () -> getProvider().createContextStack(environment));
+ environmentLazy.map(environment -> () -> getProvider().getThreadContextMapFactory());
private final Lazy recyclerFactoryLazy =
environmentLazy.map(RecyclerFactoryRegistry::findRecyclerFactory);
public LoggingSystem() {}
- private SystemProvider getProvider() {
- return providerLazy.get();
+ public static Provider getProvider() {
+ return getInstance().providerLazy.get();
}
- private SystemProvider findProvider() {
+ private Provider findProvider() {
final SortedMap providers = new TreeMap<>();
loadDefaultProviders().forEach(p -> providers.put(p.getPriority(), p));
loadLegacyProviders().forEach(p -> providers.put(p.getPriority(), p));
if (providers.isEmpty()) {
- return new SystemProvider();
+ return new SimpleProvider();
}
final Provider provider = providers.get(providers.lastKey());
if (providers.size() > 1) {
@@ -127,29 +117,17 @@ private SystemProvider findProvider() {
sb.append("Using ").append(provider);
LowLevelLogUtil.log(sb.toString());
}
- return new SystemProvider(provider);
- }
-
- public void setLoggerContextFactory(final LoggerContextFactory loggerContextFactory) {
- loggerContextFactoryLazy.set(loggerContextFactory);
+ return provider;
}
public void setMessageFactory(final MessageFactory messageFactory) {
messageFactoryLazy.set(messageFactory);
}
- public void setFlowMessageFactory(final FlowMessageFactory flowMessageFactory) {
- flowMessageFactoryLazy.set(flowMessageFactory);
- }
-
public void setThreadContextMapFactory(final Supplier threadContextMapFactory) {
threadContextMapFactoryLazy.set(threadContextMapFactory);
}
- public void setThreadContextStackFactory(final Supplier threadContextStackFactory) {
- threadContextStackFactoryLazy.set(threadContextStackFactory);
- }
-
public void setRecyclerFactory(final RecyclerFactory factory) {
recyclerFactoryLazy.set(factory);
}
@@ -161,14 +139,6 @@ public static LoggingSystem getInstance() {
return SYSTEM.get();
}
- /**
- * Gets the current LoggerContextFactory. This may initialize the instance if this is the first time it was
- * requested.
- */
- public static LoggerContextFactory getLoggerContextFactory() {
- return getInstance().loggerContextFactoryLazy.get();
- }
-
public static MessageFactory getMessageFactory() {
return getInstance().messageFactoryLazy.get();
}
@@ -177,22 +147,15 @@ public static FlowMessageFactory getFlowMessageFactory() {
return getInstance().flowMessageFactoryLazy.get();
}
- /**
- * Creates a new ThreadContextMap.
- */
- public static ThreadContextMap createContextMap() {
- return getInstance().threadContextMapFactoryLazy.get().get();
+ public static RecyclerFactory getRecyclerFactory() {
+ return getInstance().recyclerFactoryLazy.get();
}
/**
- * Creates a new ThreadContextStack.
+ * Temporarily for tests
*/
- public static ThreadContextStack createContextStack() {
- return getInstance().threadContextStackFactoryLazy.get().get();
- }
-
- public static RecyclerFactory getRecyclerFactory() {
- return getInstance().recyclerFactoryLazy.get();
+ public static void reset() {
+ getProvider().reset();
}
private static List loadDefaultProviders() {
@@ -231,7 +194,7 @@ private static boolean validVersion(final String version) {
return false;
}
- private static T tryInstantiate(final Class clazz) {
+ static T tryInstantiate(final Class clazz) {
Constructor constructor;
try {
constructor = clazz.getConstructor();
@@ -259,7 +222,7 @@ private static T tryInstantiate(final Class clazz) {
return null;
}
- private static T createInstance(final String className, final Class type) {
+ static T createInstance(final String className, final Class type) {
try {
final Class> loadedClass = LoaderUtil.loadClass(className);
final Class extends T> typedClass = loadedClass.asSubclass(type);
@@ -271,98 +234,9 @@ private static T createInstance(final String className, final Class type)
}
}
- private static final class SystemProvider {
- private final Provider provider;
-
- private SystemProvider() {
- this(null);
- }
-
- private SystemProvider(final Provider provider) {
- this.provider = provider;
- }
-
- public LoggerContextFactory createLoggerContextFactory(final PropertyEnvironment environment) {
- final String customFactoryClass =
- environment.getStringProperty(LoggingSystemProperty.LOGGER_CONTEXT_FACTORY_CLASS);
- if (customFactoryClass != null) {
- final LoggerContextFactory customFactory =
- createInstance(customFactoryClass, LoggerContextFactory.class);
- if (customFactory != null) {
- return customFactory;
- }
- }
- if (provider != null) {
- final Class extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
- if (factoryClass != null) {
- final LoggerContextFactory factory = tryInstantiate(factoryClass);
- if (factory != null) {
- return factory;
- }
- }
- }
- LowLevelLogUtil.log("Log4j could not find a logging implementation. "
- + "Please add log4j-core dependencies to classpath or module path. "
- + "Using SimpleLogger to log to the console.");
- return SimpleLoggerContextFactory.INSTANCE;
- }
-
- /**
- * Creates the ThreadContextMap instance used by the ThreadContext.
- *
- * A garbage-free StringMap-based context map can
- * be installed by setting system property {@link LoggingSystemProperty#THREAD_CONTEXT_GARBAGE_FREE_ENABLED} to {@code true}.
- *
- * Furthermore, any custom {@code ThreadContextMap} can be installed by setting system property
- * {@link LoggingSystemProperty#THREAD_CONTEXT_MAP_CLASS} to the fully qualified class name of the class implementing the
- * {@code ThreadContextMap} interface. (Also implement the {@code ReadOnlyThreadContextMap} interface if your custom
- * {@code ThreadContextMap} implementation should be accessible to applications via the
- * {@link ThreadContext#getThreadContextMap()} method.)
- *
- * Instead of system properties, the above can also be specified in a properties file named
- * {@code log4j2.component.properties} in the classpath.
- *
- *
- * @see ThreadContextMap
- * @see ReadOnlyThreadContextMap
- * @see org.apache.logging.log4j.ThreadContext
- */
- public ThreadContextMap createContextMap(final PropertyEnvironment environment) {
- final String customThreadContextMap = environment.getStringProperty(THREAD_CONTEXT_MAP_CLASS);
- if (customThreadContextMap != null) {
- final ThreadContextMap customContextMap =
- createInstance(customThreadContextMap, ThreadContextMap.class);
- if (customContextMap != null) {
- return customContextMap;
- }
- }
- final boolean enableMap = environment.getBooleanProperty(
- LoggingSystemProperty.THREAD_CONTEXT_MAP_ENABLED,
- environment.getBooleanProperty(LoggingSystemProperty.THREAD_CONTEXT_ENABLE, true));
- if (!enableMap) {
- return new NoOpThreadContextMap();
- }
- final Class extends ThreadContextMap> mapClass = provider.loadThreadContextMap();
- if (mapClass != null) {
- final ThreadContextMap map = tryInstantiate(mapClass);
- if (map != null) {
- return map;
- }
- }
- final boolean garbageFreeEnabled = environment.getBooleanProperty(THREAD_CONTEXT_GARBAGE_FREE_ENABLED);
- final boolean inheritableMap = environment.getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE);
- final int initialCapacity = environment.getIntegerProperty(
- THREAD_CONTEXT_INITIAL_CAPACITY, THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY);
- if (garbageFreeEnabled) {
- return new GarbageFreeSortedArrayThreadContextMap(inheritableMap, initialCapacity);
- }
- return new CopyOnWriteSortedArrayThreadContextMap(inheritableMap, initialCapacity);
- }
-
- public ThreadContextStack createContextStack(final PropertyEnvironment environment) {
- final boolean enableStack = environment.getBooleanProperty(
- THREAD_CONTEXT_STACK_ENABLED, environment.getBooleanProperty(THREAD_CONTEXT_ENABLE, true));
- return new DefaultThreadContextStack(enableStack);
+ private static class SimpleProvider extends Provider {
+ public SimpleProvider() {
+ super(0, "3.0.0", SimpleLoggerContextFactory.class, NoOpThreadContextMap.class);
}
}
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
index 94c4b2c82f8..451d7811d2e 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java
@@ -16,12 +16,25 @@
*/
package org.apache.logging.log4j.spi;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_ENABLE;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_GARBAGE_FREE_ENABLED;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_INITIAL_CAPACITY;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_MAP_CLASS;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_MAP_INHERITABLE;
+import static org.apache.logging.log4j.spi.LoggingSystemProperty.THREAD_CONTEXT_STACK_ENABLED;
+
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.Objects;
import java.util.Properties;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Lazy;
+import org.apache.logging.log4j.util.LowLevelLogUtil;
+import org.apache.logging.log4j.util.PropertiesUtil;
/**
* Model class for a Log4j 2 provider. The properties in this class correspond to the properties used in a
@@ -42,6 +55,8 @@ public class Provider {
*/
public static final String LOGGER_CONTEXT_FACTORY = "LoggerContextFactory";
+ public static final int THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY = 16;
+
private static final Integer DEFAULT_PRIORITY = -1;
private static final Logger LOGGER = StatusLogger.getLogger();
@@ -54,6 +69,12 @@ public class Provider {
private final URL url;
private final WeakReference classLoader;
+ // Temporary fields until we revert to Log4j API 2.x
+ private final Lazy loggerContextFactory = Lazy.lazy(this::createLoggerContextFactory);
+ private final Lazy threadContextMapFactory = Lazy.lazy(this::createThreadContextMap);
+ private final Lazy threadContextStack = Lazy.lazy(this::createThreadContextStack);
+ private final Lock lock = new ReentrantLock();
+
public Provider(final Properties props, final URL url, final ClassLoader classLoader) {
this.url = url;
this.classLoader = new WeakReference<>(classLoader);
@@ -193,6 +214,91 @@ public URL getUrl() {
return url;
}
+ public LoggerContextFactory getLoggerContextFactory() {
+ return loggerContextFactory.get();
+ }
+
+ protected LoggerContextFactory createLoggerContextFactory() {
+ final String customFactoryClass =
+ PropertiesUtil.getProperties().getStringProperty(LoggingSystemProperty.LOGGER_CONTEXT_FACTORY_CLASS);
+ if (customFactoryClass != null) {
+ final LoggerContextFactory customFactory =
+ LoggingSystem.createInstance(customFactoryClass, LoggerContextFactory.class);
+ if (customFactory != null) {
+ return customFactory;
+ }
+ }
+ final Class extends LoggerContextFactory> factoryClass = loadLoggerContextFactory();
+ if (factoryClass != null) {
+ final LoggerContextFactory factory = LoggingSystem.tryInstantiate(factoryClass);
+ if (factory != null) {
+ return factory;
+ }
+ }
+ LowLevelLogUtil.log("Log4j could not find a logging implementation. "
+ + "Please add log4j-core dependencies to classpath or module path. "
+ + "Using SimpleLogger to log to the console.");
+ return SimpleLoggerContextFactory.INSTANCE;
+ }
+
+ public ThreadContextMap getThreadContextMapFactory() {
+ return threadContextMapFactory.get();
+ }
+
+ protected ThreadContextMap createThreadContextMap() {
+ final PropertiesUtil environment = PropertiesUtil.getProperties();
+ final String customThreadContextMap = environment.getStringProperty(THREAD_CONTEXT_MAP_CLASS);
+ if (customThreadContextMap != null) {
+ final ThreadContextMap customContextMap =
+ LoggingSystem.createInstance(customThreadContextMap, ThreadContextMap.class);
+ if (customContextMap != null) {
+ return customContextMap;
+ }
+ }
+ final boolean enableMap = environment.getBooleanProperty(
+ LoggingSystemProperty.THREAD_CONTEXT_MAP_ENABLED,
+ environment.getBooleanProperty(LoggingSystemProperty.THREAD_CONTEXT_ENABLE, true));
+ if (!enableMap) {
+ return new NoOpThreadContextMap();
+ }
+ final Class extends ThreadContextMap> mapClass = loadThreadContextMap();
+ if (mapClass != null) {
+ final ThreadContextMap map = LoggingSystem.tryInstantiate(mapClass);
+ if (map != null) {
+ return map;
+ }
+ }
+ final boolean garbageFreeEnabled = environment.getBooleanProperty(THREAD_CONTEXT_GARBAGE_FREE_ENABLED);
+ final boolean inheritableMap = environment.getBooleanProperty(THREAD_CONTEXT_MAP_INHERITABLE);
+ final int initialCapacity = environment.getIntegerProperty(
+ THREAD_CONTEXT_INITIAL_CAPACITY, THREAD_CONTEXT_DEFAULT_INITIAL_CAPACITY);
+ if (garbageFreeEnabled) {
+ return new GarbageFreeSortedArrayThreadContextMap(inheritableMap, initialCapacity);
+ }
+ return new CopyOnWriteSortedArrayThreadContextMap(inheritableMap, initialCapacity);
+ }
+
+ public ThreadContextStack getThreadContextStack() {
+ return threadContextStack.get();
+ }
+
+ protected ThreadContextStack createThreadContextStack() {
+ final PropertiesUtil environment = PropertiesUtil.getProperties();
+ final boolean enableStack = environment.getBooleanProperty(
+ THREAD_CONTEXT_STACK_ENABLED, environment.getBooleanProperty(THREAD_CONTEXT_ENABLE, true));
+ return new DefaultThreadContextStack(enableStack);
+ }
+
+ public synchronized void setThreadContextMapFactory(final ThreadContextMap threadContextMapFactory) {
+ this.threadContextMapFactory.set(threadContextMapFactory);
+ }
+
+ void reset() {
+ loggerContextFactory.set(null);
+ threadContextMapFactory.set(null);
+ threadContextStack.set(null);
+ }
+
@Override
public String toString() {
final StringBuilder result = new StringBuilder("Provider[");
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLogger.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLogger.java
index 7143a5b7b76..80578ee369a 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLogger.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLogger.java
@@ -37,6 +37,8 @@
import org.apache.logging.log4j.message.FlowMessageFactory;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.spi.recycler.Recycler;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.util.StringMap;
@@ -281,4 +283,33 @@ private static StringMap getContextData(final ReusableLogEvent event) {
AsyncLoggerDisruptor getAsyncLoggerDisruptor() {
return loggerDisruptor;
}
+
+ public static class Builder extends Logger.Builder {
+
+ private final AsyncLoggerDisruptor disruptor;
+
+ @Inject
+ public Builder(
+ final LoggerContext context,
+ final MessageFactory messageFactory,
+ final FlowMessageFactory flowMessageFactory,
+ final RecyclerFactory recyclerFactory,
+ final @Named("StatusLogger") org.apache.logging.log4j.Logger statusLogger,
+ final AsyncLoggerDisruptor disruptor) {
+ super(context, messageFactory, flowMessageFactory, recyclerFactory, statusLogger);
+ this.disruptor = disruptor;
+ }
+
+ @Override
+ public Logger build() {
+ return new AsyncLogger(
+ getContext(),
+ getName(),
+ getActualMessageFactory(),
+ getFlowMessageFactory(),
+ getRecyclerFactory(),
+ getStatusLogger(),
+ disruptor);
+ }
+ }
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfig.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfig.java
index b8591342bb6..690a67e5933 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfig.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfig.java
@@ -29,7 +29,6 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.kit.logger.AbstractLogger;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
@@ -65,10 +64,10 @@
*/
@Configurable(printObject = true)
@Plugin("asyncLogger")
-public class AsyncLoggerConfig extends LoggerConfig {
+public final class AsyncLoggerConfig extends LoggerConfig {
private static final ThreadLocal ASYNC_LOGGER_ENTERED = ThreadLocal.withInitial(() -> Boolean.FALSE);
- private AsyncLoggerConfigDelegate delegate;
+ private AsyncLoggerConfigDisruptor disruptor;
@PluginFactory
public static > B newAsyncBuilder() {
@@ -80,9 +79,10 @@ public static class Builder> extends LoggerConfig.Builder appenders,
final Filter filter,
@@ -104,22 +103,23 @@ protected AsyncLoggerConfig(
final boolean additive,
final Property[] properties,
final Configuration config,
- final boolean includeLocation,
- final LogEventFactory logEventFactory) {
- super(name, appenders, filter, level, additive, properties, config, includeLocation, logEventFactory);
+ final boolean includeLocation) {
+ super(name, appenders, filter, level, additive, properties, config, includeLocation);
}
@Override
public void initialize() {
final Configuration configuration = getConfiguration();
- final DisruptorConfiguration disruptorConfig = configuration.addExtensionIfAbsent(
- DisruptorConfiguration.class,
- () -> DisruptorConfiguration.newBuilder().build());
- delegate = disruptorConfig.getAsyncLoggerConfigDelegate();
- delegate.setLogEventFactory(getLogEventFactory());
+ // Retrieve or create the common holder for the disruptor.
+ final DisruptorConfiguration disruptorConfiguration = configuration.addExtensionIfAbsent(
+ DisruptorConfiguration.class, () -> DisruptorConfiguration.newBuilder()
+ .setConfiguration(configuration)
+ .build());
+ this.disruptor = disruptorConfiguration.getLoggerConfigDisruptor();
super.initialize();
}
+ @Override
protected void log(final LogEvent event, final Predicate predicate) {
// See LOG4J2-2301
if (predicate == null
@@ -153,8 +153,8 @@ protected void log(final LogEvent event, final Predicate predicate
}
// package-protected for testing
- AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() {
- return delegate;
+ AsyncLoggerConfigDisruptor getAsyncLoggerConfigDisruptor() {
+ return disruptor;
}
@Override
@@ -165,7 +165,7 @@ protected void callAppenders(final LogEvent event) {
private void logToAsyncDelegate(final LogEvent event) {
// Passes on the event to a separate thread that will call
// asyncCallAppenders(LogEvent).
- if (!delegate.tryEnqueue(event, this)) {
+ if (!disruptor.tryEnqueue(event, this)) {
handleQueueFull(event);
}
}
@@ -177,7 +177,7 @@ private void handleQueueFull(final LogEvent event) {
logToAsyncLoggerConfigsOnCurrentThread(event);
} else {
// otherwise, we leave it to the user preference
- final EventRoute eventRoute = delegate.getEventRoute(event.getLevel());
+ final EventRoute eventRoute = disruptor.getEventRoute(event.getLevel());
switch (eventRoute) {
case DISCARD:
break;
@@ -193,14 +193,15 @@ private void handleQueueFull(final LogEvent event) {
}
void logInBackgroundThread(final LogEvent event) {
- delegate.enqueueEvent(event, this);
+ disruptor.enqueueEvent(event, this);
}
/**
* Called by AsyncLoggerConfigHelper.RingBufferLog4jEventHandler.
- *
+ *
* This method will log the provided event to only configs of type {@link AsyncLoggerConfig} (not
* default {@link LoggerConfig} definitions), which will be invoked on the calling thread.
+ *
*/
void logToAsyncLoggerConfigsOnCurrentThread(final LogEvent event) {
// skip the filter, which was already called on the logging thread
@@ -231,30 +232,33 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) {
*/
@Configurable(printObject = true)
@Plugin("asyncRoot")
- public static class RootLogger extends LoggerConfig {
+ public static final class RootLogger extends LoggerConfig {
@PluginFactory
- public static > B newAsyncRootBuilder() {
- return new Builder().asBuilder();
+ public static Builder newAsyncRootBuilder() {
+ return new Builder();
+ }
+
+ private RootLogger() {
+ super(Strings.EMPTY, Level.ERROR, false, null);
}
- public static class Builder> extends RootLogger.Builder {
+ public static class Builder extends RootLogger.Builder {
@Override
public LoggerConfig build() {
final LevelAndRefs container =
LoggerConfig.getLevelAndRefs(getLevel(), getRefs(), getLevelAndRefs(), getConfig());
- final String includeLocationConfigValue = getIncludeLocation();
+ final boolean includeLocation = Boolean.TRUE.equals(getIncludeLocation());
return new AsyncLoggerConfig(
LogManager.ROOT_LOGGER_NAME,
container.refs,
getFilter(),
container.level,
- isAdditivity(),
+ ADDITIVITY,
getProperties(),
getConfig(),
- Boolean.parseBoolean(includeLocationConfigValue),
- getLogEventFactory());
+ includeLocation);
}
}
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDelegate.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDelegate.java
index e3997404c42..f58ce5d2975 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDelegate.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDelegate.java
@@ -19,7 +19,6 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.async.EventRoute;
-import org.apache.logging.log4j.core.impl.LogEventFactory;
/**
* Encapsulates the mechanism used to log asynchronously. There is one delegate per configuration, which is shared by
@@ -43,13 +42,4 @@ public interface AsyncLoggerConfigDelegate {
void enqueueEvent(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
boolean tryEnqueue(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
-
- /**
- * Notifies the delegate what LogEventFactory an AsyncLoggerConfig is using, so the delegate can determine
- * whether to populate the ring buffer with mutable log events or not. This method may be invoked multiple times
- * for all AsyncLoggerConfigs that use this delegate.
- *
- * @param logEventFactory the factory used
- */
- void setLogEventFactory(LogEventFactory logEventFactory);
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDisruptor.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDisruptor.java
index a17aa977603..1faed03aaa4 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDisruptor.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigDisruptor.java
@@ -33,6 +33,7 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.async.logger.internal.DisruptorUtil;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.ReusableLogEvent;
@@ -49,6 +50,7 @@
import org.apache.logging.log4j.core.util.Log4jThreadFactory;
import org.apache.logging.log4j.core.util.Throwables;
import org.apache.logging.log4j.message.ReusableMessage;
+import org.apache.logging.log4j.plugins.Inject;
/**
* Helper class decoupling the {@code AsyncLoggerConfig} class from the LMAX Disruptor library.
@@ -62,7 +64,7 @@
* This class serves to make the dependency on the Disruptor optional, so that these classes are only loaded when the
* {@code AsyncLoggerConfig} is actually used.
*/
-public class AsyncLoggerConfigDisruptor extends AbstractLifeCycle implements AsyncLoggerConfigDelegate {
+public class AsyncLoggerConfigDisruptor extends AbstractLifeCycle {
private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200;
private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50;
@@ -166,20 +168,21 @@ private void notifyIntermediateProgress(final long sequence) {
};
private AsyncQueueFullPolicy asyncQueueFullPolicy;
- private Boolean mutable = Boolean.FALSE;
private volatile Disruptor disruptor;
private long backgroundThreadId; // LOG4J2-471
private EventTranslatorTwoArg translator;
private static volatile boolean alreadyLoggedWarning;
- private final AsyncWaitStrategyFactory asyncWaitStrategyFactory;
- private WaitStrategy waitStrategy;
+ private final WaitStrategy waitStrategy;
+ private final boolean mutable;
private final Lock startLock = new ReentrantLock();
private final Lock queueFullEnqueueLock = new ReentrantLock();
- public AsyncLoggerConfigDisruptor(final AsyncWaitStrategyFactory asyncWaitStrategyFactory) {
- this.asyncWaitStrategyFactory = asyncWaitStrategyFactory; // may be null
+ @Inject
+ public AsyncLoggerConfigDisruptor(final WaitStrategy waitStrategy, final LogEventFactory logEventFactory) {
+ this.waitStrategy = waitStrategy;
+ this.mutable = logEventFactory instanceof ReusableLogEventFactory;
}
// package-protected for testing
@@ -187,14 +190,6 @@ WaitStrategy getWaitStrategy() {
return waitStrategy;
}
- // called from AsyncLoggerConfig constructor
- @Override
- public void setLogEventFactory(final LogEventFactory logEventFactory) {
- // if any AsyncLoggerConfig uses a ReusableLogEventFactory
- // then we need to populate our ringbuffer with MutableLogEvents
- this.mutable = mutable || (logEventFactory instanceof ReusableLogEventFactory);
- }
-
/**
* Increases the reference count and creates and starts a new Disruptor and associated thread if none currently
* exists.
@@ -213,8 +208,6 @@ public void start() {
LOGGER.trace("AsyncLoggerConfigDisruptor creating new disruptor for this configuration.");
final int ringBufferSize =
DisruptorUtil.calculateRingBufferSize(Log4jPropertyKey.ASYNC_CONFIG_RING_BUFFER_SIZE);
- waitStrategy = DisruptorUtil.createWaitStrategy(
- Log4jPropertyKey.ASYNC_CONFIG_WAIT_STRATEGY, asyncWaitStrategyFactory);
final ThreadFactory threadFactory =
new Log4jThreadFactory("AsyncLoggerConfig", true, Thread.NORM_PRIORITY) {
@@ -304,7 +297,6 @@ private static boolean hasBacklog(final Disruptor> theDisruptor) {
return !ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize());
}
- @Override
public EventRoute getEventRoute(final Level logLevel) {
final int remainingCapacity = remainingDisruptorCapacity();
if (remainingCapacity < 0) {
@@ -332,7 +324,6 @@ private boolean hasLog4jBeenShutDown(final Disruptor aDisrupt
return false;
}
- @Override
public void enqueueEvent(final LogEvent event, final AsyncLoggerConfig asyncLoggerConfig) {
// LOG4J2-639: catch NPE if disruptor field was set to null after our check above
try {
@@ -416,7 +407,6 @@ private boolean synchronizeEnqueueWhenQueueFull() {
&& !(Thread.currentThread() instanceof Log4jThread);
}
- @Override
public boolean tryEnqueue(final LogEvent event, final AsyncLoggerConfig asyncLoggerConfig) {
return disruptor.getRingBuffer().tryPublishEvent(translator, event, asyncLoggerConfig);
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContext.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContext.java
index bc96643c349..772afe9c617 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContext.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContext.java
@@ -18,123 +18,74 @@
import java.net.URI;
import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.async.logger.internal.DefaultBundle;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.message.FlowMessageFactory;
-import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
+import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Lazy;
/**
* {@code LoggerContext} that creates {@code AsyncLogger} objects.
*/
public class AsyncLoggerContext extends LoggerContext {
- private final AsyncLoggerDisruptor loggerDisruptor;
-
- public AsyncLoggerContext(final String name) {
- super(name);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
-
- public AsyncLoggerContext(final String name, final Object externalContext) {
- super(name, externalContext);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
-
- public AsyncLoggerContext(final String name, final Object externalContext, final URI configLocn) {
- super(name, externalContext, configLocn);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
+ private final Lazy loggerDisruptor = Lazy.lazy(() ->
+ getInstanceFactory().getInstance(AsyncLoggerDisruptor.Factory.class).createAsyncLoggerDisruptor(getName()));
public AsyncLoggerContext(
final String name,
final Object externalContext,
- final URI configLocn,
+ final URI configLocation,
final ConfigurableInstanceFactory instanceFactory) {
- super(name, externalContext, configLocn, instanceFactory);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
-
- public AsyncLoggerContext(final String name, final Object externalContext, final String configLocn) {
- super(name, externalContext, configLocn);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
-
- public AsyncLoggerContext(
- final String name,
- final Object externalContext,
- final String configLocn,
- final ConfigurableInstanceFactory instanceFactory) {
- super(name, externalContext, configLocn, instanceFactory);
- loggerDisruptor = new AsyncLoggerDisruptor(name, this::createAsyncWaitStrategyFactory);
- }
-
- private AsyncWaitStrategyFactory createAsyncWaitStrategyFactory() {
- final DisruptorConfiguration disruptorConfiguration =
- getConfiguration().getExtension(DisruptorConfiguration.class);
- return disruptorConfiguration != null ? disruptorConfiguration.getWaitStrategyFactory() : null;
+ super(name, externalContext, configLocation, instanceFactory);
+ instanceFactory.registerBundle(DefaultBundle.class);
+ instanceFactory.registerBinding(Key.forClass(AsyncLoggerDisruptor.class), loggerDisruptor);
}
@Override
- protected Logger newInstance(
- final LoggerContext ctx,
- final String name,
- final MessageFactory messageFactory,
- final FlowMessageFactory flowMessageFactory,
- final RecyclerFactory recyclerFactory,
- final org.apache.logging.log4j.Logger statusLogger) {
- return new AsyncLogger(
- ctx, name, messageFactory, flowMessageFactory, recyclerFactory, statusLogger, loggerDisruptor);
+ protected Class extends Logger.Builder> getLoggerBuilderClass() {
+ return AsyncLogger.Builder.class;
}
@Override
public void setName(final String name) {
super.setName("AsyncContext[" + name + "]");
- loggerDisruptor.setContextName(name);
+ if (loggerDisruptor.isInitialized()) {
+ loggerDisruptor.get().setContextName(name);
+ }
}
- /*
- * (non-Javadoc)
- *
- * @see org.apache.logging.log4j.core.LoggerContext#start()
- */
@Override
public void start() {
- loggerDisruptor.start();
+ getAsyncLoggerDisruptor().start();
super.start();
}
- /*
- * (non-Javadoc)
- *
- * @see org.apache.logging.log4j.core.LoggerContext#start(org.apache.logging.log4j.core.config.Configuration)
- */
@Override
public void start(final Configuration config) {
- maybeStartHelper(config);
- super.start(config);
- }
-
- private void maybeStartHelper(final Configuration config) {
// If no log4j configuration was found, there are no loggers
// and there is no point in starting the disruptor (which takes up
// significant memory and starts a thread).
if (config instanceof DefaultConfiguration) {
StatusLogger.getLogger().debug("[{}] Not starting Disruptor for DefaultConfiguration.", getName());
} else {
- loggerDisruptor.start();
+ getAsyncLoggerDisruptor().start();
}
+ super.start(config);
}
@Override
public boolean stop(final long timeout, final TimeUnit timeUnit) {
setStopping();
// first stop Disruptor
- loggerDisruptor.stop(timeout, timeUnit);
+ if (loggerDisruptor.isInitialized()) {
+ loggerDisruptor.get().stop(timeout, timeUnit);
+ }
super.stop(timeout, timeUnit);
return true;
}
@@ -146,6 +97,19 @@ public boolean includeLocation() {
// package-protected for tests
AsyncLoggerDisruptor getAsyncLoggerDisruptor() {
- return loggerDisruptor;
+ return loggerDisruptor.get();
+ }
+
+ public static final class Builder extends LoggerContext.Builder {
+
+ @Inject
+ public Builder(final ConfigurableInstanceFactory parentInstanceFactory) {
+ super(parentInstanceFactory);
+ }
+
+ @Override
+ public LoggerContext build() {
+ return new AsyncLoggerContext(getContextName(), null, getConfigLocation(), createInstanceFactory());
+ }
}
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextSelector.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextSelector.java
index 31e5b9c4031..22a36e0b3fc 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextSelector.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextSelector.java
@@ -16,7 +16,6 @@
*/
package org.apache.logging.log4j.async.logger;
-import java.net.URI;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
import org.apache.logging.log4j.plugins.Inject;
@@ -37,9 +36,8 @@ public AsyncLoggerContextSelector(final ConfigurableInstanceFactory instanceFact
}
@Override
- protected LoggerContext createContext(
- final String name, final URI configLocation, final ConfigurableInstanceFactory instanceFactory) {
- return new AsyncLoggerContext(name, null, configLocation, instanceFactory);
+ protected LoggerContext.Builder newBuilder() {
+ return instanceFactory.getInstance(AsyncLoggerContext.Builder.class);
}
@Override
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerDisruptor.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerDisruptor.java
index b2280e62b7e..d634899c137 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerDisruptor.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncLoggerDisruptor.java
@@ -22,13 +22,12 @@
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
-import java.util.Objects;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Supplier;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.async.logger.internal.DisruptorUtil;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.async.AsyncQueueFullPolicy;
import org.apache.logging.log4j.core.async.AsyncQueueFullPolicyFactory;
@@ -46,7 +45,7 @@
* life cycle of the context. The AsyncLoggerDisruptor of the context is shared by all AsyncLogger objects created by
* that AsyncLoggerContext.
*/
-class AsyncLoggerDisruptor extends AbstractLifeCycle {
+public class AsyncLoggerDisruptor extends AbstractLifeCycle {
private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50;
private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200;
@@ -55,17 +54,14 @@ class AsyncLoggerDisruptor extends AbstractLifeCycle {
private volatile Disruptor disruptor;
private String contextName;
- private final Supplier waitStrategyFactorySupplier;
private long backgroundThreadId;
private AsyncQueueFullPolicy asyncQueueFullPolicy;
private WaitStrategy waitStrategy;
- AsyncLoggerDisruptor(
- final String contextName, final Supplier waitStrategyFactorySupplier) {
+ public AsyncLoggerDisruptor(final String contextName, final WaitStrategy waitStrategy) {
this.contextName = contextName;
- this.waitStrategyFactorySupplier =
- Objects.requireNonNull(waitStrategyFactorySupplier, "waitStrategyFactorySupplier");
+ this.waitStrategy = waitStrategy;
}
// package-protected for testing
@@ -104,9 +100,6 @@ public void start() {
LOGGER.trace("[{}] AsyncLoggerDisruptor creating new disruptor for this context.", contextName);
final int ringBufferSize =
DisruptorUtil.calculateRingBufferSize(Log4jPropertyKey.ASYNC_LOGGER_RING_BUFFER_SIZE);
- final AsyncWaitStrategyFactory factory =
- waitStrategyFactorySupplier.get(); // get factory from configuration
- waitStrategy = DisruptorUtil.createWaitStrategy(Log4jPropertyKey.ASYNC_LOGGER_WAIT_STRATEGY, factory);
final ThreadFactory threadFactory =
new Log4jThreadFactory("AsyncLogger[" + contextName + "]", true, Thread.NORM_PRIORITY) {
@@ -288,4 +281,9 @@ private void logWarningOnNpeFromDisruptorPublish(
RingBuffer getRingBuffer() {
return disruptor.getRingBuffer();
}
+
+ @FunctionalInterface
+ public interface Factory {
+ AsyncLoggerDisruptor createAsyncLoggerDisruptor(String contextName);
+ }
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncWaitStrategyFactory.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncWaitStrategyFactory.java
index 491b37eebf7..24fd78688be 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncWaitStrategyFactory.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/AsyncWaitStrategyFactory.java
@@ -17,6 +17,7 @@
package org.apache.logging.log4j.async.logger;
import com.lmax.disruptor.WaitStrategy;
+import java.util.function.Supplier;
/**
* This interface allows users to configure a custom Disruptor WaitStrategy used for
@@ -24,7 +25,8 @@
*
* @since 2.17.3
*/
-public interface AsyncWaitStrategyFactory {
+@FunctionalInterface
+public interface AsyncWaitStrategyFactory extends Supplier {
/**
* Creates and returns a non-null implementation of the LMAX Disruptor's WaitStrategy interface.
* This WaitStrategy will be used by Log4j Async Loggers and Async LoggerConfigs.
@@ -32,4 +34,9 @@ public interface AsyncWaitStrategyFactory {
* @return the WaitStrategy instance to be used by Async Loggers and Async LoggerConfigs
*/
WaitStrategy createWaitStrategy();
+
+ @Override
+ default WaitStrategy get() {
+ return createWaitStrategy();
+ }
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/BasicAsyncLoggerContextSelector.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/BasicAsyncLoggerContextSelector.java
index e8d458f4662..fd40008033a 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/BasicAsyncLoggerContextSelector.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/BasicAsyncLoggerContextSelector.java
@@ -16,7 +16,6 @@
*/
package org.apache.logging.log4j.async.logger;
-import java.net.URI;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.selector.BasicContextSelector;
import org.apache.logging.log4j.plugins.Inject;
@@ -36,8 +35,13 @@ public BasicAsyncLoggerContextSelector(final ConfigurableInstanceFactory instanc
super(instanceFactory);
}
+ @Override
+ protected LoggerContext.Builder newBuilder() {
+ return instanceFactory.getInstance(AsyncLoggerContext.Builder.class);
+ }
+
@Override
protected LoggerContext createContext() {
- return new AsyncLoggerContext("AsyncDefault", null, (URI) null, instanceFactory);
+ return createContext("AsyncDefault", null, getClass().getClassLoader());
}
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorConfiguration.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorConfiguration.java
index 01eccd43e64..9dce16de99a 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorConfiguration.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorConfiguration.java
@@ -20,16 +20,30 @@
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.AbstractLifeCycle;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationExtension;
import org.apache.logging.log4j.plugins.Configurable;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginAliases;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Lazy;
import org.apache.logging.log4j.util.LoaderUtil;
-
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A container for:
+ *
+ * - A user provided wait strategy factory.
+ * - The common {@link AsyncLoggerConfigDisruptor} instance shared by all logger configs.
+ *
+ * TODO: the only reason the disruptor needs a holder is that
+ * {@link org.apache.logging.log4j.plugins.di.InstanceFactory} is currently unable to stop the services it creates.
+ * In the future the disruptor will be in the instance factory.
+ */
@Configurable(printObject = true)
@Plugin("Disruptor")
@PluginAliases("AsyncWaitStrategyFactory")
@@ -37,37 +51,35 @@ public final class DisruptorConfiguration extends AbstractLifeCycle implements C
private static final Logger LOGGER = StatusLogger.getLogger();
- private final AsyncWaitStrategyFactory waitStrategyFactory;
- private final Lazy loggerConfigDisruptor =
- Lazy.lazy(() -> new AsyncLoggerConfigDisruptor(getWaitStrategyFactory()));
+ private final @Nullable AsyncWaitStrategyFactory waitStrategyFactory;
+ private final Lazy loggerConfigDisruptor;
- private DisruptorConfiguration(final AsyncWaitStrategyFactory waitStrategyFactory) {
+ private DisruptorConfiguration(
+ final @Nullable AsyncWaitStrategyFactory waitStrategyFactory, final Configuration configuration) {
this.waitStrategyFactory = waitStrategyFactory;
+ this.loggerConfigDisruptor =
+ Lazy.lazy(() -> configuration.getComponent(Key.forClass(AsyncLoggerConfigDisruptor.class)));
}
- public AsyncWaitStrategyFactory getWaitStrategyFactory() {
+ public @Nullable AsyncWaitStrategyFactory getWaitStrategyFactory() {
return waitStrategyFactory;
}
- public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() {
+ AsyncLoggerConfigDisruptor getLoggerConfigDisruptor() {
return loggerConfigDisruptor.get();
}
@Override
public void start() {
- if (loggerConfigDisruptor.isInitialized()) {
- LOGGER.info("Starting AsyncLoggerConfigDisruptor.");
- loggerConfigDisruptor.get().start();
- }
+ LOGGER.info("Starting AsyncLoggerConfigDisruptor.");
+ loggerConfigDisruptor.get().start();
super.start();
}
@Override
public boolean stop(final long timeout, final TimeUnit timeUnit) {
- if (loggerConfigDisruptor.isInitialized()) {
- LOGGER.info("Stopping AsyncLoggerConfigDisruptor.");
- loggerConfigDisruptor.get().stop(timeout, timeUnit);
- }
+ LOGGER.info("Stopping AsyncLoggerConfigDisruptor.");
+ loggerConfigDisruptor.get().stop(timeout, timeUnit);
return super.stop(timeout, timeUnit);
}
@@ -84,6 +96,8 @@ public static final class Builder implements org.apache.logging.log4j.plugins.ut
@PluginBuilderAttribute
private String waitFactory;
+ private Configuration configuration;
+
public Builder setFactoryClassName(final String factoryClassName) {
this.factoryClassName = factoryClassName;
return this;
@@ -94,19 +108,21 @@ public Builder setWaitFactory(final String waitFactory) {
return this;
}
- @Override
- public DisruptorConfiguration build() {
- return new DisruptorConfiguration(
- createWaitStrategyFactory(Objects.toString(waitFactory, factoryClassName)));
+ @Inject
+ public Builder setConfiguration(final Configuration configuration) {
+ this.configuration = configuration;
+ return this;
}
- private static AsyncWaitStrategyFactory createWaitStrategyFactory(final String factoryClassName) {
+ @Override
+ public DisruptorConfiguration build() {
+ final String factoryClassName = Objects.toString(waitFactory, this.factoryClassName);
if (factoryClassName != null) {
try {
final AsyncWaitStrategyFactory asyncWaitStrategyFactory =
LoaderUtil.newCheckedInstanceOf(factoryClassName, AsyncWaitStrategyFactory.class);
LOGGER.info("Using configured AsyncWaitStrategy factory {}.", factoryClassName);
- return asyncWaitStrategyFactory;
+ return new DisruptorConfiguration(asyncWaitStrategyFactory, configuration);
} catch (final ClassCastException e) {
LOGGER.error(
"Ignoring factory '{}': it is not assignable to AsyncWaitStrategyFactory",
@@ -118,9 +134,10 @@ private static AsyncWaitStrategyFactory createWaitStrategyFactory(final String f
e.getMessage(),
e);
}
+ } else {
+ LOGGER.info("Using default AsyncWaitStrategy factory.");
}
- LOGGER.info("Using default AsyncWaitStrategy factory.");
- return null;
+ return new DisruptorConfiguration(null, configuration);
}
}
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DefaultAsyncWaitStrategyFactory.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultAsyncWaitStrategyFactory.java
similarity index 95%
rename from log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DefaultAsyncWaitStrategyFactory.java
rename to log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultAsyncWaitStrategyFactory.java
index d0084a17ee3..6ee433a7a57 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DefaultAsyncWaitStrategyFactory.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultAsyncWaitStrategyFactory.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.async.logger;
+package org.apache.logging.log4j.async.logger.internal;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.BusySpinWaitStrategy;
@@ -23,13 +23,14 @@
import com.lmax.disruptor.YieldingWaitStrategy;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.async.logger.AsyncWaitStrategyFactory;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyKey;
import org.apache.logging.log4j.util.Strings;
-class DefaultAsyncWaitStrategyFactory implements AsyncWaitStrategyFactory {
+public class DefaultAsyncWaitStrategyFactory implements AsyncWaitStrategyFactory {
static final String DEFAULT_WAIT_STRATEGY_CLASSNAME = TimeoutBlockingWaitStrategy.class.getName();
private static final Logger LOGGER = StatusLogger.getLogger();
private final PropertyKey propertyKey;
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultBundle.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultBundle.java
new file mode 100644
index 00000000000..7fe21f07d81
--- /dev/null
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DefaultBundle.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.async.logger.internal;
+
+import com.lmax.disruptor.WaitStrategy;
+import org.apache.logging.log4j.async.logger.AsyncLoggerConfigDisruptor;
+import org.apache.logging.log4j.async.logger.AsyncLoggerDisruptor;
+import org.apache.logging.log4j.async.logger.DisruptorConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
+import org.apache.logging.log4j.core.impl.LogEventFactory;
+import org.apache.logging.log4j.plugins.Factory;
+import org.apache.logging.log4j.plugins.Named;
+import org.apache.logging.log4j.plugins.SingletonFactory;
+import org.apache.logging.log4j.plugins.condition.ConditionalOnMissingBinding;
+import org.apache.logging.log4j.plugins.condition.ConditionalOnPresentBindings;
+
+/**
+ * Provides default services for the per-context instance factory.
+ */
+public class DefaultBundle {
+
+ @Factory
+ @Named("AsyncLogger")
+ @ConditionalOnMissingBinding
+ public WaitStrategy asyncLoggerWaitStrategy() {
+ return DisruptorUtil.createWaitStrategy(Log4jPropertyKey.ASYNC_LOGGER_WAIT_STRATEGY, null);
+ }
+
+ @SingletonFactory
+ @ConditionalOnMissingBinding
+ public AsyncLoggerDisruptor.Factory asyncLoggerDisruptorFactory(
+ final @Named("AsyncLogger") WaitStrategy waitStrategy) {
+ return contextName -> new AsyncLoggerDisruptor(contextName, waitStrategy);
+ }
+
+ @Factory
+ @Named("AsyncLoggerConfig")
+ @ConditionalOnPresentBindings(bindings = Configuration.class)
+ public WaitStrategy defaultAsyncLoggerWaitStrategy(final Configuration configuration) {
+ final DisruptorConfiguration disruptorConfiguration = configuration.getExtension(DisruptorConfiguration.class);
+ return DisruptorUtil.createWaitStrategy(
+ Log4jPropertyKey.ASYNC_CONFIG_WAIT_STRATEGY,
+ disruptorConfiguration != null ? disruptorConfiguration.getWaitStrategyFactory() : null);
+ }
+
+ @Factory
+ @ConditionalOnPresentBindings(bindings = Configuration.class)
+ public AsyncLoggerConfigDisruptor asyncLoggerConfigDisruptor(
+ final @Named("AsyncLoggerConfig") WaitStrategy waitStrategy, final LogEventFactory logEventFactory) {
+ return new AsyncLoggerConfigDisruptor(waitStrategy, logEventFactory);
+ }
+}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorUtil.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DisruptorUtil.java
similarity index 75%
rename from log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorUtil.java
rename to log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DisruptorUtil.java
index 9716276ed65..dc639223838 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/DisruptorUtil.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/DisruptorUtil.java
@@ -14,16 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.async.logger;
+package org.apache.logging.log4j.async.logger.internal;
import static org.apache.logging.log4j.core.impl.Log4jPropertyKey.ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME;
import static org.apache.logging.log4j.core.impl.Log4jPropertyKey.ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.WaitStrategy;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.async.logger.AsyncLoggerConfigDefaultExceptionHandler;
+import org.apache.logging.log4j.async.logger.AsyncLoggerConfigDisruptor;
+import org.apache.logging.log4j.async.logger.AsyncLoggerDefaultExceptionHandler;
+import org.apache.logging.log4j.async.logger.AsyncWaitStrategyFactory;
+import org.apache.logging.log4j.async.logger.RingBufferLogEvent;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.core.util.Integers;
import org.apache.logging.log4j.status.StatusLogger;
@@ -34,7 +37,7 @@
/**
* Utility methods for getting Disruptor related configuration.
*/
-final class DisruptorUtil {
+public final class DisruptorUtil {
private static final Logger LOGGER = StatusLogger.getLogger();
private static final int RINGBUFFER_MIN_SIZE = 128;
private static final int RINGBUFFER_DEFAULT_SIZE = 4 * 1024;
@@ -45,15 +48,15 @@ final class DisruptorUtil {
* especially when the number of application threads vastly outnumbered the number of cores.
* CPU utilization is significantly reduced by restricting access to the enqueue operation.
*/
- static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
+ public static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
.getBooleanProperty(Log4jPropertyKey.ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, true);
- static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
+ public static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
.getBooleanProperty(Log4jPropertyKey.ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL, true);
private DisruptorUtil() {}
- static WaitStrategy createWaitStrategy(
+ public static WaitStrategy createWaitStrategy(
final PropertyKey key, final AsyncWaitStrategyFactory asyncWaitStrategyFactory) {
if (asyncWaitStrategyFactory == null) {
@@ -66,7 +69,7 @@ static WaitStrategy createWaitStrategy(
return asyncWaitStrategyFactory.createWaitStrategy();
}
- static int calculateRingBufferSize(final PropertyKey key) {
+ public static int calculateRingBufferSize(final PropertyKey key) {
int ringBufferSize = RINGBUFFER_DEFAULT_SIZE;
final String userPreferredRBSize =
PropertiesUtil.getProperties().getStringProperty(key, String.valueOf(ringBufferSize));
@@ -84,7 +87,7 @@ static int calculateRingBufferSize(final PropertyKey key) {
return Integers.ceilingNextPowerOfTwo(ringBufferSize);
}
- static ExceptionHandler getAsyncLoggerExceptionHandler() {
+ public static ExceptionHandler getAsyncLoggerExceptionHandler() {
try {
return LoaderUtil.newCheckedInstanceOfProperty(
ASYNC_LOGGER_EXCEPTION_HANDLER_CLASS_NAME,
@@ -96,7 +99,8 @@ static ExceptionHandler getAsyncLoggerExceptionHandler() {
}
}
- static ExceptionHandler getAsyncLoggerConfigExceptionHandler() {
+ public static ExceptionHandler
+ getAsyncLoggerConfigExceptionHandler() {
try {
return LoaderUtil.newCheckedInstanceOfProperty(
ASYNC_CONFIG_EXCEPTION_HANDLER_CLASS_NAME,
@@ -107,22 +111,4 @@ static ExceptionHandler getAsyncLo
return new AsyncLoggerConfigDefaultExceptionHandler();
}
}
-
- /**
- * Returns the thread ID of the background appender thread. This allows us to detect Logger.log() calls initiated
- * from the appender thread, which may cause deadlock when the RingBuffer is full. (LOG4J2-471)
- *
- * @param executor runs the appender thread
- * @return the thread ID of the background appender thread
- */
- public static long getExecutorThreadId(final ExecutorService executor) {
- final Future result = executor.submit(() -> Thread.currentThread().getId());
- try {
- return result.get();
- } catch (final Exception ex) {
- final String msg =
- "Could not obtain executor thread Id. " + "Giving up to avoid the risk of application deadlock.";
- throw new IllegalStateException(msg, ex);
- }
- }
}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/InstanceFactoryPostProcessor.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/InstanceFactoryPostProcessor.java
new file mode 100644
index 00000000000..18bb9dddbbd
--- /dev/null
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/InstanceFactoryPostProcessor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.async.logger.internal;
+
+import aQute.bnd.annotation.Resolution;
+import aQute.bnd.annotation.spi.ServiceProvider;
+import org.apache.logging.log4j.plugins.Ordered;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor;
+
+@Ordered(Ordered.LAST - 2000)
+@ServiceProvider(value = ConfigurableInstanceFactoryPostProcessor.class, resolution = Resolution.OPTIONAL)
+public class InstanceFactoryPostProcessor implements ConfigurableInstanceFactoryPostProcessor {
+ @Override
+ public void postProcessFactory(final ConfigurableInstanceFactory factory) {
+ factory.registerBundle(new DefaultBundle());
+ }
+}
diff --git a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/TimeoutBlockingWaitStrategy.java b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/TimeoutBlockingWaitStrategy.java
similarity index 97%
rename from log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/TimeoutBlockingWaitStrategy.java
rename to log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/TimeoutBlockingWaitStrategy.java
index 657da6fec47..faacfdd6aa8 100644
--- a/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/TimeoutBlockingWaitStrategy.java
+++ b/log4j-async-logger/src/main/java/org/apache/logging/log4j/async/logger/internal/TimeoutBlockingWaitStrategy.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.async.logger;
+package org.apache.logging.log4j.async.logger.internal;
import com.lmax.disruptor.AlertException;
import com.lmax.disruptor.BatchEventProcessor;
@@ -46,7 +46,7 @@
//
// Log4j 3.0.0 NOTE:
// Implementation was updated to use Lock/Condition API for https://github.com/apache/logging-log4j2/issues/1532
-class TimeoutBlockingWaitStrategy implements WaitStrategy {
+public class TimeoutBlockingWaitStrategy implements WaitStrategy {
private final Lock mutex = new ReentrantLock();
private final Condition condition = mutex.newCondition();
private final long timeoutInNanos;
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerClassLoadDeadlockTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerClassLoadDeadlockTest.java
index b4ff970790c..eb694e6a972 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerClassLoadDeadlockTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerClassLoadDeadlockTest.java
@@ -31,7 +31,7 @@
@Tag("async")
@SetTestProperty(
key = "LoggerContext.selector",
- value = "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector")
+ value = "org.apache.logging.log4j.async.logger.AsyncLoggerContextSelector")
@SetTestProperty(key = "AsyncLogger.ringBufferSize", value = "128")
@SetTestProperty(
key = "Configuration.file",
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigAutoFlushTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigAutoFlushTest.java
index d59738208a2..9e5ec1189fd 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigAutoFlushTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigAutoFlushTest.java
@@ -16,11 +16,12 @@
*/
package org.apache.logging.log4j.async.logger;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.assertj.core.api.Assertions.assertThat;
-import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
@@ -37,14 +38,14 @@ public class AsyncLoggerConfigAutoFlushTest {
@Test
@LoggerContextSource
public void testFlushAtEndOfBatch(final LoggerContext ctx) throws Exception {
- final File file =
- loggingPath.resolve("AsyncLoggerConfigAutoFlushTest.log").toFile();
+ final Path file = loggingPath.resolve("AsyncLoggerConfigAutoFlushTest.log");
final Logger log = ctx.getLogger("com.foo.Bar");
final String msg = "Message flushed with immediate flush=false";
log.info(msg);
ctx.stop(); // stop async thread
- final String contents = Files.readString(file.toPath());
- assertTrue(contents.contains(msg), "line1 correct");
+ final List contents = Files.readAllLines(file, UTF_8);
+ assertThat(contents).hasSize(1);
+ assertThat(contents.get(0)).contains(msg);
}
}
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigTest.java
index 6a08fdaf867..5a63ba1e40f 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerConfigTest.java
@@ -107,8 +107,7 @@ public void testSingleFilterInvocation() {
when(appender.getName()).thenReturn("test");
config.addAppender(appender, null, null);
final DisruptorConfiguration disruptorConfig = configuration.getExtension(DisruptorConfiguration.class);
- final AsyncLoggerConfigDisruptor disruptor =
- (AsyncLoggerConfigDisruptor) disruptorConfig.getAsyncLoggerConfigDelegate();
+ final AsyncLoggerConfigDisruptor disruptor = disruptorConfig.getLoggerConfigDisruptor();
disruptor.start();
try {
config.log(FQCN, FQCN, null, Level.INFO, new SimpleMessage(), null);
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextTest.java
index bba0cbd178c..996621b3d41 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerContextTest.java
@@ -19,11 +19,9 @@
import static org.junit.Assert.assertTrue;
import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.CoreLoggerContexts;
import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
-import org.apache.logging.log4j.internal.recycler.DummyRecyclerFactoryProvider;
-import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.plugins.di.DI;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -32,14 +30,7 @@ public class AsyncLoggerContextTest {
@Test
public void testNewInstanceReturnsAsyncLogger() {
- final Logger logger = new AsyncLoggerContext("a")
- .newInstance(
- new LoggerContext("a"),
- "a",
- null,
- null,
- new DummyRecyclerFactoryProvider().createForEnvironment(null),
- StatusLogger.getLogger());
+ final Logger logger = new AsyncLoggerContext("a", null, null, DI.createInitializedFactory()).getLogger("a");
assertTrue(logger instanceof AsyncLogger);
CoreLoggerContexts.stopLoggerContext(); // stop async thread
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerCustomSelectorLocationTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerCustomSelectorLocationTest.java
index f84dd735abe..c81b3d3f55d 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerCustomSelectorLocationTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncLoggerCustomSelectorLocationTest.java
@@ -34,6 +34,7 @@
import org.apache.logging.log4j.core.test.junit.ContextSelectorType;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.plugins.Singleton;
+import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.test.junit.TempLoggingDir;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@@ -74,7 +75,8 @@ public void testCustomAsyncSelectorLocation(final LoggerContext ctx) throws Exce
@Singleton
public static final class CustomAsyncContextSelector implements ContextSelector {
- private static final LoggerContext CONTEXT = new AsyncLoggerContext("AsyncDefault");
+ private static final LoggerContext CONTEXT =
+ new AsyncLoggerContext("AsyncDefault", null, null, DI.createInitializedFactory());
@Override
public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncThreadContextTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncThreadContextTest.java
index c8d57007bc1..8ce0ec2fffb 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncThreadContextTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/AsyncThreadContextTest.java
@@ -37,6 +37,7 @@
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.test.CoreLoggerContexts;
import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.spi.LoggingSystem;
import org.apache.logging.log4j.spi.LoggingSystemProperty;
import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
import org.apache.logging.log4j.test.TestProperties;
@@ -97,6 +98,7 @@ void init() {
System.setProperty(
LoggingSystemProperty.Constant.THREAD_CONTEXT_MAP_CLASS, PACKAGE + implClassSimpleName());
PropertiesUtil.getProperties().reload();
+ LoggingSystem.reset();
ThreadContextTestAccess.init();
}
@@ -169,7 +171,7 @@ private static void runTest(
((AsyncLoggerContext) context).getAsyncLoggerDisruptor().getRingBuffer()::remainingCapacity;
} else {
remainingCapacity =
- ((AsyncLoggerConfigDisruptor) ((AsyncLoggerConfig) log.get()).getAsyncLoggerConfigDelegate())
+ ((AsyncLoggerConfigDisruptor) ((AsyncLoggerConfig) log.get()).getAsyncLoggerConfigDisruptor())
.getRingBuffer()::remainingCapacity;
}
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DefaultIncludeLocationTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DefaultIncludeLocationTest.java
index 9f92ff02c6b..6911b7a224a 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DefaultIncludeLocationTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DefaultIncludeLocationTest.java
@@ -16,12 +16,13 @@
*/
package org.apache.logging.log4j.async.logger;
+import java.net.URI;
import java.util.stream.Stream;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.NullConfiguration;
-import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.plugins.di.DI;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -58,8 +59,7 @@ private static Stream loggerConfigs(final Configuration config) {
}
static Stream loggerContextDefaultLocation() {
- final LoggerContext ctx = new LoggerContext("sync");
- ctx.setProperties(PropertiesUtil.getProperties());
+ final LoggerContext ctx = new LoggerContext("sync", null, (URI) null, DI.createInitializedFactory());
final NullConfiguration config = new NullConfiguration(ctx);
ctx.setConfiguration(config);
return loggerConfigs(config);
@@ -74,8 +74,7 @@ void loggerContextDefaultLocation(final LoggerConfig loggerConfig, final boolean
}
static Stream asyncLoggerContextDefaultLocation() {
- final AsyncLoggerContext ctx = new AsyncLoggerContext("async");
- ctx.setProperties(PropertiesUtil.getProperties());
+ final AsyncLoggerContext ctx = new AsyncLoggerContext("async", null, null, DI.createInitializedFactory());
final NullConfiguration config = new NullConfiguration(ctx);
ctx.setConfiguration(config);
return loggerConfigs(config).map(args -> (LoggerConfig) args.get()[0]);
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationInvalidTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationInvalidTest.java
index c7742987d5e..a4473efdf58 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationInvalidTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationInvalidTest.java
@@ -19,6 +19,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.apache.logging.log4j.async.logger.internal.TimeoutBlockingWaitStrategy;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.ContextSelectorType;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationTest.java
index 190dbee16bc..f3424774230 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/DisruptorConfigurationTest.java
@@ -20,6 +20,8 @@
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.YieldingWaitStrategy;
+import org.apache.logging.log4j.async.logger.internal.DefaultAsyncWaitStrategyFactory;
+import org.apache.logging.log4j.async.logger.internal.TimeoutBlockingWaitStrategy;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
@@ -57,8 +59,7 @@ public void testWaitStrategy(final LoggerContext context) throws Exception {
final AsyncLoggerConfig loggerConfig =
(AsyncLoggerConfig) ((org.apache.logging.log4j.core.Logger) logger).get();
- final AsyncLoggerConfigDisruptor delegate =
- (AsyncLoggerConfigDisruptor) loggerConfig.getAsyncLoggerConfigDelegate();
+ final AsyncLoggerConfigDisruptor delegate = loggerConfig.getAsyncLoggerConfigDisruptor();
assertThat(delegate.getWaitStrategy().getClass()).isEqualTo(YieldingWaitStrategy.class);
assertThat(delegate.getWaitStrategy()).isInstanceOf(com.lmax.disruptor.YieldingWaitStrategy.class);
}
@@ -81,7 +82,7 @@ public void testIncorrectWaitStrategyFallsBackToDefault(
final AsyncLoggerConfig loggerConfig =
(AsyncLoggerConfig) ((org.apache.logging.log4j.core.Logger) logger).get();
final AsyncLoggerConfigDisruptor delegate =
- (AsyncLoggerConfigDisruptor) loggerConfig.getAsyncLoggerConfigDelegate();
+ (AsyncLoggerConfigDisruptor) loggerConfig.getAsyncLoggerConfigDisruptor();
assertThat(delegate.getWaitStrategy().getClass()).isEqualTo(TimeoutBlockingWaitStrategy.class);
assertThat(delegate.getWaitStrategy()).isInstanceOf(TimeoutBlockingWaitStrategy.class);
}
diff --git a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/QueueFullAsyncAbstractTest.java b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/QueueFullAsyncAbstractTest.java
index 1e5e4bf3bc0..501c8b68d98 100644
--- a/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/QueueFullAsyncAbstractTest.java
+++ b/log4j-async-logger/src/test/java/org/apache/logging/log4j/async/logger/QueueFullAsyncAbstractTest.java
@@ -57,23 +57,21 @@ protected static void assertAsyncLoggerConfig(final LoggerContext ctx, final int
assertThat(config).isNotNull();
assertThat(config.getRootLogger()).isInstanceOf(AsyncLoggerConfig.class);
final DisruptorConfiguration disruptorConfig = config.getExtension(DisruptorConfiguration.class);
- final AsyncLoggerConfigDisruptor disruptor =
- (AsyncLoggerConfigDisruptor) disruptorConfig.getAsyncLoggerConfigDelegate();
+ final AsyncLoggerConfigDisruptor disruptor = disruptorConfig.getLoggerConfigDisruptor();
assertThat(disruptor.getRingBuffer().getBufferSize()).isEqualTo(expectedBufferSize);
}
@Override
protected long asyncRemainingCapacity(final Logger logger) {
if (logger instanceof final AsyncLogger asyncLogger) {
- return Optional.ofNullable(asyncLogger.getAsyncLoggerDisruptor())
+ return Optional.of(asyncLogger.getAsyncLoggerDisruptor())
.map(AsyncLoggerDisruptor::getRingBuffer)
.map(RingBuffer::remainingCapacity)
.orElse(0L);
} else {
final LoggerConfig loggerConfig = ((org.apache.logging.log4j.core.Logger) logger).get();
if (loggerConfig instanceof final AsyncLoggerConfig asyncLoggerConfig) {
- return Optional.ofNullable(
- (AsyncLoggerConfigDisruptor) asyncLoggerConfig.getAsyncLoggerConfigDelegate())
+ return Optional.ofNullable(asyncLoggerConfig.getAsyncLoggerConfigDisruptor())
.map(AsyncLoggerConfigDisruptor::getRingBuffer)
.map(RingBuffer::remainingCapacity)
.orElse(0L);
diff --git a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfiguration.java b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfiguration.java
index 03224bbec72..92d16ff6901 100644
--- a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfiguration.java
+++ b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfiguration.java
@@ -29,12 +29,13 @@
*/
public class JavaPropsConfiguration extends AbstractJacksonConfiguration {
- public JavaPropsConfiguration(final LoggerContext loggerContext, final ConfigurationSource configSource) {
- super(loggerContext, configSource);
+ public JavaPropsConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
+ super(loggerContext, configurationSource);
}
@Override
- protected Configuration createConfiguration(LoggerContext loggerContext, ConfigurationSource configurationSource) {
+ protected Configuration createConfiguration(
+ final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
return new JavaPropsConfiguration(loggerContext, configurationSource);
}
diff --git a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
index 5230d140008..b585cdc6e5c 100644
--- a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
+++ b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
@@ -40,7 +40,7 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final C
}
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return SUFFIXES;
}
}
diff --git a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfiguration.java b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfiguration.java
index 9cc255f5e6e..0deff0b9dd1 100644
--- a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfiguration.java
+++ b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfiguration.java
@@ -39,6 +39,7 @@ protected Configuration createConfiguration(
return new YamlConfiguration(loggerContext, configurationSource);
}
+ @Override
protected ObjectMapper getObjectMapper() {
return YAMLMapper.builder()
.configure(JsonParser.Feature.ALLOW_COMMENTS, true)
diff --git a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
index fc6671ba248..ae6c4d95035 100644
--- a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
+++ b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
@@ -40,7 +40,7 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final C
}
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return SUFFIXES;
}
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
index 30e06d28ce4..643b77741dd 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
@@ -24,6 +24,9 @@
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.util.PropertiesUtil;
/**
*
@@ -33,11 +36,11 @@ public class BasicConfigurationFactory extends ConfigurationFactory {
@Override
public Configuration getConfiguration(
final LoggerContext loggerContext, final String name, final URI configLocation) {
- return new BasicConfiguration();
+ return new BasicConfiguration(loggerContext);
}
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return null;
}
@@ -51,7 +54,17 @@ public static class BasicConfiguration extends AbstractConfiguration {
private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
public BasicConfiguration() {
- super(null, ConfigurationSource.NULL_SOURCE);
+ this(null);
+ }
+
+ public BasicConfiguration(final LoggerContext loggerContext) {
+ super(
+ loggerContext,
+ ConfigurationSource.NULL_SOURCE,
+ loggerContext != null ? loggerContext.getEnvironment() : PropertiesUtil.getProperties(),
+ loggerContext != null
+ ? (ConfigurableInstanceFactory) loggerContext.getInstanceFactory()
+ : DI.createInitializedFactory());
final LoggerConfig root = getRootLogger();
final String name = System.getProperty(DEFAULT_LEVEL);
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/config/AbstractNestedLoggerConfigTest.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/config/AbstractNestedLoggerConfigTest.java
index 4c0a3cbb5f5..2f0ec5d34a8 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/config/AbstractNestedLoggerConfigTest.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/config/AbstractNestedLoggerConfigTest.java
@@ -20,11 +20,13 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
+import org.apache.logging.log4j.plugins.di.DI;
import org.junit.jupiter.api.Test;
public abstract class AbstractNestedLoggerConfigTest {
@@ -51,8 +53,9 @@ public void testInheritParentLevel() throws IOException {
private Configuration loadConfiguration(final String resourcePath) throws IOException {
try (final InputStream in = getClass().getResourceAsStream(getClass().getSimpleName() + resourcePath)) {
- final Configuration configuration =
- new XmlConfiguration(new LoggerContext("test"), new ConfigurationSource(in));
+ final Configuration configuration = new XmlConfiguration(
+ new LoggerContext("test", null, (URI) null, DI.createInitializedFactory()),
+ new ConfigurationSource(in));
configuration.initialize();
configuration.start();
return configuration;
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
index 01f67048266..be40bc61b0e 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
@@ -22,6 +22,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.URIConfigurationFactory;
/**
* Specifies a particular {@link ConfigurationFactory} class to use for a test class or method instead of the default.
@@ -31,5 +32,5 @@
@Inherited
@Log4jTest
public @interface ConfigurationFactoryType {
- Class extends ConfigurationFactory> value();
+ Class extends URIConfigurationFactory> value();
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jExtension.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jExtension.java
index 1cb0c2d93b7..4827d843bb9 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jExtension.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jExtension.java
@@ -25,7 +25,7 @@
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.URIConfigurationFactory;
import org.apache.logging.log4j.core.impl.Log4jContextFactory;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.core.selector.ContextSelector;
@@ -33,6 +33,7 @@
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.Provider;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
@@ -104,14 +105,15 @@ private static void configure(
final AnnotatedElement element,
final Class> testClass) {
final ConfigurableInstanceFactory instanceFactory = configureInstanceFactory(builder, element);
- final Log4jContextFactory factory = instanceFactory.getInstance(Log4jContextFactory.class);
+ final Provider provider = instanceFactory.getInstance(Provider.class);
+ final Log4jContextFactory factory = (Log4jContextFactory) provider.getLoggerContextFactory();
store.put(LoggerContextFactoryHolder.class, new LoggerContextFactoryHolder(factory));
if (AnnotationSupport.isAnnotated(element, LoggingResolvers.class)) {
AnnotationSupport.findAnnotation(element, LoggerContextSource.class)
.map(source -> configureLoggerContextSource(source, testClass, factory))
.or(() -> AnnotationSupport.findAnnotation(element, LegacyLoggerContextSource.class)
.map(source -> configureLegacyLoggerContextSource(source, testClass, factory)))
- .ifPresent(provider -> store.put(LoggerContextProvider.class, provider));
+ .ifPresent(p -> store.put(LoggerContextProvider.class, p));
}
}
@@ -125,7 +127,7 @@ private static ConfigurableInstanceFactory configureInstanceFactory(
.toFunction(instanceFactory -> instanceFactory.getFactory(clazz)));
AnnotationSupport.findAnnotation(element, ConfigurationFactoryType.class)
.map(ConfigurationFactoryType::value)
- .ifPresent(clazz -> builder.addBindingFrom(ConfigurationFactory.KEY)
+ .ifPresent(clazz -> builder.addBindingFrom(URIConfigurationFactory.KEY)
.toFunction(instanceFactory -> instanceFactory.getFactory(clazz)));
return builder.build();
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerContextTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerContextTest.java
deleted file mode 100644
index a381f161c53..00000000000
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerContextTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
-import org.apache.logging.log4j.core.impl.internal.InternalLoggerContext;
-import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry;
-import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
-import org.apache.logging.log4j.spi.LoggerContextFactory;
-import org.junit.jupiter.api.Test;
-
-/**
- * Validate Logging after Shutdown.
- */
-public class LoggerContextTest {
-
- @Test
- public void shutdownTest() {
- LoggerContextFactory contextFactory = LogManager.getFactory();
- assertTrue(contextFactory instanceof Log4jContextFactory);
- Log4jContextFactory factory = (Log4jContextFactory) contextFactory;
- ShutdownCallbackRegistry registry = factory.getShutdownCallbackRegistry();
- assertTrue(registry instanceof DefaultShutdownCallbackRegistry);
- ((DefaultShutdownCallbackRegistry) registry).start();
- ((DefaultShutdownCallbackRegistry) registry).stop();
- org.apache.logging.log4j.spi.LoggerContext loggerContext = LogManager.getContext(false);
- assertTrue(loggerContext instanceof InternalLoggerContext);
- }
-}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
index 84aab071807..49f30589562 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
@@ -52,6 +52,7 @@
import org.apache.logging.log4j.message.StringFormatterMessageFactory;
import org.apache.logging.log4j.message.StructuredDataMessage;
import org.apache.logging.log4j.spi.LoggingSystem;
+import org.awaitility.Awaitility;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@@ -125,7 +126,7 @@ public void builder() {
final List events = app.getEvents();
assertEventCount(events, 3);
assertEquals(
- "org.apache.logging.log4j.core.LoggerTest.builder(LoggerTest.java:121)",
+ "org.apache.logging.log4j.core.LoggerTest.builder(LoggerTest.java:122)",
events.get(0).getSource().toString(),
"Incorrect location");
assertEquals(Level.DEBUG, events.get(0).getLevel(), "Incorrect Level");
@@ -505,13 +506,7 @@ public void testReconfiguration(final LoggerContext context) throws Exception {
for (int i = 0; i < 17; ++i) {
logger.debug("Reconfigure");
}
- Thread.sleep(100);
- for (int i = 0; i < 20; i++) {
- if (context.getConfiguration() != oldConfig) {
- break;
- }
- Thread.sleep(50);
- }
+ Awaitility.await().atMost(10, TimeUnit.MINUTES).until(() -> context.getConfiguration() != oldConfig);
final Configuration newConfig = context.getConfiguration();
assertNotNull(newConfig, "No configuration");
assertNotSame(newConfig, oldConfig, "Reconfiguration failed");
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ReconfigureAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ReconfigureAppenderTest.java
index df2e82d2651..373601a6659 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ReconfigureAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ReconfigureAppenderTest.java
@@ -134,13 +134,15 @@ private void createAndAddAppender() {
config_builder.add(config_builder.newRootLogger(Level.INFO));
// Initialise the logger context.
- final LoggerContext logger_context = Configurator.initialize(config_builder.build());
+ final BuiltConfiguration configuration = config_builder.build();
+ final LoggerContext logger_context = Configurator.initialize(configuration);
// Retrieve the logger.
final Logger logger = (Logger) LogManager.getLogger(this.getClass());
- final Builder pattern_builder =
- PatternLayout.newBuilder().setPattern("[%d{dd-MM-yy HH:mm:ss}] %p %m %throwable %n");
+ final Builder pattern_builder = PatternLayout.newBuilder()
+ .setConfiguration(configuration)
+ .setPattern("[%d{dd-MM-yy HH:mm:ss}] %p %m %throwable %n");
final PatternLayout pattern_layout = (PatternLayout) pattern_builder.build();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
index 90d7f95bf73..7398c87c815 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderCronTest.java
@@ -32,10 +32,12 @@
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.test.junit.CleanUpDirectories;
import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.DisabledUntil;
/**
*
*/
+@DisabledUntil(date = "2024-04-01", reason = "Temporarily disabled due to deadlocks.")
public class RollingAppenderCronTest extends AbstractRollingListenerTest {
private static final String CONFIG = "log4j-rolling-cron.xml";
@@ -54,7 +56,6 @@ public void testAppender(final LoggerContext context, @Named("RollingFile") fina
final File file = new File(FILE);
assertThat(file).exists();
logger.debug("This is test message number 1");
- currentTimeMillis.addAndGet(2500);
rollover.await();
final File dir = new File(DIR);
@@ -67,12 +68,10 @@ public void testAppender(final LoggerContext context, @Named("RollingFile") fina
Files.newOutputStream(Path.of("target", "test-classes", "log4j-rolling-cron.xml"))) {
Files.copy(src, os);
}
- currentTimeMillis.addAndGet(5000);
// force a reconfiguration
for (int i = 0; i < 20; ++i) {
logger.debug("Adding new event {}", i);
}
- currentTimeMillis.addAndGet(1000);
reconfigured.await();
final RollingFileAppender appender = context.getConfiguration().getAppender("RollingFile");
final TriggeringPolicy policy = appender.getManager().getTriggeringPolicy();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
index c8cc306acec..afe24c95f2e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteWithHtmlLayoutTest.java
@@ -71,7 +71,7 @@ private void checkAppenderWithHtmlLayout(final boolean append, final Configurati
.setStrategy(DirectWriteRolloverStrategy.newBuilder()
.setConfig(config)
.build())
- .setLayout(HtmlLayout.createDefaultLayout())
+ .setLayout(HtmlLayout.newBuilder().setConfiguration(config).build())
.setAppend(append)
.build();
boolean stopped = false;
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java
index 2b80472a263..67f7c38e284 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java
@@ -55,7 +55,7 @@ public void testRefresh() {
.setAdditivity(false)
.setLevel(Level.INFO)
.setLoggerName("testlog4j2refresh")
- .setIncludeLocation("true")
+ .setIncludeLocation(true)
.setRefs(refs)
.setConfig(config)
.build();
@@ -98,7 +98,6 @@ public void testRefreshMinimalCodeStopStartConfig() {
assertDoesNotThrow(() -> log.error("Info message"));
}
- @SuppressWarnings("deprecation")
@Test
public void testRefreshDeprecatedApis() {
final Logger log = LogManager.getLogger(this.getClass());
@@ -138,7 +137,7 @@ public void testRefreshDeprecatedApis() {
.setAdditivity(false)
.setLevel(Level.INFO)
.setLoggerName("testlog4j2refresh")
- .setIncludeLocation("true")
+ .setIncludeLocation(true)
.setRefs(refs)
.setConfig(config)
.build();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerContextAwarePostProcessorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerContextAwarePostProcessorTest.java
index 20c0e66c4e5..70a151e1de9 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerContextAwarePostProcessorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggerContextAwarePostProcessorTest.java
@@ -18,7 +18,9 @@
import static org.assertj.core.api.Assertions.assertThat;
+import java.net.URI;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.InstanceFactory;
import org.junit.jupiter.api.Test;
@@ -34,7 +36,8 @@ public void setLoggerContext(final LoggerContext loggerContext) {
@Test
void loggerContextAwareInjection() {
- try (final LoggerContext context = new LoggerContext(getClass().getName())) {
+ try (final LoggerContext context =
+ new LoggerContext(getClass().getName(), null, (URI) null, DI.createInitializedFactory())) {
final InstanceFactory instanceFactory = context.getInstanceFactory();
final TestBean instance = instanceFactory.getInstance(TestBean.class);
assertThat(instance.context).isSameAs(context);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
index 5bb6691169e..7ea70a46146 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
@@ -122,8 +122,8 @@ private void testContextDataInjector() {
}
private void prepareThreadContext(final boolean isThreadContextMapInheritable) {
- LoggingSystem.getInstance()
- .setThreadContextMapFactory(() -> threadContextMapConstructor.apply(isThreadContextMapInheritable));
+ LoggingSystem.getProvider()
+ .setThreadContextMapFactory(threadContextMapConstructor.apply(isThreadContextMapInheritable));
ThreadContext.init();
ThreadContext.remove("baz");
ThreadContext.put("foo", "bar");
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
index 044a8cac7c7..cb14f727eab 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
@@ -38,6 +38,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
@@ -53,6 +54,9 @@
@UsingAnyThreadContext
@ConfigurationFactoryType(BasicConfigurationFactory.class)
public class HtmlLayoutTest {
+
+ private final Configuration CONFIGURATION = new DefaultConfiguration();
+
private static class MyLogEvent extends AbstractLogEvent {
@Override
@@ -91,14 +95,15 @@ public Message getMessage() {
@Test
public void testDefaultContentType() {
- final HtmlLayout layout = HtmlLayout.createDefaultLayout();
+ final HtmlLayout layout =
+ HtmlLayout.newBuilder().setConfiguration(CONFIGURATION).build();
assertEquals("text/html; charset=UTF-8", layout.getContentType());
}
@Test
public void testContentType() {
final HtmlLayout layout = HtmlLayout.newBuilder()
- .setConfiguration(new DefaultConfiguration())
+ .setConfiguration(CONFIGURATION)
.setContentType("text/html; charset=UTF-16")
.build();
assertEquals("text/html; charset=UTF-16", layout.getContentType());
@@ -108,7 +113,8 @@ public void testContentType() {
@Test
public void testDefaultCharset() {
- final HtmlLayout layout = HtmlLayout.createDefaultLayout();
+ final HtmlLayout layout =
+ HtmlLayout.newBuilder().setConfiguration(CONFIGURATION).build();
assertEquals(StandardCharsets.UTF_8, layout.getCharset());
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
index e5fc2ec29bc..0ceed7c43ae 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.logging.log4j.core.lookup;
+import static org.apache.logging.log4j.core.lookup.StrSubstitutorTest.LOOKUP_PLUGINS;
import static org.junit.Assert.assertSame;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -66,7 +67,7 @@ public void testGetDefaultLookup() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
final MapLookup defaultLookup = new MapLookup(map);
- final Interpolator interpolator = new Interpolator(defaultLookup);
+ final Interpolator interpolator = new Interpolator(defaultLookup, LOOKUP_PLUGINS);
assertEquals(defaultLookup.getMap(), ((MapLookup) interpolator.getDefaultLookup()).getMap());
assertSame(defaultLookup, interpolator.getDefaultLookup());
}
@@ -75,7 +76,7 @@ public void testGetDefaultLookup() {
public void testLookup() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
ThreadContext.put(TESTKEY, TESTVAL);
String value = lookup.lookup(TESTKEY);
assertEquals(TESTVAL, value);
@@ -101,7 +102,7 @@ private void assertLookupNotEmpty(final StrLookup lookup, final String key) {
@Test
public void testLookupWithDefaultInterpolator() {
- final StrLookup lookup = new Interpolator();
+ final StrLookup lookup = new Interpolator(new PropertiesLookup(Map.of()), LOOKUP_PLUGINS);
String value = lookup.lookup("sys:" + TESTKEY);
assertEquals(TESTVAL, value);
value = lookup.lookup("env:PATH");
@@ -123,7 +124,7 @@ public void testLookupWithDefaultInterpolator() {
public void testInterpolatorMapMessageWithNoPrefix() {
final HashMap configProperties = new HashMap<>();
configProperties.put("key", "configProperties");
- final Interpolator interpolator = new Interpolator(configProperties);
+ final Interpolator interpolator = new Interpolator(new PropertiesLookup(configProperties), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
@@ -137,7 +138,8 @@ public void testInterpolatorMapMessageWithNoPrefix() {
@Test
public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() {
- final Interpolator interpolator = new Interpolator(Collections.emptyMap());
+ final Interpolator interpolator =
+ new Interpolator(new PropertiesLookup(Collections.emptyMap()), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
@@ -153,7 +155,7 @@ public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() {
public void testInterpolatorMapMessageWithMapPrefix() {
final HashMap configProperties = new HashMap<>();
configProperties.put("key", "configProperties");
- final Interpolator interpolator = new Interpolator(configProperties);
+ final Interpolator interpolator = new Interpolator(new PropertiesLookup(configProperties), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java
index c0802beb8ea..14d5cd0be5d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.logging.log4j.core.lookup;
+import static org.apache.logging.log4j.core.lookup.StrSubstitutorTest.LOOKUP_PLUGINS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.HashMap;
@@ -35,7 +36,7 @@ public void testMainArgs() {
final Map properties = new HashMap();
properties.put("key", "value");
properties.put("bar", "default_bar_value");
- final Interpolator lookup = new Interpolator(properties);
+ final Interpolator lookup = new Interpolator(new PropertiesLookup(properties), LOOKUP_PLUGINS);
final StrSubstitutor substitutor = new StrSubstitutor(lookup);
final String replacedValue = substitutor.replace(null, str);
final String[] values = replacedValue.split(" ");
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java
index 6f5a119d2a9..0b88a4e662d 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/StrSubstitutorTest.java
@@ -20,8 +20,13 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.model.PluginType;
import org.apache.logging.log4j.test.junit.StatusLoggerLevel;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@@ -30,6 +35,14 @@
@StatusLoggerLevel("OFF")
public class StrSubstitutorTest {
+ static final ConfigurableInstanceFactory INSTANCE_FACTORY = DI.createInitializedFactory();
+ static final Map> LOOKUP_PLUGINS =
+ INSTANCE_FACTORY.getInstance(StrLookup.PLUGIN_CATEGORY_KEY).stream()
+ .collect(Collectors.toMap(
+ PluginType::getKey,
+ value -> INSTANCE_FACTORY.getFactory(
+ value.getPluginClass().asSubclass(StrLookup.class))));
+
private static final String TESTKEY = "TestKey";
private static final String TESTVAL = "TestValue";
@@ -47,7 +60,7 @@ public static void after() {
public void testLookup() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
ThreadContext.put(TESTKEY, TESTVAL);
String value = subst.replace("${TestKey}-${ctx:TestKey}-${sys:TestKey}");
@@ -162,7 +175,7 @@ public void testValueEscapeDelimiter() {
public void testDefault() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
ThreadContext.put(TESTKEY, TESTVAL);
// String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}");
@@ -174,7 +187,7 @@ public void testDefault() {
public void testDefaultReferencesLookupValue() {
final Map map = new HashMap<>();
map.put(TESTKEY, "${java:version}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}");
@@ -183,7 +196,7 @@ public void testDefaultReferencesLookupValue() {
@Test
public void testInfiniteSubstitutionOnString() {
- final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>()));
+ final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>()), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
final String infiniteSubstitution = "${${::-${::-$${::-j}}}}";
@@ -192,7 +205,7 @@ public void testInfiniteSubstitutionOnString() {
@Test
public void testInfiniteSubstitutionOnStringBuilder() {
- final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>()));
+ final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>()), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
final String infiniteSubstitution = "${${::-${::-$${::-j}}}}";
@@ -204,7 +217,7 @@ public void testRecursiveSubstitution() {
final Map map = new HashMap<>();
map.put("first", "${ctx:first}");
map.put("second", "secondValue");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
assertEquals("${ctx:first} and secondValue", subst.replace("${ctx:first} and ${ctx:second}"));
@@ -214,7 +227,7 @@ public void testRecursiveSubstitution() {
public void testRecursiveWithDefault() {
final Map map = new HashMap<>();
map.put("first", "${ctx:first:-default}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
assertEquals("default", subst.replace("${ctx:first}"));
@@ -224,7 +237,7 @@ public void testRecursiveWithDefault() {
public void testRecursiveWithRecursiveDefault() {
final Map map = new HashMap<>();
map.put("first", "${ctx:first:-${ctx:first}}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
assertEquals("${ctx:first}", subst.replace("${ctx:first}"));
@@ -234,7 +247,7 @@ public void testRecursiveWithRecursiveDefault() {
public void testNestedSelfReferenceWithRecursiveEvaluation() {
final Map map = new HashMap<>();
map.put("first", "${${ctx:first}}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
assertEquals("${${ctx:first}}", subst.replace("${ctx:first}"));
@@ -244,7 +257,7 @@ public void testNestedSelfReferenceWithRecursiveEvaluation() {
public void testRandomWithRecursiveDefault() {
final Map map = new HashMap<>();
map.put("first", "${env:RANDOM:-${ctx:first}}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(true);
assertEquals("${ctx:first}", subst.replace("${ctx:first}"));
@@ -255,7 +268,7 @@ public void testNoRecursiveEvaluationWithDefault() {
final Map map = new HashMap<>();
map.put("first", "${java:version}");
map.put("second", "${java:runtime}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("${java:version}", subst.replace("${ctx:first:-${ctx:second}}"));
@@ -265,7 +278,7 @@ public void testNoRecursiveEvaluationWithDefault() {
public void testNoRecursiveEvaluationWithDepthOne() {
final Map map = new HashMap<>();
map.put("first", "${java:version}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("${java:version}", subst.replace("${ctx:first}"));
@@ -275,7 +288,7 @@ public void testNoRecursiveEvaluationWithDepthOne() {
public void testLookupsNestedWithoutRecursiveEvaluation() {
final Map map = new HashMap<>();
map.put("first", "${java:version}");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("${java:version}", subst.replace("${${lower:C}t${lower:X}:first}"));
@@ -283,21 +296,23 @@ public void testLookupsNestedWithoutRecursiveEvaluation() {
@Test
public void testLookupThrows() {
- final StrSubstitutor subst = new StrSubstitutor(new Interpolator(new StrLookup() {
-
- @Override
- public String lookup(final String key) {
- if ("throw".equals(key)) {
- throw new RuntimeException();
- }
- return "success";
- }
-
- @Override
- public String lookup(final LogEvent event, final String key) {
- return lookup(key);
- }
- }));
+ final StrSubstitutor subst = new StrSubstitutor(new Interpolator(
+ new StrLookup() {
+
+ @Override
+ public String lookup(final String key) {
+ if ("throw".equals(key)) {
+ throw new RuntimeException();
+ }
+ return "success";
+ }
+
+ @Override
+ public String lookup(final LogEvent event, final String key) {
+ return lookup(key);
+ }
+ },
+ LOOKUP_PLUGINS));
subst.setRecursiveEvaluationAllowed(false);
assertEquals("success ${foo:throw} success", subst.replace("${foo:a} ${foo:throw} ${foo:c}"));
}
@@ -306,7 +321,7 @@ public String lookup(final LogEvent event, final String key) {
public void testTopLevelLookupsWithoutRecursiveEvaluation() {
final Map map = new HashMap<>();
map.put("key", "VaLuE");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("value", subst.replace("${lower:${ctx:key}}"));
@@ -316,7 +331,7 @@ public void testTopLevelLookupsWithoutRecursiveEvaluation() {
public void testTopLevelLookupsWithoutRecursiveEvaluation_doubleLower() {
final Map map = new HashMap<>();
map.put("key", "VaLuE");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("value", subst.replace("${lower:${lower:${ctx:key}}}"));
@@ -326,7 +341,7 @@ public void testTopLevelLookupsWithoutRecursiveEvaluation_doubleLower() {
public void testTopLevelLookupsWithoutRecursiveEvaluationAndDefaultValueLookup() {
final Map map = new HashMap<>();
map.put("key2", "TWO");
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
final StrSubstitutor subst = new StrSubstitutor(lookup);
subst.setRecursiveEvaluationAllowed(false);
assertEquals("two", subst.replace("${lower:${ctx:key1:-${ctx:key2}}}"));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest2.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest2.java
index 94e83708247..1e4f51b4243 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest2.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest2.java
@@ -22,10 +22,14 @@
import java.util.Calendar;
import java.util.Date;
import java.util.List;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.NullConfiguration;
import org.junit.jupiter.api.Test;
public class PatternParserTest2 {
+ private static final Configuration CONFIGURATION = new NullConfiguration();
+
@Test
public void testParseConvertBackslashes() {
final boolean convert = true;
@@ -58,7 +62,7 @@ public void testParseDontConvertBackslashes() {
private void parse(
final String pattern, final boolean convert, final StringBuilder buf, final Date date, final int i) {
- final PatternParser parser0 = new PatternParser(null, "Converter", null);
+ final PatternParser parser0 = new PatternParser(CONFIGURATION, "Converter", null);
final List converters = new ArrayList<>();
final List fields = new ArrayList<>();
parser0.parse(pattern, converters, fields, false, false, convert);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java
index 783300bc2fe..2481fe8b626 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java
@@ -19,8 +19,6 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import org.apache.logging.log4j.Level;
@@ -54,11 +52,8 @@ public void testReplacement(final LoggerContext context, @Named("List") final Li
logger.error(this.getClass().getName());
final List msgs = app.getMessages();
- assertNotNull(msgs);
- assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size());
- assertTrue(
- msgs.get(0).endsWith(EXPECTED),
- "Replacement failed - expected ending " + EXPECTED + ", actual " + msgs.get(0));
+ assertThat(msgs).isNotEmpty();
+ assertThat(msgs.get(0)).as("check formatted message").endsWith(EXPECTED);
}
@Test
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/NamedLoggerContextPropertiesTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/NamedLoggerContextPropertiesTest.java
index 8e8f2dea73a..a483be69a4e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/NamedLoggerContextPropertiesTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/NamedLoggerContextPropertiesTest.java
@@ -19,7 +19,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import java.net.URI;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LifeCycle;
import org.apache.logging.log4j.core.LoggerContext;
@@ -38,7 +37,7 @@ public class NamedLoggerContextPropertiesTest {
public void testProperties() {
final LoggerContext context = LoggerContext.getContext();
assertEquals(LifeCycle.State.STARTED, context.getState());
- final PropertyEnvironment props = context.getProperties();
+ final PropertyEnvironment props = context.getEnvironment();
assertNotNull(props, "Logger Context Properties were not loaded");
final String scriptLanguages = props.getStringProperty("Script.enableLanguages");
assertEquals("Groovy,JavaScript", scriptLanguages);
@@ -56,8 +55,9 @@ public TestContextSelector(final ConfigurableInstanceFactory injector) {
super(injector);
}
+ @Override
protected LoggerContext createContext() {
- return new LoggerContext("my-app", null, (URI) null, instanceFactory);
+ return createContext("my-app", null, getClass().getClassLoader());
}
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
index ab87808b5a4..09a6d89482c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
@@ -32,6 +32,8 @@
import org.apache.logging.log4j.message.FlowMessageFactory;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.util.Strings;
import org.apache.logging.log4j.util.Supplier;
@@ -802,4 +804,76 @@ public boolean equals(final Object o) {
public int hashCode() {
return getName().hashCode();
}
+
+ public static class Builder {
+ private String name;
+ /**
+ * Message factory explicitly requested by the user.
+ */
+ private @Nullable MessageFactory messageFactory;
+
+ private final LoggerContext context;
+ private final MessageFactory defaultMessageFactory;
+ private final FlowMessageFactory flowMessageFactory;
+ private final RecyclerFactory recyclerFactory;
+ private final org.apache.logging.log4j.Logger statusLogger;
+
+ @Inject
+ public Builder(
+ final LoggerContext context,
+ final MessageFactory defaultMessageFactory,
+ final FlowMessageFactory flowMessageFactory,
+ final RecyclerFactory recyclerFactory,
+ final @Named("StatusLogger") org.apache.logging.log4j.Logger statusLogger) {
+ this.context = context;
+ this.defaultMessageFactory = defaultMessageFactory;
+ this.flowMessageFactory = flowMessageFactory;
+ this.recyclerFactory = recyclerFactory;
+ this.statusLogger = statusLogger;
+ }
+
+ public Builder setName(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder setMessageFactory(final MessageFactory messageFactory) {
+ this.messageFactory = messageFactory;
+ return this;
+ }
+
+ protected LoggerContext getContext() {
+ return context;
+ }
+
+ protected String getName() {
+ return name;
+ }
+
+ protected MessageFactory getActualMessageFactory() {
+ return messageFactory != null ? messageFactory : defaultMessageFactory;
+ }
+
+ protected FlowMessageFactory getFlowMessageFactory() {
+ return flowMessageFactory;
+ }
+
+ protected RecyclerFactory getRecyclerFactory() {
+ return recyclerFactory;
+ }
+
+ protected org.apache.logging.log4j.Logger getStatusLogger() {
+ return statusLogger;
+ }
+
+ public Logger build() {
+ return new Logger(
+ getContext(),
+ getName(),
+ getActualMessageFactory(),
+ getFlowMessageFactory(),
+ getRecyclerFactory(),
+ getStatusLogger());
+ }
+ }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 53e7b30fdaf..6b2a2898c16 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -18,13 +18,14 @@
import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -35,24 +36,25 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationScheduler;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.LoggerContextAwarePostProcessor;
import org.apache.logging.log4j.core.config.NullConfiguration;
import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.core.config.URIConfigurationFactory;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.core.util.Cancellable;
-import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.core.util.ExecutorServices;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
-import org.apache.logging.log4j.message.FlowMessageFactory;
import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.InstanceFactory;
import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor;
+import org.apache.logging.log4j.plugins.util.OrderedComparator;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.spi.LoggerContextShutdownAware;
@@ -60,11 +62,12 @@
import org.apache.logging.log4j.spi.LoggerRegistry;
import org.apache.logging.log4j.spi.LoggingSystem;
import org.apache.logging.log4j.spi.Terminable;
-import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Lazy;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyEnvironment;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
+import org.jspecify.annotations.Nullable;
/**
* The LoggerContext is the anchor for the logging system. It maintains a list of all the loggers requested by
@@ -81,17 +84,18 @@ public class LoggerContext extends AbstractLifeCycle
public static final Key KEY = Key.forClass(LoggerContext.class);
private final LoggerRegistry loggerRegistry = new LoggerRegistry<>();
- private final List> configurationStartedListeners = new ArrayList<>();
- private final List> configurationStoppedListeners = new ArrayList<>();
+ private final Collection> configurationStartedListeners = new ArrayList<>();
+ private final Collection> configurationStoppedListeners = new ArrayList<>();
private final Lazy> listeners = Lazy.relaxed(CopyOnWriteArrayList::new);
private final ConfigurableInstanceFactory instanceFactory;
- private PropertiesUtil properties;
+ private final PropertyEnvironment environment;
+ private final ConfigurationScheduler configurationScheduler;
/**
* The Configuration is volatile to guarantee that initialization of the Configuration has completed before the
* reference is updated.
*/
- private volatile Configuration configuration = new DefaultConfiguration();
+ private volatile Configuration configuration;
private final Configuration nullConfiguration;
private static final String EXTERNAL_CONTEXT_KEY = "__EXTERNAL_CONTEXT_KEY__";
@@ -102,115 +106,67 @@ public class LoggerContext extends AbstractLifeCycle
private final Lock configLock = new ReentrantLock();
- /**
- * Constructor used to create an InternalLoggerContext.
- */
- protected LoggerContext() {
- setStarted();
- instanceFactory = null;
- this.nullConfiguration = null;
- }
-
- /**
- * Constructor taking only a name.
- *
- * @param name The context name.
- */
- public LoggerContext(final String name) {
- this(name, null, (URI) null);
- }
-
- /**
- * Constructor taking a name and a reference to an external context.
- *
- * @param name The context name.
- * @param externalContext The external context.
- */
- public LoggerContext(final String name, final Object externalContext) {
- this(name, externalContext, (URI) null);
- }
-
- /**
- * Constructor taking a name, external context and a configuration URI.
- *
- * @param name The context name.
- * @param externalContext The external context.
- * @param configLocn The location of the configuration as a URI.
- */
- public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
- this(name, externalContext, configLocn, DI.createInitializedFactory());
- }
-
/**
* Constructs a LoggerContext with a name, external context, configuration URI, and a ConfigurableInstanceFactory.
*
* @param name context name
* @param externalContext external context or null
- * @param configLocn location of configuration as a URI
+ * @param configLocation location of configuration as a URI
* @param instanceFactory initialized ConfigurableInstanceFactory
*/
public LoggerContext(
final String name,
- final Object externalContext,
- final URI configLocn,
+ final @Nullable Object externalContext,
+ final @Nullable URI configLocation,
final ConfigurableInstanceFactory instanceFactory) {
- this.contextName = name;
+ this.contextName = Objects.requireNonNull(name);
+ this.instanceFactory = Objects.requireNonNull(instanceFactory);
+ this.instanceFactory.registerBinding(KEY, Lazy.weak(this));
+ // Post-process the factory, after registering itself
+ ServiceLoaderUtil.safeStream(ServiceLoader.load(
+ ConfigurableInstanceFactoryPostProcessor.class, LoggerContext.class.getClassLoader()))
+ .sorted(Comparator.comparing(
+ ConfigurableInstanceFactoryPostProcessor::getClass, OrderedComparator.INSTANCE))
+ .forEachOrdered(processor -> processor.postProcessFactory(instanceFactory));
+
+ this.instanceFactory.registerInstancePostProcessor(new LoggerContextAwarePostProcessor(this));
if (externalContext != null) {
externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
}
- this.configLocation = configLocn;
- this.instanceFactory = instanceFactory.newChildInstanceFactory();
- initializeInstanceFactory();
+ this.configLocation = configLocation;
+ this.environment = instanceFactory.getInstance(PropertyEnvironment.class);
+ this.configurationScheduler = instanceFactory.getInstance(ConfigurationScheduler.class);
+
+ this.configuration = new DefaultConfiguration(this);
this.nullConfiguration = new NullConfiguration(this);
}
- /**
- * Constructor taking a name external context and a configuration location String. The location must be resolvable
- * to a File.
- *
- * @param name The configuration location.
- * @param externalContext The external context.
- * @param configLocn The configuration location.
- */
- @SuppressFBWarnings(
- value = "PATH_TRAVERSAL_IN",
- justification = "The configLocn comes from a secure source (Log4j properties)")
- public LoggerContext(final String name, final Object externalContext, final String configLocn) {
- this(name, externalContext, configLocn, DI.createInitializedFactory());
+ private static @Nullable URI fileToUri(final String fileName) {
+ if (fileName != null) {
+ try {
+ return new File(fileName).toURI();
+ } catch (final Exception ignored) {
+ // NOP
+ }
+ }
+ return null;
}
/**
* Constructs a LoggerContext with a name, external context, configuration location string, and an instance factory.
* The location must be resolvable to a File.
*
- * @param name context name
+ * @param contextName context name
* @param externalContext external context or null
- * @param configLocn configuration location
+ * @param configLocation configuration location
* @param instanceFactory initialized ConfigurableInstanceFactory
*/
public LoggerContext(
- final String name,
+ final String contextName,
final Object externalContext,
- final String configLocn,
+ final String configLocation,
final ConfigurableInstanceFactory instanceFactory) {
- this.contextName = name;
- if (externalContext != null) {
- externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
- }
- if (configLocn != null) {
- URI uri;
- try {
- uri = new File(configLocn).toURI();
- } catch (final Exception ex) {
- uri = null;
- }
- configLocation = uri;
- } else {
- configLocation = null;
- }
- this.instanceFactory = instanceFactory.newChildInstanceFactory();
- initializeInstanceFactory();
- this.nullConfiguration = new NullConfiguration(this);
+ this(contextName, externalContext, fileToUri(configLocation), instanceFactory);
}
/**
@@ -245,19 +201,9 @@ public static void checkMessageFactory(final ExtendedLogger logger, final Messag
}
}
- private void initializeInstanceFactory() {
- final Lazy ref = Lazy.weak(this);
- instanceFactory.registerBinding(KEY, ref);
- instanceFactory.registerInstancePostProcessor(new LoggerContextAwarePostProcessor(this));
- }
-
- public void setProperties(final PropertiesUtil properties) {
- this.properties = properties;
- }
-
@Override
- public PropertyEnvironment getProperties() {
- return properties;
+ public PropertyEnvironment getEnvironment() {
+ return environment;
}
@Override
@@ -357,7 +303,7 @@ public static LoggerContext getContext(
@Override
public void start() {
LOGGER.debug("Starting {}...", this);
- if (getProperties().getBooleanProperty(Log4jPropertyKey.STACKTRACE_ON_START, false)) {
+ if (getEnvironment().getBooleanProperty(Log4jPropertyKey.STACKTRACE_ON_START, false)) {
LOGGER.debug(
"Stack trace to locate invoker",
new Exception("Not a real error, showing stack trace to locate invoker"));
@@ -479,6 +425,9 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) {
shutdownCallback.cancel();
shutdownCallback = null;
}
+ if (configurationScheduler.isStarted()) {
+ configurationScheduler.stop(timeout, timeUnit);
+ }
final Configuration prev = configuration;
configuration = nullConfiguration;
updateLoggers();
@@ -618,15 +567,9 @@ public Logger getLogger(final String name, final MessageFactory messageFactory)
checkMessageFactory(logger, messageFactory);
return logger;
}
- final MessageFactory actualMessageFactory =
- messageFactory != null ? messageFactory : instanceFactory.getInstance(MessageFactory.class);
- final FlowMessageFactory flowMessageFactory = instanceFactory.getInstance(FlowMessageFactory.class);
- final RecyclerFactory recyclerFactory = instanceFactory.getInstance(RecyclerFactory.class);
- final org.apache.logging.log4j.Logger statusLogger =
- instanceFactory.getInstance(Constants.DEFAULT_STATUS_LOGGER_KEY);
- logger = newInstance(this, name, actualMessageFactory, flowMessageFactory, recyclerFactory, statusLogger);
- loggerRegistry.putIfAbsent(name, actualMessageFactory, logger);
- return loggerRegistry.getLogger(name, actualMessageFactory);
+ logger = newLogger(name, messageFactory);
+ loggerRegistry.putIfAbsent(name, logger.getMessageFactory(), logger);
+ return loggerRegistry.getLogger(name, logger.getMessageFactory());
}
/**
@@ -715,8 +658,8 @@ public Configuration getConfiguration(final String name, final URI configLocatio
return getConfigurationFactory().getConfiguration(this, name, configLocation, loader);
}
- private ConfigurationFactory getConfigurationFactory() {
- return instanceFactory.getInstance(ConfigurationFactory.KEY);
+ private URIConfigurationFactory getConfigurationFactory() {
+ return instanceFactory.getInstance(URIConfigurationFactory.KEY);
}
/**
@@ -873,34 +816,22 @@ private void reconfigure(final URI configURI) {
final Object externalContext = externalMap.get(EXTERNAL_CONTEXT_KEY);
final ClassLoader cl = externalContext instanceof ClassLoader ? (ClassLoader) externalContext : null;
LOGGER.debug("Reconfiguration started for {} at URI {} with optional ClassLoader: {}", this, configURI, cl);
- boolean setProperties = false;
- if (properties != null && !PropertiesUtil.hasThreadProperties()) {
- PropertiesUtil.setThreadProperties(properties);
- setProperties = true;
- }
- try {
- final Configuration instance = getConfiguration(contextName, configURI, cl);
- if (instance == null) {
- LOGGER.error(
- "Reconfiguration failed: No configuration found for '{}' at '{}' in '{}'",
- contextName,
- configURI,
- cl);
- } else {
- setConfiguration(instance);
- /*
- * instance.start(); Configuration old = setConfiguration(instance); updateLoggers(); if (old != null) {
- * old.stop(); }
- */
- final String location =
- configuration == null ? "?" : String.valueOf(configuration.getConfigurationSource());
- LOGGER.debug(
- "Reconfiguration complete for {} at URI {} with optional ClassLoader: {}", this, location, cl);
- }
- } finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
+ final Configuration instance = getConfiguration(contextName, configURI, cl);
+ if (instance == null) {
+ LOGGER.error(
+ "Reconfiguration failed: No configuration found for '{}' at '{}' in '{}'",
+ contextName,
+ configURI,
+ cl);
+ } else {
+ setConfiguration(instance);
+ /*
+ * instance.start(); Configuration old = setConfiguration(instance); updateLoggers(); if (old != null) {
+ * old.stop(); }
+ */
+ final String location =
+ configuration == null ? "?" : String.valueOf(configuration.getConfigurationSource());
+ LOGGER.debug("Reconfiguration complete for {} at URI {} with optional ClassLoader: {}", this, location, cl);
}
}
@@ -980,15 +911,17 @@ public String toString() {
return "LoggerContext[" + contextName + "]";
}
- // LOG4J2-151: changed visibility from private to protected
- protected Logger newInstance(
- final LoggerContext ctx,
- final String name,
- final MessageFactory messageFactory,
- final FlowMessageFactory flowMessageFactory,
- final RecyclerFactory recyclerFactory,
- final org.apache.logging.log4j.Logger statusLogger) {
- return new Logger(ctx, name, messageFactory, flowMessageFactory, recyclerFactory, statusLogger);
+ protected Class extends Logger.Builder> getLoggerBuilderClass() {
+ return Logger.Builder.class;
+ }
+
+ private Logger newLogger(final String name, final @Nullable MessageFactory messageFactory) {
+ final Logger.Builder builder =
+ instanceFactory.getInstance(getLoggerBuilderClass()).setName(name);
+ if (messageFactory != null) {
+ builder.setMessageFactory(messageFactory);
+ }
+ return builder.build();
}
/**
@@ -997,4 +930,57 @@ protected Logger newInstance(
public boolean includeLocation() {
return true;
}
+
+ public static class Builder {
+ private final ConfigurableInstanceFactory parentInstanceFactory;
+
+ private String contextName;
+ private @Nullable URI configLocation;
+ private ClassLoader loader = LoggerContext.class.getClassLoader();
+
+ @Inject
+ public Builder(final ConfigurableInstanceFactory parentInstanceFactory) {
+ this.parentInstanceFactory = parentInstanceFactory;
+ }
+
+ private PropertyEnvironment createProperties(final String contextName, final ClassLoader loader) {
+ return PropertiesUtil.getContextProperties(loader, contextName);
+ }
+
+ private ConfigurableInstanceFactory createInstanceFactory(
+ final PropertyEnvironment environment, final ClassLoader loader) {
+ return parentInstanceFactory.newChildInstanceFactory(() -> environment, () -> loader);
+ }
+
+ protected String getContextName() {
+ return contextName;
+ }
+
+ public Builder setContextName(final String contextName) {
+ this.contextName = contextName;
+ return this;
+ }
+
+ protected @Nullable URI getConfigLocation() {
+ return configLocation;
+ }
+
+ public Builder setConfigLocation(final URI configLocation) {
+ this.configLocation = configLocation;
+ return this;
+ }
+
+ public Builder setLoader(final ClassLoader loader) {
+ this.loader = loader;
+ return this;
+ }
+
+ protected ConfigurableInstanceFactory createInstanceFactory() {
+ return createInstanceFactory(createProperties(contextName, loader), loader);
+ }
+
+ public LoggerContext build() {
+ return new LoggerContext(getContextName(), null, getConfigLocation(), createInstanceFactory());
+ }
+ }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
index c3dfa9a78cb..614084161af 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
@@ -168,7 +168,7 @@ public ConsoleAppender build() {
final Configuration configuration = getConfiguration();
final PropertyEnvironment propertyEnvironment =
configuration != null && configuration.getLoggerContext() != null
- ? configuration.getLoggerContext().getProperties()
+ ? configuration.getLoggerContext().getEnvironment()
: PropertiesUtil.getProperties();
return new ConsoleAppender(
getName(),
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
index 18896aa5696..9bd613138eb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
@@ -22,7 +22,6 @@
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.LoggerFields;
import org.apache.logging.log4j.core.layout.Rfc5424Layout;
import org.apache.logging.log4j.core.layout.SyslogLayout;
@@ -113,7 +112,7 @@ public SyslogAppender build() {
if (layout == null) {
layout = RFC5424.equalsIgnoreCase(format)
? new Rfc5424Layout.Rfc5424LayoutBuilder()
- .setConfig(new DefaultConfiguration())
+ .setConfig(configuration)
.setFacility(facility)
.setId(id)
.setEin(enterpriseNumber)
@@ -131,12 +130,11 @@ public SyslogAppender build() {
.setExceptionPattern(exceptionPattern)
.setUseTLSMessageFormat(useTlsMessageFormat)
.setLoggerFields(loggerFields)
- .setConfig(configuration)
.build()
:
// @formatter:off
SyslogLayout.newBuilder()
- .setConfiguration(new DefaultConfiguration())
+ .setConfiguration(configuration)
.setFacility(facility)
.setIncludeNewLine(newLine)
.setEscapeNL(escapeNL)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
index 316551eca7b..24f415b56bf 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
@@ -145,7 +145,7 @@ public DefaultRolloverStrategy build() {
final String trimmedCompressionLevelStr =
compressionLevelStr != null ? compressionLevelStr.trim() : compressionLevelStr;
final int compressionLevel = Integers.parseInt(trimmedCompressionLevelStr, Deflater.DEFAULT_COMPRESSION);
- // The config object can be null when this object is built programmatically.
+ // The config object can be null only in tests
final Configuration configuration = config != null ? config : new NullConfiguration();
final StrSubstitutor nonNullStrSubstitutor = configuration.getStrSubstitutor();
return new DefaultRolloverStrategy(
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 189a1b8e5c9..d895437054f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -22,6 +22,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -72,21 +73,25 @@
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor;
import org.apache.logging.log4j.plugins.di.spi.StringValueResolver;
import org.apache.logging.log4j.plugins.model.PluginNamespace;
import org.apache.logging.log4j.plugins.model.PluginType;
+import org.apache.logging.log4j.plugins.util.OrderedComparator;
import org.apache.logging.log4j.util.Cast;
import org.apache.logging.log4j.util.Lazy;
import org.apache.logging.log4j.util.NameUtil;
-import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyEnvironment;
import org.apache.logging.log4j.util.ServiceLoaderUtil;
+import org.apache.logging.log4j.util.Strings;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
/**
* The base Configuration. Many configuration implementations will extend this class.
*/
+@NullMarked
@ServiceConsumer(value = ScriptManagerFactory.class, cardinality = Cardinality.SINGLE, resolution = Resolution.OPTIONAL)
public abstract class AbstractConfiguration extends AbstractFilterable implements Configuration {
@@ -151,13 +156,13 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
private final Interpolator tempLookup;
private final StrSubstitutor runtimeStrSubstitutor;
private final StrSubstitutor configurationStrSubstitutor;
- private LoggerConfig root = new LoggerConfig();
+ private LoggerConfig root;
private final ConcurrentMap componentMap = new ConcurrentHashMap<>();
private final ConfigurationSource configurationSource;
private final ConfigurationScheduler configurationScheduler;
private final WatchManager watchManager;
private final WeakReference loggerContext;
- private final PropertyEnvironment contextProperties;
+ private final PropertyEnvironment environment;
private final Lock configLock = new ReentrantLock();
private final List extensions = new CopyOnWriteArrayList<>();
@@ -165,30 +170,43 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
* Constructor.
*/
protected AbstractConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
+ this(
+ Objects.requireNonNull(loggerContext),
+ configurationSource,
+ loggerContext.getEnvironment(),
+ (ConfigurableInstanceFactory) loggerContext.getInstanceFactory());
+ }
+
+ protected AbstractConfiguration(
+ final @Nullable LoggerContext loggerContext,
+ final ConfigurationSource configurationSource,
+ final PropertyEnvironment environment,
+ final ConfigurableInstanceFactory parentInstanceFactory) {
this.loggerContext = new WeakReference<>(loggerContext);
- // The loggerContext is null for the NullConfiguration class.
- // this.loggerContext = new WeakReference(Objects.requireNonNull(loggerContext, "loggerContext is null"));
this.configurationSource = Objects.requireNonNull(configurationSource, "configurationSource is null");
- if (loggerContext != null) {
- instanceFactory = loggerContext.newChildInstanceFactory();
- this.contextProperties = loggerContext.getProperties();
- } else {
- // for NullConfiguration
- instanceFactory = DI.createInitializedFactory();
- this.contextProperties = PropertiesUtil.getProperties();
- }
+ // The scheduler is shared by all configurations
+ this.configurationScheduler = parentInstanceFactory.getInstance(ConfigurationScheduler.class);
+ this.environment = environment;
+ this.instanceFactory = parentInstanceFactory.newChildInstanceFactory();
+ this.watchManager = new WatchManager(configurationScheduler);
+
configurationProcessor = new ConfigurationProcessor(instanceFactory);
- final var ref = Lazy.weak(this);
- instanceFactory.registerBinding(Configuration.KEY, ref);
- instanceFactory.registerInstancePostProcessor(new ConfigurationAwarePostProcessor(ref));
+ instanceFactory.registerBinding(Configuration.KEY, Lazy.weak(this));
+ ServiceLoaderUtil.safeStream(ServiceLoader.load(
+ ConfigurableInstanceFactoryPostProcessor.class, AbstractConfiguration.class.getClassLoader()))
+ .sorted(Comparator.comparing(
+ ConfigurableInstanceFactoryPostProcessor::getClass, OrderedComparator.INSTANCE))
+ .forEachOrdered(processor -> processor.postProcessFactory(instanceFactory));
+
+ instanceFactory.registerInstancePostProcessor(new ConfigurationAwarePostProcessor(Lazy.weak(this)));
componentMap.put(Configuration.CONTEXT_PROPERTIES, properties);
interpolatorFactory = instanceFactory.getInstance(InterpolatorFactory.class);
tempLookup = interpolatorFactory.newInterpolator(new PropertiesLookup(properties));
instanceFactory.injectMembers(tempLookup);
runtimeStrSubstitutor = new RuntimeStrSubstitutor(tempLookup);
configurationStrSubstitutor = new ConfigurationStrSubstitutor(runtimeStrSubstitutor);
- configurationScheduler = instanceFactory.getInstance(ConfigurationScheduler.class);
- watchManager = instanceFactory.getInstance(WatchManager.class);
+ // Root logger
+ root = new LoggerConfig(Strings.EMPTY, Level.ERROR, true, this);
setState(State.INITIALIZING);
}
@@ -202,9 +220,13 @@ public Map getProperties() {
return properties;
}
+ protected ConfigurableInstanceFactory getInstanceFactory() {
+ return instanceFactory;
+ }
+
@Override
- public PropertyEnvironment getContextProperties() {
- return contextProperties;
+ public PropertyEnvironment getEnvironment() {
+ return environment;
}
@Override
@@ -527,6 +549,11 @@ public Supplier getFactory(final Key key) {
return instanceFactory.getFactory(key);
}
+ @Override
+ public void setComponent(final Key key, final Supplier extends T> supplier) {
+ instanceFactory.registerBinding(key, supplier);
+ }
+
@Override
public void addComponent(final String componentName, final Object obj) {
componentMap.putIfAbsent(componentName, obj);
@@ -755,7 +782,7 @@ protected void setToDefault() {
addAppender(appender);
final LoggerConfig rootLoggerConfig = getRootLogger();
rootLoggerConfig.addAppender(appender, null, null);
- final String defaultLevelName = contextProperties.getStringProperty(Log4jPropertyKey.CONFIG_DEFAULT_LEVEL);
+ final String defaultLevelName = environment.getStringProperty(Log4jPropertyKey.CONFIG_DEFAULT_LEVEL);
final Level defaultLevel = Level.toLevel(defaultLevelName, Level.ERROR);
rootLoggerConfig.setLevel(defaultLevel);
}
@@ -860,7 +887,9 @@ public Advertiser getAdvertiser() {
*/
@Override
public ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) {
- return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig);
+ final String strategy =
+ getEnvironment().getStringProperty(Log4jPropertyKey.CONFIG_RELIABILITY_STRATEGY, "AwaitCompletion");
+ return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig, strategy);
}
/**
@@ -885,7 +914,9 @@ public void addLoggerAppender(final org.apache.logging.log4j.core.Logger logger,
if (lc.getName().equals(loggerName)) {
lc.addAppender(appender, null, null);
} else {
- final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive());
+ final Level level = lc.getLevel();
+ final boolean additivity = lc.isAdditive();
+ final LoggerConfig nlc = new LoggerConfig(loggerName, level, additivity, this);
nlc.addAppender(appender, null, null);
nlc.setParent(lc);
loggerConfigs.putIfAbsent(loggerName, nlc);
@@ -915,7 +946,9 @@ public void addLoggerFilter(final org.apache.logging.log4j.core.Logger logger, f
if (lc.getName().equals(loggerName)) {
lc.addFilter(filter);
} else {
- final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive());
+ final Level level = lc.getLevel();
+ final boolean additivity = lc.isAdditive();
+ final LoggerConfig nlc = new LoggerConfig(loggerName, level, additivity, this);
nlc.addFilter(filter);
nlc.setParent(lc);
loggerConfigs.putIfAbsent(loggerName, nlc);
@@ -945,7 +978,8 @@ public void setLoggerAdditive(final org.apache.logging.log4j.core.Logger logger,
if (lc.getName().equals(loggerName)) {
lc.setAdditive(additive);
} else {
- final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), additive);
+ final Level level = lc.getLevel();
+ final LoggerConfig nlc = new LoggerConfig(loggerName, level, additive, this);
nlc.setParent(lc);
loggerConfigs.putIfAbsent(loggerName, nlc);
setParents();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
index c082d5c2bc4..86ca98e64c3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
@@ -111,12 +111,12 @@ public interface Configuration extends Filterable {
Map getProperties();
/**
- * Returns the {@linkplain org.apache.logging.log4j.spi.LoggerContext#getProperties() context properties}
+ * Returns the {@linkplain org.apache.logging.log4j.spi.LoggerContext#getEnvironment() context properties}
* associated with the logger context for this configuration.
*
* @return the context properties
*/
- PropertyEnvironment getContextProperties();
+ PropertyEnvironment getEnvironment();
/**
* Returns the root Logger.
@@ -149,6 +149,8 @@ default T getComponent(Key key) {
return getFactory(key).get();
}
+ void setComponent(Key key, Supplier extends T> supplier);
+
void addComponent(String name, Object object);
void setAdvertiser(Advertiser advertiser);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
index 493638450f8..d145f71c968 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
@@ -29,7 +29,6 @@
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.PropertyEnvironment;
import org.apache.logging.log4j.util.PropertyKey;
/**
@@ -52,12 +51,7 @@
* be called in their respective order. DefaultConfiguration is always called
* last if no configuration has been returned.
*/
-public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
-
- public ConfigurationFactory() {
- super();
- // TEMP For breakpoints
- }
+public abstract class ConfigurationFactory extends ConfigurationBuilderFactory implements URIConfigurationFactory {
public static final PropertyKey LOG4J1_CONFIGURATION_FILE_PROPERTY = Log4jPropertyKey.CONFIG_V1_FILE_NAME;
@@ -91,7 +85,6 @@ public ConfigurationFactory() {
protected static final String DEFAULT_PREFIX = "log4j2";
protected static final String LOG4J1_VERSION = "1";
- protected static final String LOG4J2_VERSION = "2";
/**
* The name of the classloader URI scheme.
@@ -105,20 +98,9 @@ public ConfigurationFactory() {
protected abstract String[] getSupportedTypes();
- protected String getTestPrefix() {
- return TEST_PREFIX;
- }
-
- protected String getDefaultPrefix() {
- return DEFAULT_PREFIX;
- }
-
- protected String getVersion() {
- return LOG4J2_VERSION;
- }
-
- protected boolean isActive() {
- return true;
+ @Override
+ public String[] getSupportedExtensions() {
+ return getSupportedTypes();
}
@Deprecated(since = "3.0.0", forRemoval = true)
@@ -132,10 +114,23 @@ public static ConfigurationFactory getInstance() {
* @return the AuthorizationProvider, if any.
*/
public static AuthorizationProvider authorizationProvider(final PropertiesUtil props) {
- return AuthorizationProvider.getAuthorizationProvider((PropertyEnvironment) props);
+ return AuthorizationProvider.getAuthorizationProvider(props);
}
- public abstract Configuration getConfiguration(final LoggerContext loggerContext, ConfigurationSource source);
+ @Override
+ public String getTestPrefix() {
+ return TEST_PREFIX;
+ }
+
+ @Override
+ public String getDefaultPrefix() {
+ return DEFAULT_PREFIX;
+ }
+
+ @Override
+ public String getVersion() {
+ return LOG4J2_VERSION;
+ }
/**
* Returns the Configuration.
@@ -144,11 +139,9 @@ public static AuthorizationProvider authorizationProvider(final PropertiesUtil p
* @param configLocation The configuration location.
* @return The Configuration.
*/
+ @Override
public Configuration getConfiguration(
final LoggerContext loggerContext, final String name, final URI configLocation) {
- if (!isActive()) {
- return null;
- }
if (configLocation != null) {
final ConfigurationSource source = ConfigurationSource.fromUri(configLocation);
if (source != null) {
@@ -168,11 +161,9 @@ public Configuration getConfiguration(
*
* @return The Configuration.
*/
+ @Override
public Configuration getConfiguration(
final LoggerContext loggerContext, final String name, final URI configLocation, final ClassLoader loader) {
- if (!isActive()) {
- return null;
- }
if (loader == null) {
return getConfiguration(loggerContext, name, configLocation);
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
index fcd235ee674..69a43e8f882 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
@@ -226,7 +226,10 @@ public void setScheduledFuture(final CronScheduledFuture> future) {
@Override
public void run() {
try {
- final long millis = scheduledFuture.getFireTime().getTime() - System.currentTimeMillis();
+ final CronScheduledFuture> scheduledFuture = this.scheduledFuture;
+ final long millis = scheduledFuture != null
+ ? scheduledFuture.getFireTime().getTime() - System.currentTimeMillis()
+ : 0L;
if (millis > 0) {
LOGGER.debug("{} Cron thread woke up {} millis early. Sleeping", name, millis);
try {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
index 76eeabef888..410fe25f0fa 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
@@ -434,7 +434,7 @@ private static boolean setLevel(final String loggerName, final Level level, fina
LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
if (!loggerName.equals(loggerConfig.getName())) {
// TODO Should additivity be inherited?
- loggerConfig = new LoggerConfig(loggerName, level, true);
+ loggerConfig = new LoggerConfig(loggerName, level, true, config);
config.addLogger(loggerName, loggerConfig);
loggerConfig.setLevel(level);
set = true;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
index 6e0b7be8e0e..607c971ecdf 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
@@ -16,6 +16,10 @@
*/
package org.apache.logging.log4j.core.config;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
/**
* The default configuration writes all output to the Console using the default logging level. You configure default
* logging level by setting the system property "org.apache.logging.log4j.level" to a level name. If you do not
@@ -35,10 +39,19 @@ public class DefaultConfiguration extends AbstractConfiguration {
public static final String DEFAULT_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
/**
- * Constructor to create the default configuration.
+ * Only for tests.
*/
+ @Deprecated
public DefaultConfiguration() {
- super(null, ConfigurationSource.NULL_SOURCE);
+ super(null, ConfigurationSource.NULL_SOURCE, PropertiesUtil.getProperties(), DI.createInitializedFactory());
+ setToDefault();
+ }
+
+ /**
+ * Constructor to create the default configuration.
+ */
+ public DefaultConfiguration(final LoggerContext loggerContext) {
+ super(loggerContext, ConfigurationSource.NULL_SOURCE);
setToDefault();
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java
index 47fe7133dae..2011816c849 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfigurationFactory.java
@@ -27,13 +27,12 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
+import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.plugins.Inject;
-import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.InstanceFactory;
import org.apache.logging.log4j.spi.LoggingSystemProperty;
-import org.apache.logging.log4j.util.Lazy;
import org.apache.logging.log4j.util.LoaderUtil;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyEnvironment;
@@ -47,16 +46,6 @@ public class DefaultConfigurationFactory extends ConfigurationFactory {
private static final String ALL_TYPES = "*";
private static final String OVERRIDE_PARAM = "override";
- private final Lazy> configurationFactories;
- private final StrSubstitutor substitutor;
-
- @Inject
- public DefaultConfigurationFactory(
- final ConfigurableInstanceFactory instanceFactory, final StrSubstitutor substitutor) {
- configurationFactories = Lazy.lazy(() -> loadConfigurationFactories(instanceFactory));
- this.substitutor = substitutor;
- }
-
/**
* Default Factory Constructor.
*
@@ -67,9 +56,11 @@ public DefaultConfigurationFactory(
@Override
public Configuration getConfiguration(
final LoggerContext loggerContext, final String name, final URI configLocation) {
-
+ final InstanceFactory instanceFactory = loggerContext.getInstanceFactory();
+ final List configurationFactories = loadConfigurationFactories(instanceFactory);
+ final StrSubstitutor substitutor = instanceFactory.getInstance(ConfigurationStrSubstitutor.class);
if (configLocation == null) {
- PropertyEnvironment properties = loggerContext.getProperties();
+ PropertyEnvironment properties = loggerContext.getEnvironment();
if (properties == null) {
properties = PropertiesUtil.getProperties();
}
@@ -80,7 +71,8 @@ public Configuration getConfiguration(
if (sources.length > 1) {
final List configs = new ArrayList<>();
for (final String sourceLocation : sources) {
- final Configuration config = getConfiguration(loggerContext, sourceLocation.trim());
+ final Configuration config =
+ getConfiguration(null, loggerContext, sourceLocation.trim(), configurationFactories);
if (config != null) {
if (config instanceof AbstractConfiguration) {
configs.add((AbstractConfiguration) config);
@@ -93,22 +85,22 @@ public Configuration getConfiguration(
}
}
if (configs.size() > 1) {
- return new CompositeConfiguration(configs);
+ return new CompositeConfiguration(loggerContext, configs);
} else if (configs.size() == 1) {
return configs.get(0);
}
}
- return getConfiguration(loggerContext, configLocationStr);
+ return getConfiguration(null, loggerContext, configLocationStr, configurationFactories);
} else {
final String log4j1ConfigStr =
substitutor.replace(properties.getStringProperty(LOG4J1_CONFIGURATION_FILE_PROPERTY));
if (log4j1ConfigStr != null) {
System.setProperty(LOG4J1_EXPERIMENTAL.getSystemKey(), "true");
- return getConfiguration(LOG4J1_VERSION, loggerContext, log4j1ConfigStr);
+ return getConfiguration(LOG4J1_VERSION, loggerContext, log4j1ConfigStr, configurationFactories);
}
}
- for (final ConfigurationFactory factory : configurationFactories.get()) {
- final String[] types = factory.getSupportedTypes();
+ for (final URIConfigurationFactory factory : configurationFactories) {
+ final String[] types = factory.getSupportedExtensions();
if (types != null) {
for (final String type : types) {
if (type.equals(ALL_TYPES)) {
@@ -126,7 +118,8 @@ public Configuration getConfiguration(
if (sources.length > 1) {
final List configs = new ArrayList<>();
for (final String sourceLocation : sources) {
- final Configuration config = getConfiguration(loggerContext, sourceLocation.trim());
+ final Configuration config =
+ getConfiguration(null, loggerContext, sourceLocation.trim(), configurationFactories);
if (config instanceof AbstractConfiguration) {
configs.add((AbstractConfiguration) config);
} else {
@@ -134,11 +127,11 @@ public Configuration getConfiguration(
return null;
}
}
- return new CompositeConfiguration(configs);
+ return new CompositeConfiguration(loggerContext, configs);
}
final String configLocationStr = configLocation.toString();
- for (final ConfigurationFactory factory : configurationFactories.get()) {
- final String[] types = factory.getSupportedTypes();
+ for (final URIConfigurationFactory factory : configurationFactories) {
+ final String[] types = factory.getSupportedExtensions();
if (types != null) {
for (final String type : types) {
if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) {
@@ -152,13 +145,13 @@ public Configuration getConfiguration(
}
}
- Configuration config = getConfiguration(loggerContext, true, name);
+ Configuration config = getConfiguration(loggerContext, true, name, configurationFactories);
if (config == null) {
- config = getConfiguration(loggerContext, true, null);
+ config = getConfiguration(loggerContext, true, null, configurationFactories);
if (config == null) {
- config = getConfiguration(loggerContext, false, name);
+ config = getConfiguration(loggerContext, false, name, configurationFactories);
if (config == null) {
- config = getConfiguration(loggerContext, false, null);
+ config = getConfiguration(loggerContext, false, null, configurationFactories);
}
}
}
@@ -173,31 +166,30 @@ public Configuration getConfiguration(
+ "to show Log4j 2 internal initialization logging. "
+ "See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2",
LoggingSystemProperty.STATUS_LOGGER_DEBUG);
- return new DefaultConfiguration();
- }
-
- private Configuration getConfiguration(final LoggerContext loggerContext, final String configLocationStr) {
- return getConfiguration(null, loggerContext, configLocationStr);
+ return new DefaultConfiguration(loggerContext);
}
private Configuration getConfiguration(
- final String requiredVersion, final LoggerContext loggerContext, final String configLocationStr) {
+ final String requiredVersion,
+ final LoggerContext loggerContext,
+ final String configLocation,
+ final Iterable extends URIConfigurationFactory> configurationFactories) {
ConfigurationSource source = null;
try {
- source = ConfigurationSource.fromUri(NetUtils.toURI(configLocationStr));
+ source = ConfigurationSource.fromUri(NetUtils.toURI(configLocation));
} catch (final Exception ex) {
// Ignore the error and try as a String.
LOGGER.catching(Level.DEBUG, ex);
}
if (source != null) {
- for (final ConfigurationFactory factory : configurationFactories.get()) {
+ for (final URIConfigurationFactory factory : configurationFactories) {
if (requiredVersion != null && !factory.getVersion().equals(requiredVersion)) {
continue;
}
- final String[] types = factory.getSupportedTypes();
+ final String[] types = factory.getSupportedExtensions();
if (types != null) {
for (final String type : types) {
- if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) {
+ if (type.equals(ALL_TYPES) || configLocation.endsWith(type)) {
final Configuration config = factory.getConfiguration(loggerContext, source);
if (config != null) {
return config;
@@ -210,13 +202,17 @@ private Configuration getConfiguration(
return null;
}
- private Configuration getConfiguration(final LoggerContext loggerContext, final boolean isTest, final String name) {
+ private Configuration getConfiguration(
+ final LoggerContext loggerContext,
+ final boolean isTest,
+ final CharSequence name,
+ final Iterable extends URIConfigurationFactory> configurationFactories) {
final boolean named = Strings.isNotEmpty(name);
final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
- for (final ConfigurationFactory factory : configurationFactories.get()) {
+ for (final URIConfigurationFactory factory : configurationFactories) {
String configName;
final String prefix = isTest ? factory.getTestPrefix() : factory.getDefaultPrefix();
- final String[] types = factory.getSupportedTypes();
+ final String[] types = factory.getSupportedExtensions();
if (types == null) {
continue;
}
@@ -229,13 +225,15 @@ private Configuration getConfiguration(final LoggerContext loggerContext, final
final ConfigurationSource source = ConfigurationSource.fromResource(configName, loader);
if (source != null) {
- if (!factory.isActive()) {
+ try {
+ return factory.getConfiguration(loggerContext, source);
+ } catch (final LinkageError e) {
LOGGER.warn(
- "Found configuration file {} for inactive ConfigurationFactory {}",
- configName,
- factory.getClass().getName());
+ "Failed to create configuration from resource {} using {}.",
+ source,
+ factory.getClass().getName(),
+ e);
}
- return factory.getConfiguration(loggerContext, source);
}
}
}
@@ -243,16 +241,18 @@ private Configuration getConfiguration(final LoggerContext loggerContext, final
}
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return null;
}
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
if (source != null) {
+ final List configurationFactories =
+ loadConfigurationFactories(loggerContext.getInstanceFactory());
final String config = source.getLocation();
- for (final ConfigurationFactory factory : configurationFactories.get()) {
- final String[] types = factory.getSupportedTypes();
+ for (final URIConfigurationFactory factory : configurationFactories) {
+ final String[] types = factory.getSupportedExtensions();
if (types != null) {
for (final String type : types) {
if (type.equals(ALL_TYPES) || config != null && config.endsWith(type)) {
@@ -303,11 +303,11 @@ private String[] parseConfigLocations(final String configLocations) {
return new String[] {configLocations};
}
- private static List loadConfigurationFactories(
- final ConfigurableInstanceFactory instanceFactory) {
- final List factories = new ArrayList<>();
+ private static List loadConfigurationFactories(final InstanceFactory instanceFactory) {
+ final List factories = new ArrayList<>();
- Optional.ofNullable(PropertiesUtil.getProperties()
+ Optional.ofNullable(instanceFactory
+ .getInstance(PropertyEnvironment.class)
.getStringProperty(Log4jPropertyKey.CONFIG_CONFIGURATION_FACTORY_CLASS_NAME))
.flatMap(DefaultConfigurationFactory::tryLoadFactoryClass)
.map(clazz -> {
@@ -320,10 +320,10 @@ private static List loadConfigurationFactories(
})
.ifPresent(factories::add);
- final List> configurationFactoryPluginClasses = new ArrayList<>();
+ final List> configurationFactoryPluginClasses = new ArrayList<>();
instanceFactory.getInstance(PLUGIN_NAMESPACE_KEY).forEach(type -> {
try {
- configurationFactoryPluginClasses.add(type.getPluginClass().asSubclass(ConfigurationFactory.class));
+ configurationFactoryPluginClasses.add(type.getPluginClass().asSubclass(URIConfigurationFactory.class));
} catch (final Exception ex) {
LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex);
}
@@ -340,7 +340,7 @@ private static List loadConfigurationFactories(
return factories;
}
- private static Optional> tryLoadFactoryClass(final String factoryClass) {
+ private static Optional> tryLoadFactoryClass(final String factoryClass) {
try {
return Optional.of(Loader.loadClass(factoryClass).asSubclass(ConfigurationFactory.class));
} catch (final Exception ex) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
index 1fa925a824c..2b7bcd5c253 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
@@ -62,7 +62,7 @@ public HttpWatcher(
final List> configurationListeners,
final long lastModifiedMillis) {
super(configuration, reconfigurable, configurationListeners);
- properties = configuration.getContextProperties();
+ properties = configuration.getEnvironment();
sslConfiguration = SslConfigurationFactory.getSslConfiguration(properties);
authorizationProvider = AuthorizationProvider.getAuthorizationProvider(properties);
this.lastModifiedMillis = lastModifiedMillis;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index ab9930c633b..046364b7aae 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -18,6 +18,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
@@ -32,21 +33,20 @@
import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.LogEventFactory;
-import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.plugins.Configurable;
-import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginAttribute;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginElement;
import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.plugins.validation.constraints.Required;
import org.apache.logging.log4j.util.PerformanceSensitive;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.Strings;
+import org.jspecify.annotations.Nullable;
/**
* Logger object that is created via configuration.
@@ -56,6 +56,7 @@
public class LoggerConfig extends AbstractFilterable {
public static final String ROOT = "root";
+ static Key KEY = Key.forClass(LoggerConfig.class).withQualifierType(PluginElement.class);
private List appenderRefs = new ArrayList<>();
private final AppenderControlArraySet appenders = new AppenderControlArraySet();
@@ -86,20 +87,19 @@ public static class Builder>
implements org.apache.logging.log4j.plugins.util.Builder {
@PluginBuilderAttribute
- private Boolean additivity;
+ private boolean additivity = true;
private Level level;
private String levelAndRefs;
private String loggerName;
- private String includeLocation;
+ private @Nullable Boolean includeLocation;
private AppenderRef[] refs;
private Property[] properties;
private Configuration config;
private Filter filter;
- private LogEventFactory logEventFactory;
public boolean isAdditivity() {
- return additivity == null || additivity;
+ return additivity;
}
public B setAdditivity(final boolean additivity) {
@@ -135,15 +135,21 @@ public B setLoggerName(
return asBuilder();
}
- public String getIncludeLocation() {
+ public @Nullable Boolean getIncludeLocation() {
return includeLocation;
}
- public B setIncludeLocation(@PluginAttribute final String includeLocation) {
+ public B setIncludeLocation(final @Nullable Boolean includeLocation) {
this.includeLocation = includeLocation;
return asBuilder();
}
+ // TODO: remove this once https://github.com/apache/logging-log4j2/pull/2329 is solved.
+ @Deprecated
+ public B setIncludeLocation(final @PluginAttribute @Nullable String includeLocation) {
+ return setIncludeLocation(includeLocation != null ? Boolean.valueOf(includeLocation) : null);
+ }
+
public AppenderRef[] getRefs() {
return refs;
}
@@ -180,31 +186,13 @@ public B setFilter(@PluginElement final Filter filter) {
return asBuilder();
}
- public LogEventFactory getLogEventFactory() {
- return logEventFactory;
- }
-
- @Inject
- public B setLogEventFactory(final LogEventFactory logEventFactory) {
- this.logEventFactory = logEventFactory;
- return asBuilder();
- }
-
@Override
public LoggerConfig build() {
final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
final LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, config);
- final boolean useLocation = includeLocation(includeLocation, config);
+ final boolean useLocation = includeLocation(getIncludeLocation(), config);
return new LoggerConfig(
- name,
- container.refs,
- filter,
- container.level,
- isAdditivity(),
- properties,
- config,
- useLocation,
- logEventFactory);
+ name, container.refs, filter, container.level, isAdditivity(), properties, config, useLocation);
}
@SuppressWarnings("unchecked")
@@ -213,19 +201,6 @@ public B asBuilder() {
}
}
- /**
- * Default constructor.
- */
- public LoggerConfig() {
- this.logEventFactory = DI.createInitializedFactory().getInstance(ReusableLogEventFactory.class);
- this.level = Level.ERROR;
- this.name = Strings.EMPTY;
- this.properties = null;
- this.propertiesRequireLookup = false;
- this.config = null;
- this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
- }
-
/**
* Constructor that sets the name, level and additive values.
*
@@ -233,15 +208,8 @@ public LoggerConfig() {
* @param level The Level.
* @param additive true if the Logger is additive, false otherwise.
*/
- public LoggerConfig(final String name, final Level level, final boolean additive) {
- this.logEventFactory = DI.createInitializedFactory().getInstance(ReusableLogEventFactory.class);
- this.name = name;
- this.level = level;
- this.additive = additive;
- this.properties = null;
- this.propertiesRequireLookup = false;
- this.config = null;
- this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
+ public LoggerConfig(final String name, final Level level, final boolean additive, final Configuration config) {
+ this(name, Collections.emptyList(), null, level, additive, null, config, includeLocation(null, config));
}
protected LoggerConfig(
@@ -252,12 +220,9 @@ protected LoggerConfig(
final boolean additive,
final Property[] properties,
final Configuration config,
- final boolean includeLocation,
- final LogEventFactory logEventFactory) {
+ final boolean includeLocation) {
super(filter, null);
- this.logEventFactory = logEventFactory != null
- ? logEventFactory
- : DI.createInitializedFactory().getInstance(ReusableLogEventFactory.class);
+ this.logEventFactory = config.getLogEventFactory();
this.name = name;
this.appenderRefs = appenders;
this.level = level;
@@ -669,17 +634,12 @@ public String toString() {
// Note: for asynchronous loggers, includeLocation default is FALSE,
// for synchronous loggers, includeLocation default is TRUE.
- protected static boolean includeLocation(
- final String includeLocationConfigValue, final Configuration configuration) {
- if (includeLocationConfigValue == null) {
- if (configuration != null) {
- final LoggerContext context = configuration.getLoggerContext();
- return context != null ? context.includeLocation() : false;
- } else {
- return false;
- }
+ protected static boolean includeLocation(final Boolean configuredValue, final Configuration configuration) {
+ if (configuredValue == null) {
+ final LoggerContext context = configuration.getLoggerContext();
+ return context != null && context.includeLocation();
}
- return Boolean.parseBoolean(includeLocationConfigValue);
+ return configuredValue;
}
protected final boolean hasAppenders() {
@@ -691,112 +651,101 @@ protected final boolean hasAppenders() {
*/
@Configurable(printObject = true)
@Plugin(ROOT)
- public static class RootLogger extends LoggerConfig {
+ public static final class RootLogger extends LoggerConfig {
@PluginFactory
- public static > B newRootBuilder() {
- return new Builder().asBuilder();
+ public static Builder newRootBuilder() {
+ return new Builder();
+ }
+
+ private RootLogger() {
+ super(Strings.EMPTY, Level.ERROR, false, null);
}
/**
* Builds LoggerConfig instances.
- *
- * @param
* The type to build
*/
- public static class Builder>
- implements org.apache.logging.log4j.plugins.util.Builder {
+ public static class Builder implements org.apache.logging.log4j.plugins.util.Builder {
+
+ protected static final boolean ADDITIVITY = true;
- private boolean additivity;
private Level level;
private String levelAndRefs;
- private String includeLocation;
+ // TODO: Change to Boolean, once the DI starts supporting null Booleans.
+ private @Nullable Boolean includeLocation;
private AppenderRef[] refs;
private Property[] properties;
private Configuration config;
private Filter filter;
- private LogEventFactory logEventFactory;
-
- public boolean isAdditivity() {
- return additivity;
- }
-
- public B setAdditivity(@PluginAttribute final boolean additivity) {
- this.additivity = additivity;
- return asBuilder();
- }
public Level getLevel() {
return level;
}
- public B setLevel(@PluginAttribute final Level level) {
+ public Builder setLevel(@PluginAttribute final Level level) {
this.level = level;
- return asBuilder();
+ return this;
}
public String getLevelAndRefs() {
return levelAndRefs;
}
- public B setLevelAndRefs(@PluginAttribute final String levelAndRefs) {
+ public Builder setLevelAndRefs(@PluginAttribute final String levelAndRefs) {
this.levelAndRefs = levelAndRefs;
- return asBuilder();
+ return this;
}
- public String getIncludeLocation() {
+ public @Nullable Boolean getIncludeLocation() {
return includeLocation;
}
- public B setIncludeLocation(@PluginAttribute final String includeLocation) {
+ public Builder setIncludeLocation(final @Nullable Boolean includeLocation) {
this.includeLocation = includeLocation;
- return asBuilder();
+ return this;
+ }
+
+ // TODO: remove this once https://github.com/apache/logging-log4j2/pull/2329 is solved.
+ @Deprecated
+ public Builder setIncludeLocation(final @PluginAttribute @Nullable String includeLocation) {
+ return setIncludeLocation(includeLocation != null ? Boolean.valueOf(includeLocation) : null);
}
public AppenderRef[] getRefs() {
return refs;
}
- public B setRefs(@PluginElement final AppenderRef[] refs) {
+ public Builder setRefs(@PluginElement final AppenderRef[] refs) {
this.refs = refs;
- return asBuilder();
+ return this;
}
public Property[] getProperties() {
return properties;
}
- public B setProperties(@PluginElement final Property[] properties) {
+ public Builder setProperties(@PluginElement final Property[] properties) {
this.properties = properties;
- return asBuilder();
+ return this;
}
public Configuration getConfig() {
return config;
}
- public B setConfig(@PluginConfiguration final Configuration config) {
+ public Builder setConfig(@PluginConfiguration final Configuration config) {
this.config = config;
- return asBuilder();
+ return this;
}
public Filter getFilter() {
return filter;
}
- public B setFilter(@PluginElement final Filter filter) {
+ public Builder setFilter(@PluginElement final Filter filter) {
this.filter = filter;
- return asBuilder();
- }
-
- public LogEventFactory getLogEventFactory() {
- return logEventFactory;
- }
-
- @Inject
- public B setLogEventFactory(final LogEventFactory logEventFactory) {
- this.logEventFactory = logEventFactory;
- return asBuilder();
+ return this;
}
@Override
@@ -807,16 +756,10 @@ public LoggerConfig build() {
container.refs,
filter,
container.level,
- additivity,
+ ADDITIVITY,
properties,
config,
- includeLocation(includeLocation, config),
- logEventFactory);
- }
-
- @SuppressWarnings("unchecked")
- public B asBuilder() {
- return (B) this;
+ includeLocation(getIncludeLocation(), config));
}
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java
index 3384b42fd67..fa95c0c8aa7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/NullConfiguration.java
@@ -18,6 +18,8 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.util.PropertiesUtil;
/**
* This configuration defaults to no logging.
@@ -29,8 +31,15 @@ public class NullConfiguration extends AbstractConfiguration {
*/
public static final String NULL_NAME = "Null";
+ /**
+ * Used only in tests
+ */
+ @Deprecated
public NullConfiguration() {
- this(null);
+ super(null, ConfigurationSource.NULL_SOURCE, PropertiesUtil.getProperties(), DI.createInitializedFactory());
+ setName(NULL_NAME);
+ final LoggerConfig root = getRootLogger();
+ root.setLevel(Level.OFF);
}
public NullConfiguration(final LoggerContext loggerContext) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java
index 3b6e7b459b5..9bfa18ababb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategyFactory.java
@@ -44,9 +44,13 @@ private ReliabilityStrategyFactory() {}
* configuration change
*/
public static ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) {
+ return getReliabilityStrategy(
+ loggerConfig,
+ PropertiesUtil.getProperties()
+ .getStringProperty(Log4jPropertyKey.CONFIG_RELIABILITY_STRATEGY, "AwaitCompletion"));
+ }
- final String strategy = PropertiesUtil.getProperties()
- .getStringProperty(Log4jPropertyKey.CONFIG_RELIABILITY_STRATEGY, "AwaitCompletion");
+ static ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig, final String strategy) {
if ("AwaitCompletion".equals(strategy)) {
return new AwaitCompletionReliabilityStrategy(loggerConfig);
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/URIConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/URIConfigurationFactory.java
new file mode 100644
index 00000000000..9c9f631b372
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/URIConfigurationFactory.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.config;
+
+import java.net.URI;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.plugins.di.Key;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Creates configuration from an {@link URI}.
+ */
+public interface URIConfigurationFactory {
+
+ Key KEY = Key.forClass(URIConfigurationFactory.class);
+
+ String LOG4J2_VERSION = "2";
+
+ /**
+ * The prefix to use for automatic discovery of configuration files.
+ */
+ String getDefaultPrefix();
+
+ /**
+ * The prefix to use for automatic discovery of test configuration files.
+ */
+ String getTestPrefix();
+
+ /**
+ * A list of supported file extensions.
+ *
+ * Can contain {@code *}, if an attempt should be made to parse files with any file extension.
+ *
+ */
+ String[] getSupportedExtensions();
+
+ /**
+ * The version of the configuration format.
+ *
+ * Should return {@value LOG4J2_VERSION} for the Log4j 2.x configuration format.
+ *
+ */
+ String getVersion();
+
+ /**
+ * @param loggerContext The logger context to associate with the configuration.
+ * @param source The source of the configuration.
+ * @return A Configuration or {@code null}.
+ */
+ @Nullable
+ Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source);
+
+ /**
+ * @param loggerContext The logger context to associate with the configuration.
+ * @param name The name of the logger context.
+ * @param configLocation The configuration location or {@code null}
+ * @return A Configuration or {@code null}.
+ */
+ @Nullable
+ Configuration getConfiguration(LoggerContext loggerContext, String name, @Nullable URI configLocation);
+
+ /**
+ * @param loggerContext The logger context to associate with the configuration.
+ * @param name The name of the logger context.
+ * @param configLocation The configuration location or {@code null}
+ * @param loader The classloader to use to load resources.
+ * @return A Configuration or {@code null}.
+ */
+ @Nullable
+ Configuration getConfiguration(
+ LoggerContext loggerContext, String name, @Nullable URI configLocation, ClassLoader loader);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
index ca52e83c72c..1f561b8c31d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
@@ -26,7 +26,11 @@
import org.apache.logging.log4j.core.config.builder.api.Component;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.model.PluginType;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.jspecify.annotations.Nullable;
/**
* This is the general version of the Configuration created by the Builder. It may be extended to
@@ -46,8 +50,16 @@ public class BuiltConfiguration extends AbstractConfiguration {
private String contentType = "text";
public BuiltConfiguration(
- final LoggerContext loggerContext, final ConfigurationSource source, final Component rootComponent) {
- super(loggerContext, source);
+ final @Nullable LoggerContext loggerContext,
+ final ConfigurationSource source,
+ final Component rootComponent) {
+ super(
+ loggerContext,
+ source,
+ loggerContext != null ? loggerContext.getEnvironment() : PropertiesUtil.getProperties(),
+ loggerContext != null
+ ? (ConfigurableInstanceFactory) loggerContext.getInstanceFactory()
+ : DI.createInitializedFactory());
statusConfig = new StatusConfiguration().setStatus(getDefaultStatus());
for (final Component component : rootComponent.getComponents()) {
switch (component.getPluginType()) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index 5fced3a969f..8b9455aa227 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
@@ -23,11 +23,12 @@
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.AbstractConfiguration;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.core.config.URIConfigurationFactory;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.util.Source;
import org.apache.logging.log4j.core.util.WatchManager;
@@ -48,11 +49,12 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
*
* @param configurations The List of Configurations to merge.
*/
- public CompositeConfiguration(final List extends AbstractConfiguration> configurations) {
- super(configurations.get(0).getLoggerContext(), ConfigurationSource.COMPOSITE_SOURCE);
+ public CompositeConfiguration(
+ final LoggerContext loggerContext, final List extends AbstractConfiguration> configurations) {
+ super(loggerContext, ConfigurationSource.COMPOSITE_SOURCE);
rootNode = configurations.get(0).getRootNode();
this.configurations = configurations;
- mergeStrategy = getComponent(MergeStrategy.KEY);
+ this.mergeStrategy = getInstanceFactory().getInstance(MergeStrategy.class);
for (final AbstractConfiguration config : configurations) {
mergeStrategy.mergeRootProperties(rootNode, config);
}
@@ -127,7 +129,7 @@ public void setup() {
public Configuration reconfigure() {
LOGGER.debug("Reconfiguring composite configuration");
final List configs = new ArrayList<>();
- final ConfigurationFactory factory = instanceFactory.getInstance(ConfigurationFactory.KEY);
+ final URIConfigurationFactory factory = instanceFactory.getInstance(URIConfigurationFactory.KEY);
for (final AbstractConfiguration config : configurations) {
final ConfigurationSource source = config.getConfigurationSource();
final URI sourceURI = source.getURI();
@@ -145,7 +147,7 @@ public Configuration reconfigure() {
configs.add((AbstractConfiguration) currentConfig);
}
- return new CompositeConfiguration(configs);
+ return new CompositeConfiguration(getLoggerContext(), configs);
}
private void staffChildConfiguration(final AbstractConfiguration childConfiguration) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index 47f7b895e01..01cb345f394 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
@@ -27,6 +27,7 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@@ -69,19 +70,19 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
@SuppressFBWarnings(
value = "XXE_DOCUMENT",
justification = "The `newDocumentBuilder` method disables DTD processing.")
- public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource configSource) {
- super(loggerContext, configSource);
+ public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
+ super(loggerContext, configurationSource);
byte[] buffer = null;
try {
- final InputStream configStream = configSource.getInputStream();
+ final InputStream configStream = configurationSource.getInputStream();
try {
buffer = configStream.readAllBytes();
} finally {
Closer.closeSilently(configStream);
}
final InputSource source = new InputSource(new ByteArrayInputStream(buffer));
- source.setSystemId(configSource.getLocation());
+ source.setSystemId(configurationSource.getLocation());
final DocumentBuilder documentBuilder = newDocumentBuilder(true);
Document document;
try {
@@ -128,19 +129,19 @@ public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSo
} else if ("monitorInterval".equalsIgnoreCase(key)) {
monitorIntervalSeconds = Integers.parseInt(value);
} else if ("advertiser".equalsIgnoreCase(key)) {
- createAdvertiser(value, configSource, buffer, "text/xml");
+ createAdvertiser(value, configurationSource, buffer, "text/xml");
}
}
- initializeWatchers(this, configSource, monitorIntervalSeconds);
+ initializeWatchers(this, configurationSource, monitorIntervalSeconds);
statusConfig.initialize();
} catch (final SAXException | IOException | ParserConfigurationException e) {
- LOGGER.error("Error parsing " + configSource.getLocation(), e);
+ LOGGER.error("Error parsing " + configurationSource.getLocation(), e);
}
if (strict && schemaResource != null && buffer != null) {
try (final InputStream is =
Loader.getResourceAsStream(schemaResource, XmlConfiguration.class.getClassLoader())) {
if (is != null) {
- final javax.xml.transform.Source src = new StreamSource(is, LOG4J_XSD);
+ final Source src = new StreamSource(is, LOG4J_XSD);
final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = null;
try {
@@ -165,7 +166,7 @@ public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSo
}
if (getName() == null) {
- setName(configSource.getLocation());
+ setName(configurationSource.getLocation());
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
index 5b3104d436a..0e75d5cc201 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
@@ -53,7 +53,7 @@ public Configuration getConfiguration(final LoggerContext loggerContext, final C
* @return An array of File extensions.
*/
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return SUFFIXES;
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
index 1918d92c297..4cb19175332 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
@@ -331,7 +331,7 @@ public MutableThreadContextMapFilter build() {
return new MutableThreadContextMapFilter(
new NoOpFilter(), null, 0, null, getOnMatch(), getOnMismatch(), configuration);
}
- final PropertyEnvironment props = configuration.getContextProperties();
+ final PropertyEnvironment props = configuration.getEnvironment();
final AuthorizationProvider authorizationProvider = AuthorizationProvider.getAuthorizationProvider(props);
final SslConfiguration sslConfiguration = SslConfigurationFactory.getSslConfiguration(props);
Filter filter;
@@ -371,7 +371,7 @@ private class FileMonitor implements Runnable {
@Override
public void run() {
- final PropertyEnvironment properties = configuration.getContextProperties();
+ final PropertyEnvironment properties = configuration.getEnvironment();
final SslConfiguration sslConfiguration = SslConfigurationFactory.getSslConfiguration(properties);
final ConfigResult result = getConfig(source, authorizationProvider, properties, sslConfiguration);
if (result.status == Status.SUCCESS) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
index 102a585bcf6..2f176ea286d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
@@ -24,10 +24,13 @@
import org.apache.logging.log4j.core.ContextDataInjector;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.DefaultConfigurationFactory;
+import org.apache.logging.log4j.core.config.URIConfigurationFactory;
import org.apache.logging.log4j.core.config.composite.DefaultMergeStrategy;
import org.apache.logging.log4j.core.config.composite.MergeStrategy;
+import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.InterpolatorFactory;
+import org.apache.logging.log4j.core.lookup.RuntimeStrSubstitutor;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
@@ -39,14 +42,15 @@
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.message.FlowMessageFactory;
import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.plugins.Factory;
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.SingletonFactory;
import org.apache.logging.log4j.plugins.condition.ConditionalOnMissingBinding;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
import org.apache.logging.log4j.spi.CopyOnWrite;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.spi.LoggingSystem;
+import org.apache.logging.log4j.spi.Provider;
import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
import org.apache.logging.log4j.status.StatusLogger;
@@ -67,16 +71,31 @@
public class DefaultBundle {
@SingletonFactory
+ @ConditionalOnMissingBinding
+ public Provider provider(final ConfigurableInstanceFactory instanceFactory) {
+ return new Log4jProvider(instanceFactory);
+ }
+
+ @SingletonFactory
+ @ConditionalOnMissingBinding
+ public LoggerContextFactory loggerContextFactory(final ConfigurableInstanceFactory instanceFactory) {
+ return new Log4jContextFactory(instanceFactory);
+ }
+
+ @SingletonFactory
+ @ConditionalOnMissingBinding
public MessageFactory defaultMessageFactory() {
return LoggingSystem.getMessageFactory();
}
@SingletonFactory
+ @ConditionalOnMissingBinding
public FlowMessageFactory defaultFlowMessageFactory() {
return LoggingSystem.getFlowMessageFactory();
}
@SingletonFactory
+ @ConditionalOnMissingBinding
public RecyclerFactory defaultRecyclerFactory() {
return LoggingSystem.getRecyclerFactory();
}
@@ -99,20 +118,17 @@ public NanoClock defaultNanoClock() {
return new DummyNanoClock();
}
- @Factory
+ @SingletonFactory
@ConditionalOnMissingBinding
public ContextDataInjector defaultContextDataInjector() {
final ReadOnlyThreadContextMap threadContextMap = ThreadContext.getThreadContextMap();
-
- // note: map may be null (if legacy custom ThreadContextMap was installed by user)
- if (threadContextMap == null) {
- // for non StringMap-based context maps
- return new ThreadContextDataInjector.ForDefaultThreadContextMap();
- }
- if (threadContextMap instanceof CopyOnWrite) {
- return new ThreadContextDataInjector.ForCopyOnWriteThreadContextMap();
+ if (threadContextMap != null) {
+ return threadContextMap instanceof CopyOnWrite
+ ? new ThreadContextDataInjector.ForCopyOnWriteThreadContextMap()
+ : new ThreadContextDataInjector.ForGarbageFreeThreadContextMap();
}
- return new ThreadContextDataInjector.ForGarbageFreeThreadContextMap();
+ // for non StringMap-based context maps
+ return new ThreadContextDataInjector.ForDefaultThreadContextMap();
}
@SingletonFactory
@@ -134,15 +150,29 @@ public InterpolatorFactory interpolatorFactory(
@SingletonFactory
@ConditionalOnMissingBinding
- public StrSubstitutor strSubstitutor(final InterpolatorFactory factory) {
- return new StrSubstitutor(factory.newInterpolator(null));
+ public ConfigurationStrSubstitutor configurationStrSubstitutor(final InterpolatorFactory factory) {
+ return new ConfigurationStrSubstitutor(factory.newInterpolator(null));
+ }
+
+ @SingletonFactory
+ @ConditionalOnMissingBinding
+ public RuntimeStrSubstitutor runtimeStrSubstitutor(final InterpolatorFactory factory) {
+ return new RuntimeStrSubstitutor(factory.newInterpolator(null));
+ }
+
+ /**
+ * Spring Boot needs a ConfigurationFactory for compatibility.
+ */
+ @SingletonFactory
+ @ConditionalOnMissingBinding
+ public ConfigurationFactory configurationFactory() {
+ return new DefaultConfigurationFactory();
}
@SingletonFactory
@ConditionalOnMissingBinding
- public ConfigurationFactory configurationFactory(
- final ConfigurableInstanceFactory instanceFactory, final StrSubstitutor substitutor) {
- return new DefaultConfigurationFactory(instanceFactory, substitutor);
+ public URIConfigurationFactory configurationFactory(final ConfigurationFactory factory) {
+ return factory;
}
@SingletonFactory
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
index dae847bf8bc..2d1900cf940 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
@@ -29,7 +29,6 @@
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
-import org.apache.logging.log4j.core.impl.internal.InternalLoggerContext;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
@@ -38,6 +37,7 @@
import org.apache.logging.log4j.plugins.Singleton;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
@@ -50,12 +50,17 @@
public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallbackRegistry {
private static final StatusLogger LOGGER = StatusLogger.getLogger();
+ private static final Key KEY =
+ Key.builder(LoggerContextFactory.class).get();
private final ContextSelector selector;
private final ShutdownCallbackRegistry shutdownCallbackRegistry;
/**
* Initializes the ContextSelector from system property {@link Log4jPropertyKey#CONTEXT_SELECTOR_CLASS_NAME}.
+ *
+ * Only used if no {@link org.apache.logging.log4j.spi.Provider} is present.
+ *
*/
public Log4jContextFactory() {
this(DI.createInitializedFactory());
@@ -108,18 +113,8 @@ public Log4jContextFactory(
@Inject
@NullMarked
- public Log4jContextFactory(
- final ConfigurableInstanceFactory instanceFactory,
- final ContextSelector selector,
- final ShutdownCallbackRegistry registry) {
- this.selector = selector;
- this.shutdownCallbackRegistry = registry;
- LOGGER.debug("Using ShutdownCallbackRegistry {}", this.shutdownCallbackRegistry.getClass());
- initializeShutdownCallbackRegistry();
- }
-
- @NullMarked
- private Log4jContextFactory(final ConfigurableInstanceFactory instanceFactory) {
+ public Log4jContextFactory(final ConfigurableInstanceFactory instanceFactory) {
+ instanceFactory.registerBinding(KEY, () -> this);
selector = instanceFactory.getInstance(ContextSelector.KEY);
shutdownCallbackRegistry = instanceFactory.getInstance(ShutdownCallbackRegistry.KEY);
LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass());
@@ -188,21 +183,11 @@ public LoggerContext getContext(
if (ctx.getState() == LifeCycle.State.INITIALIZED) {
if (source != null) {
ContextAnchor.THREAD_CONTEXT.set(ctx);
- boolean setProperties = false;
try {
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
final Configuration config = ctx.getConfiguration(source);
LOGGER.debug("Starting {} from configuration {}", ctx, source);
ctx.start(config);
} finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
ContextAnchor.THREAD_CONTEXT.remove();
}
} else {
@@ -236,19 +221,9 @@ public LoggerContext getContext(
}
if (ctx.getState() == LifeCycle.State.INITIALIZED) {
ContextAnchor.THREAD_CONTEXT.set(ctx);
- boolean setProperties = false;
try {
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
ctx.start(configuration);
} finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
ContextAnchor.THREAD_CONTEXT.remove();
}
}
@@ -285,21 +260,11 @@ public LoggerContext getContext(
if (ctx.getState() == LifeCycle.State.INITIALIZED) {
if (configLocation != null || name != null) {
ContextAnchor.THREAD_CONTEXT.set(ctx);
- boolean setProperties = false;
try {
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
final Configuration config = ctx.getConfiguration(name, configLocation);
LOGGER.debug("Starting {} from configuration at {}", ctx, configLocation);
ctx.start(config);
} finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
ContextAnchor.THREAD_CONTEXT.remove();
}
} else {
@@ -324,22 +289,12 @@ public LoggerContext getContext(
}
if (ctx.getState() == LifeCycle.State.INITIALIZED) {
if (configLocation != null || name != null) {
- boolean setProperties = false;
try {
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
ContextAnchor.THREAD_CONTEXT.set(ctx);
final Configuration config = ctx.getConfiguration(name, configLocation);
LOGGER.debug("Starting {} from configuration at {}", ctx, configLocation);
ctx.start(config);
} finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
ContextAnchor.THREAD_CONTEXT.remove();
}
} else {
@@ -369,15 +324,8 @@ public LoggerContext getContext(
if (ctx.getState() == LifeCycle.State.INITIALIZED) {
if ((configLocations != null && !configLocations.isEmpty())) {
ContextAnchor.THREAD_CONTEXT.set(ctx);
- boolean setProperties = false;
try {
final List configurations = new ArrayList<>(configLocations.size());
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
for (final URI configLocation : configLocations) {
final Configuration currentReadConfiguration = ctx.getConfiguration(name, configLocation);
if (currentReadConfiguration != null) {
@@ -399,14 +347,9 @@ public LoggerContext getContext(
} else if (configurations.size() == 1) {
ctx.start(configurations.get(0));
} else {
- final CompositeConfiguration compositeConfiguration =
- new CompositeConfiguration(configurations);
- ctx.start(compositeConfiguration);
+ ctx.start(new CompositeConfiguration(ctx, configurations));
}
} finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
ContextAnchor.THREAD_CONTEXT.remove();
}
} else {
@@ -417,24 +360,11 @@ public LoggerContext getContext(
}
private void startContext(final LoggerContext ctx, final ClassLoader classLoader) {
- boolean setProperties = false;
- try {
- if (ctx.getProperties() == null) {
- final PropertiesUtil props = PropertiesUtil.getContextProperties(classLoader, ctx.getName());
- ctx.setProperties(props);
- PropertiesUtil.setThreadProperties(props);
- setProperties = true;
- }
- final Configuration config = ctx.getConfiguration(ctx.getName(), null);
- if (config != null) {
- ctx.start(config);
- } else {
- ctx.start();
- }
- } finally {
- if (setProperties) {
- PropertiesUtil.clearThreadProperties();
- }
+ final Configuration config = ctx.getConfiguration(ctx.getName(), null);
+ if (config != null) {
+ ctx.start(config);
+ } else {
+ ctx.start();
}
}
@@ -508,6 +438,6 @@ public boolean isShutdownHookEnabled() {
@Override
public org.apache.logging.log4j.spi.LoggerContext wrapLoggerContext(
org.apache.logging.log4j.spi.LoggerContext loggerContext) {
- return new InternalLoggerContext(loggerContext);
+ return loggerContext;
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
index 378c419bd24..e0f91dbb649 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java
@@ -18,6 +18,11 @@
import aQute.bnd.annotation.Resolution;
import aQute.bnd.annotation.spi.ServiceProvider;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.spi.Provider;
/**
@@ -25,7 +30,23 @@
*/
@ServiceProvider(value = Provider.class, resolution = Resolution.OPTIONAL)
public class Log4jProvider extends Provider {
+
+ private final ConfigurableInstanceFactory instanceFactory;
+
public Log4jProvider() {
+ this(DI.createInitializedFactory());
+ }
+
+ @Inject
+ public Log4jProvider(final ConfigurableInstanceFactory instanceFactory) {
super(10, "3.0.0", Log4jContextFactory.class);
+ this.instanceFactory = instanceFactory;
+ instanceFactory.registerBinding(Key.forClass(Provider.class), () -> this);
+ instanceFactory.registerBinding(Key.forClass(Log4jProvider.class), () -> this);
+ }
+
+ @Override
+ public LoggerContextFactory getLoggerContextFactory() {
+ return instanceFactory.getInstance(Key.forClass(LoggerContextFactory.class));
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
index 92635b09000..fc9fba3fb37 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
@@ -28,6 +28,7 @@
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.plugins.Ordered;
import org.apache.logging.log4j.plugins.SingletonFactory;
+import org.apache.logging.log4j.plugins.condition.ConditionalOnMissingBinding;
import org.apache.logging.log4j.plugins.di.InjectException;
import org.apache.logging.log4j.plugins.di.InstanceFactory;
import org.apache.logging.log4j.util.PropertyEnvironment;
@@ -61,12 +62,14 @@ public SystemPropertyBundle(
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.CONTEXT_SELECTOR_CLASS_NAME)
+ @ConditionalOnMissingBinding
@SingletonFactory
public ContextSelector systemPropertyContextSelector() throws ClassNotFoundException {
return newInstanceOfProperty(Log4jPropertyKey.CONTEXT_SELECTOR_CLASS_NAME, ContextSelector.class);
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.SHUTDOWN_CALLBACK_REGISTRY)
+ @ConditionalOnMissingBinding
@SingletonFactory
@Ordered(100)
public ShutdownCallbackRegistry systemPropertyShutdownCallbackRegistry() throws ClassNotFoundException {
@@ -74,6 +77,7 @@ public ShutdownCallbackRegistry systemPropertyShutdownCallbackRegistry() throws
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.THREAD_CONTEXT_DATA_INJECTOR_CLASS_NAME)
+ @ConditionalOnMissingBinding
@Factory
public ContextDataInjector systemPropertyContextDataInjector() throws ClassNotFoundException {
return newInstanceOfProperty(
@@ -81,18 +85,21 @@ public ContextDataInjector systemPropertyContextDataInjector() throws ClassNotFo
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.LOG_EVENT_FACTORY_CLASS_NAME)
+ @ConditionalOnMissingBinding
@SingletonFactory
public LogEventFactory systemPropertyLogEventFactory() throws ClassNotFoundException {
return newInstanceOfProperty(Log4jPropertyKey.LOG_EVENT_FACTORY_CLASS_NAME, LogEventFactory.class);
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.CONFIG_MERGE_STRATEGY)
+ @ConditionalOnMissingBinding
@SingletonFactory
public MergeStrategy systemPropertyMergeStrategy() throws ClassNotFoundException {
return newInstanceOfProperty(Log4jPropertyKey.CONFIG_MERGE_STRATEGY, MergeStrategy.class);
}
@ConditionalOnPropertyKey(key = Log4jPropertyKey.STATUS_DEFAULT_LEVEL)
+ @ConditionalOnMissingBinding
@SingletonFactory
@Named("StatusLogger")
public Level systemPropertyDefaultStatusLevel() {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/internal/InternalLoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/internal/InternalLoggerContext.java
deleted file mode 100644
index 5e02eb89b40..00000000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/internal/InternalLoggerContext.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.impl.internal;
-
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogBuilder;
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.message.FlowMessageFactory;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.spi.ExtendedLogger;
-import org.apache.logging.log4j.spi.LoggingSystem;
-import org.apache.logging.log4j.spi.recycler.RecyclerFactory;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.jspecify.annotations.NullMarked;
-import org.jspecify.annotations.Nullable;
-
-/**
- * Creates a SimpleLoggerContext compatible with log4j-core. This class is internal to Log4j.
- */
-@NullMarked
-public class InternalLoggerContext extends LoggerContext {
-
- private static final LoggerConfig LOGGER_CONFIG = new LoggerConfig.RootLogger();
-
- private final org.apache.logging.log4j.spi.LoggerContext parentLoggerContext;
- private final MessageFactory defaultMessageFactory;
- private final FlowMessageFactory defaultFlowMessageFactory;
- private final RecyclerFactory recyclerFactory;
-
- public InternalLoggerContext(org.apache.logging.log4j.spi.LoggerContext loggerContext) {
- this.parentLoggerContext = loggerContext;
- this.defaultMessageFactory = LoggingSystem.getMessageFactory();
- this.defaultFlowMessageFactory = LoggingSystem.getFlowMessageFactory();
- this.recyclerFactory = LoggingSystem.getRecyclerFactory();
- setStarted();
- }
-
- @Override
- protected Logger newInstance(
- final LoggerContext ctx,
- final String name,
- final MessageFactory messageFactory,
- final FlowMessageFactory flowMessageFactory,
- final RecyclerFactory recyclerFactory,
- final org.apache.logging.log4j.Logger statusLogger) {
- return new InternalLogger(this, name);
- }
-
- @Override
- public boolean stop(final long timeout, final TimeUnit timeUnit) {
- return false;
- }
-
- private class InternalLogger extends Logger {
- private final ExtendedLogger logger;
- private final InternalLoggerContext loggerContext;
-
- public InternalLogger(final InternalLoggerContext loggerContext, final String name) {
- super(
- loggerContext,
- name,
- defaultMessageFactory,
- defaultFlowMessageFactory,
- recyclerFactory,
- StatusLogger.getLogger());
- this.loggerContext = loggerContext;
- this.logger = parentLoggerContext.getLogger(name);
- }
-
- @Override
- public Logger getParent() {
- return null;
- }
-
- @Override
- public LoggerContext getContext() {
- return loggerContext;
- }
-
- @Override
- public void setLevel(final Level level) {}
-
- @Override
- public LoggerConfig get() {
- return LOGGER_CONFIG;
- }
-
- @Override
- protected boolean requiresLocation() {
- return false;
- }
-
- @Override
- protected void doLog(
- final String fqcn,
- @Nullable final StackTraceElement location,
- final Level level,
- @Nullable final Marker marker,
- final Message message,
- @Nullable final Throwable throwable) {
- logger.log(level, marker, message, throwable);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message, Throwable t) {
- return logger.isEnabled(level, marker, message, t);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message) {
- return logger.isEnabled(level, marker, message);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message, Object... params) {
- return logger.isEnabled(level, marker, message, params);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message, Object p0) {
- return logger.isEnabled(level, marker, message, p0);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1) {
- return logger.isEnabled(level, marker, message, p0, p1);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2) {
- return logger.isEnabled(level, marker, message, p0, p1, p2);
- }
-
- @Override
- public boolean isEnabled(
- Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3);
- }
-
- @Override
- public boolean isEnabled(
- Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4);
- }
-
- @Override
- public boolean isEnabled(
- Level level,
- Marker marker,
- String message,
- Object p0,
- Object p1,
- Object p2,
- Object p3,
- Object p4,
- Object p5) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4, p5);
- }
-
- @Override
- public boolean isEnabled(
- Level level,
- Marker marker,
- String message,
- Object p0,
- Object p1,
- Object p2,
- Object p3,
- Object p4,
- Object p5,
- Object p6) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4, p5, p6);
- }
-
- @Override
- public boolean isEnabled(
- Level level,
- Marker marker,
- String message,
- Object p0,
- Object p1,
- Object p2,
- Object p3,
- Object p4,
- Object p5,
- Object p6,
- Object p7) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7);
- }
-
- @Override
- public boolean isEnabled(
- Level level,
- Marker marker,
- String message,
- Object p0,
- Object p1,
- Object p2,
- Object p3,
- Object p4,
- Object p5,
- Object p6,
- Object p7,
- Object p8) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8);
- }
-
- @Override
- public boolean isEnabled(
- Level level,
- Marker marker,
- String message,
- Object p0,
- Object p1,
- Object p2,
- Object p3,
- Object p4,
- Object p5,
- Object p6,
- Object p7,
- Object p8,
- Object p9) {
- return logger.isEnabled(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, CharSequence message, Throwable t) {
- return logger.isEnabled(level, marker, message, t);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, Object message, Throwable t) {
- return logger.isEnabled(level, marker, message, t);
- }
-
- @Override
- public boolean isEnabled(Level level, Marker marker, Message message, Throwable t) {
- return logger.isEnabled(level, marker, message, t);
- }
-
- @Override
- public void addAppender(Appender appender) {}
-
- @Override
- public void removeAppender(Appender appender) {}
-
- @Override
- public Map getAppenders() {
- return Collections.emptyMap();
- }
-
- @Override
- public Iterator getFilters() {
- return Collections.emptyIterator();
- }
-
- @Override
- public Level getLevel() {
- return logger.getLevel();
- }
-
- @Override
- public int filterCount() {
- return 0;
- }
-
- @Override
- public void addFilter(Filter filter) {}
-
- @Override
- public boolean isAdditive() {
- return false;
- }
-
- @Override
- public void setAdditive(boolean additive) {}
-
- @Override
- public LogBuilder atLevel(Level level) {
- return logger.atLevel(level);
- }
-
- @Override
- protected void updateConfiguration(Configuration newConfig) {}
- }
-}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
index 42fdbd10eb9..6459e57cd9f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
@@ -32,7 +32,6 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.pattern.DatePatternConverter;
@@ -377,15 +376,6 @@ public byte[] getFooter() {
}
}
- /**
- * Creates an HTML Layout using the default settings.
- *
- * @return an HTML Layout.
- */
- public static HtmlLayout createDefaultLayout() {
- return newBuilder().setConfiguration(new DefaultConfiguration()).build();
- }
-
@PluginFactory
public static Builder newBuilder() {
return new Builder();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
index 7d8171b3e2c..4686d8a3f4a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
@@ -27,8 +27,6 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.ConfigurationAware;
import org.apache.logging.log4j.core.config.LoggerContextAware;
-import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.status.StatusLogger;
/**
@@ -60,49 +58,12 @@ public class Interpolator extends AbstractConfigurationAwareLookup implements Lo
private WeakReference loggerContext = null;
/**
- * Constructs an Interpolator using a given StrLookup and a list of packages to find Lookup plugins in.
- * Only used in the Interpolator.
- *
- * @param defaultLookup the default StrLookup to use as a fallback
- * @since 2.1
- */
- public Interpolator(final StrLookup defaultLookup) {
- this.defaultLookup = defaultLookup == null ? new PropertiesLookup(Map.of()) : defaultLookup;
- final ConfigurableInstanceFactory instanceFactory = DI.createInitializedFactory();
- // TODO(ms): this should use plugin map injection
- instanceFactory.getInstance(PLUGIN_CATEGORY_KEY).forEach((key, value) -> {
- try {
- strLookups.put(
- key, instanceFactory.getFactory(value.getPluginClass().asSubclass(StrLookup.class)));
- } catch (final Throwable t) {
- handleError(key, t);
- }
- });
- }
-
- /**
- * Used by interpolatrorFactory.
- *
- * @param defaultLookup The default Lookup.
- * @param strLookupPlugins The Lookup Plugins.
+ * @param defaultLookup The default {@link StrLookup}.
+ * @param additionalLookups A map associating a prefix with a secondary {@link StrLookup}.
*/
- public Interpolator(final StrLookup defaultLookup, final Map> strLookupPlugins) {
+ public Interpolator(final StrLookup defaultLookup, final Map> additionalLookups) {
this.defaultLookup = defaultLookup;
- strLookups.putAll(strLookupPlugins);
- }
-
- /**
- * Create the default Interpolator.
- */
- public Interpolator() {
- this(Map.of());
- }
-
- /**
- * Creates the default Interpolator with the provided properties.
- */
- public Interpolator(final Map properties) {
- this(new PropertiesLookup(properties));
+ strLookups.putAll(additionalLookups);
}
public StrLookup getDefaultLookup() {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
index 81ffe42769e..b9ac456161f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java
@@ -123,6 +123,7 @@ public PatternParser(
final String converterKey,
final Class> expectedClass,
final Class> filterClass) {
+ // Only null in tests
config = configuration != null ? configuration : new NullConfiguration();
final Key pluginCategoryKey = PLUGIN_CATEGORY_KEY.withNamespace(converterKey);
final PluginNamespace plugins = config.getComponent(pluginCategoryKey);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/AbstractContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/AbstractContextSelector.java
new file mode 100644
index 00000000000..a215325f48f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/AbstractContextSelector.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.selector;
+
+import java.net.URI;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.jspecify.annotations.Nullable;
+
+public abstract class AbstractContextSelector implements ContextSelector {
+
+ protected final ConfigurableInstanceFactory instanceFactory;
+
+ public AbstractContextSelector(final ConfigurableInstanceFactory instanceFactory) {
+ this.instanceFactory = instanceFactory;
+ }
+
+ protected LoggerContext.Builder newBuilder() {
+ return instanceFactory.getInstance(LoggerContext.Builder.class);
+ }
+
+ protected final LoggerContext createContext(
+ final String contextName, final @Nullable URI configLocation, final ClassLoader loader) {
+ return newBuilder()
+ .setContextName(contextName)
+ .setConfigLocation(configLocation)
+ .setLoader(loader)
+ .build();
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
index ef49ecde745..791116b92b8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
@@ -33,16 +33,16 @@
* Returns either this Thread's context or the default LoggerContext.
*/
@Singleton
-public class BasicContextSelector implements ContextSelector, LoggerContextShutdownAware {
+public class BasicContextSelector extends AbstractContextSelector
+ implements ContextSelector, LoggerContextShutdownAware {
private static final Logger LOGGER = StatusLogger.getLogger();
protected final Lazy context = Lazy.lazy(this::createContext);
- protected final ConfigurableInstanceFactory instanceFactory;
@Inject
public BasicContextSelector(final ConfigurableInstanceFactory instanceFactory) {
- this.instanceFactory = instanceFactory;
+ super(instanceFactory);
}
@Override
@@ -114,7 +114,7 @@ public List getLoggerContexts() {
}
protected LoggerContext createContext() {
- return new LoggerContext("Default", null, (URI) null, instanceFactory);
+ return createContext("Default", null, getClass().getClassLoader());
}
@Override
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
index acae3a3dbda..4e7990f9e56 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
@@ -48,18 +48,18 @@
* This ContextSelector should not be used with a Servlet Filter such as the Log4jServletFilter.
*/
@Singleton
-public class ClassLoaderContextSelector implements ContextSelector, LoggerContextShutdownAware {
+public class ClassLoaderContextSelector extends AbstractContextSelector
+ implements ContextSelector, LoggerContextShutdownAware {
protected static final StatusLogger LOGGER = StatusLogger.getLogger();
- protected final Lazy defaultContext = Lazy.lazy(() -> createContext(defaultContextName(), null));
+ protected final Lazy defaultContext =
+ Lazy.lazy(() -> createContext(defaultContextName(), null, getClass().getClassLoader()));
protected final Map>> contextMap = new ConcurrentHashMap<>();
- protected final ConfigurableInstanceFactory instanceFactory;
-
@Inject
public ClassLoaderContextSelector(final ConfigurableInstanceFactory instanceFactory) {
- this.instanceFactory = instanceFactory;
+ super(instanceFactory);
}
@Override
@@ -188,16 +188,6 @@ public List getLoggerContexts() {
return Collections.unmodifiableList(list);
}
- private ConfigurableInstanceFactory getConfigurableInstanceFactory(final Map.Entry entry) {
- if (entry != null) {
- final Object value = entry.getValue();
- if (value instanceof ConfigurableInstanceFactory) {
- return (ConfigurableInstanceFactory) value;
- }
- }
- return instanceFactory;
- }
-
private LoggerContext locateContext(
final ClassLoader loaderOrNull, final Map.Entry entry, final URI configLocation) {
// LOG4J2-477: class loader may be null
@@ -237,7 +227,7 @@ private LoggerContext locateContext(
} */
}
}
- final LoggerContext ctx = createContext(name, configLocation, getConfigurableInstanceFactory(entry));
+ final LoggerContext ctx = createContext(name, configLocation, loader);
if (entry != null) {
ctx.putObject(entry.getKey(), entry.getValue());
}
@@ -269,7 +259,7 @@ private LoggerContext locateContext(
}
return ctx;
}
- ctx = createContext(name, configLocation, getConfigurableInstanceFactory(entry));
+ ctx = createContext(name, configLocation, loader);
if (entry != null) {
ctx.putObject(entry.getKey(), entry.getValue());
}
@@ -279,16 +269,6 @@ private LoggerContext locateContext(
return ctx;
}
- protected LoggerContext createContext(final String name, final URI configLocation) {
- final ConfigurableInstanceFactory instanceFactory = this.instanceFactory;
- return createContext(name, configLocation, instanceFactory);
- }
-
- protected LoggerContext createContext(
- final String name, final URI configLocation, final ConfigurableInstanceFactory instanceFactory) {
- return new LoggerContext(name, null, configLocation, instanceFactory);
- }
-
protected String toContextMapKey(final ClassLoader loader) {
return Integer.toHexString(System.identityHashCode(loader));
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/Generate.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/Generate.java
index 15fe08b3639..5c3d34e85fc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/Generate.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/Generate.java
@@ -62,7 +62,7 @@ String imports() {
+ "import org.apache.logging.log4j.Marker;%n"
+ "import org.apache.logging.log4j.message.Message;%n"
+ "import org.apache.logging.log4j.message.MessageFactory;%n"
- + "import org.apache.logging.log4j.spi.AbstractLogger;%n"
+ + "import org.apache.logging.log4j.spi.ExtendedLogger;%n"
+ "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n"
+ "import org.apache.logging.log4j.util.MessageSupplier;%n"
+ "import org.apache.logging.log4j.util.Supplier;%n"
@@ -91,7 +91,7 @@ String constructor() {
return ""
+ "%n"
+ " private %s(final Logger logger) {%n"
- + " this.logger = new ExtendedLoggerWrapper((AbstractLogger) logger, logger.getName(), "
+ + " this.logger = new ExtendedLoggerWrapper((ExtendedLogger) logger, logger.getName(), "
+ "logger.getMessageFactory());%n"
+ " }%n";
// @formatter:on
@@ -113,7 +113,7 @@ String imports() {
+ "import org.apache.logging.log4j.Marker;%n"
+ "import org.apache.logging.log4j.message.Message;%n"
+ "import org.apache.logging.log4j.message.MessageFactory;%n"
- + "import org.apache.logging.log4j.spi.AbstractLogger;%n"
+ + "import org.apache.logging.log4j.spi.ExtendedLogger;%n"
+ "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n"
+ "import org.apache.logging.log4j.util.MessageSupplier;%n"
+ "import org.apache.logging.log4j.util.Supplier;%n"
@@ -143,7 +143,7 @@ String constructor() {
return ""
+ "%n"
+ " private %s(final Logger logger) {%n"
- + " super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());%n"
+ + " super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());%n"
+ " this.logger = this;%n"
+ " }%n";
// @formatter:on
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
index 5f8a440b793..37501158c69 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
@@ -42,7 +42,7 @@
@Plugin
public class CsvLogEventLayout extends AbstractCsvLayout {
- public static CsvLogEventLayout createDefaultLayout() {
+ static CsvLogEventLayout createDefaultLayout() {
return new CsvLogEventLayout(
new DefaultConfiguration(),
Charset.forName(DEFAULT_CHARSET),
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
index 1270771a93a..484001c4e02 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
@@ -60,7 +60,7 @@ public static AbstractCsvLayout createDefaultLayout() {
null);
}
- public static AbstractCsvLayout createLayout(final CSVFormat format) {
+ static AbstractCsvLayout createLayout(final CSVFormat format) {
return new CsvParameterLayout(new DefaultConfiguration(), Charset.forName(DEFAULT_CHARSET), format, null, null);
}
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index 784d411c02c..c393b4bab13 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -24,7 +24,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.layout.Rfc5424Layout;
import org.apache.logging.log4j.core.net.Facility;
@@ -37,6 +37,7 @@
import org.apache.logging.log4j.plugins.PluginElement;
import org.apache.logging.log4j.plugins.PluginFactory;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.Key;
/**
* An Appender that uses the Avro protocol to route events to Flume.
@@ -211,7 +212,7 @@ public static FlumeAppender createAppender(
@PluginElement final FlumeEventFactory factory,
@PluginElement Layout layout,
@PluginElement final Filter filter,
- final ConfigurableInstanceFactory instanceFactory) {
+ final Configuration configuration) {
final boolean embed = embedded != null
? Boolean.parseBoolean(embedded)
@@ -255,7 +256,7 @@ public static FlumeAppender createAppender(
if (layout == null) {
final int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
- .setConfig(new DefaultConfiguration())
+ .setConfig(configuration)
.setFacility(Facility.LOCAL0)
.setEin(String.valueOf(enterpriseNumber))
.setIncludeMDC(true)
@@ -303,7 +304,7 @@ public static FlumeAppender createAppender(
delayMillis,
lockTimeoutRetryCount,
dataDir,
- instanceFactory);
+ configuration.getComponent(Key.forClass(ConfigurableInstanceFactory.class)));
break;
default:
LOGGER.debug("No manager type specified. Defaulting to AVRO");
diff --git a/log4j-flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java b/log4j-flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java
index 9571a0d6834..8b24237b7c9 100644
--- a/log4j-flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java
+++ b/log4j-flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java
@@ -44,10 +44,10 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.status.StatusLogger;
import org.junit.After;
import org.junit.Assert;
@@ -64,7 +64,7 @@ public class FlumeAppenderTest {
private Channel channel;
private Logger avroLogger;
private String testPort;
- private ConfigurableInstanceFactory instanceFactory;
+ private Configuration configuration;
@BeforeClass
public static void setupClass() {
@@ -73,7 +73,7 @@ public static void setupClass() {
@Before
public void setUp() throws Exception {
- instanceFactory = DI.createInitializedFactory();
+ configuration = new DefaultConfiguration();
eventSource = new AvroSource();
channel = new MemoryChannel();
@@ -142,7 +142,7 @@ public void testLog4jAvroAppender() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -192,7 +192,7 @@ public void testLog4jAvroAppenderWithHostsParam() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -242,7 +242,7 @@ public void testStructured() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
final Logger eventLogger = (Logger) LogManager.getLogger("EventLogger");
Assert.assertNotNull(eventLogger);
@@ -302,7 +302,7 @@ public void testMultiple() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -357,7 +357,7 @@ public void testIncompleteBatch() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -418,7 +418,7 @@ public void testIncompleteBatch2() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -473,7 +473,7 @@ public void testBatch() throws IOException {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -527,7 +527,7 @@ public void testConnectionRefused() {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
@@ -577,7 +577,7 @@ public void testNotConnected() throws Exception {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
Assert.assertTrue("Appender Not started", avroAppender.isStarted());
avroLogger.addAppender(avroAppender);
@@ -645,7 +645,7 @@ public void testReconnect() throws Exception {
null,
null,
null,
- instanceFactory);
+ configuration);
avroAppender.start();
avroLogger.addAppender(avroAppender);
avroLogger.setLevel(Level.ALL);
diff --git a/log4j-jndi-test/src/test/java/org/apache/logging/log4j/jndi/lookup/InterpolatorTest.java b/log4j-jndi-test/src/test/java/org/apache/logging/log4j/jndi/lookup/InterpolatorTest.java
index 58b68c088ad..8762d0351aa 100644
--- a/log4j-jndi-test/src/test/java/org/apache/logging/log4j/jndi/lookup/InterpolatorTest.java
+++ b/log4j-jndi-test/src/test/java/org/apache/logging/log4j/jndi/lookup/InterpolatorTest.java
@@ -28,6 +28,8 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
@@ -35,9 +37,13 @@
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.MapLookup;
+import org.apache.logging.log4j.core.lookup.PropertiesLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.jndi.test.junit.JndiRule;
import org.apache.logging.log4j.message.StringMapMessage;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.model.PluginType;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
@@ -48,6 +54,14 @@
*/
public class InterpolatorTest {
+ static final ConfigurableInstanceFactory INSTANCE_FACTORY = DI.createInitializedFactory();
+ static final Map> LOOKUP_PLUGINS =
+ INSTANCE_FACTORY.getInstance(StrLookup.PLUGIN_CATEGORY_KEY).stream()
+ .collect(Collectors.toMap(
+ PluginType::getKey,
+ value -> INSTANCE_FACTORY.getFactory(
+ value.getPluginClass().asSubclass(StrLookup.class))));
+
private static final String TESTKEY = "TestKey";
private static final String TESTKEY2 = "TestKey2";
private static final String TESTVAL = "TestValue";
@@ -79,7 +93,7 @@ public void testGetDefaultLookup() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
final MapLookup defaultLookup = new MapLookup(map);
- final Interpolator interpolator = new Interpolator(defaultLookup);
+ final Interpolator interpolator = new Interpolator(defaultLookup, LOOKUP_PLUGINS);
assertEquals(getLookupMap(defaultLookup), getLookupMap((MapLookup) interpolator.getDefaultLookup()));
assertSame(defaultLookup, interpolator.getDefaultLookup());
}
@@ -100,7 +114,7 @@ private static Map getLookupMap(final MapLookup lookup) {
public void testLookup() {
final Map map = new HashMap<>();
map.put(TESTKEY, TESTVAL);
- final StrLookup lookup = new Interpolator(new MapLookup(map));
+ final StrLookup lookup = new Interpolator(new MapLookup(map), LOOKUP_PLUGINS);
ThreadContext.put(TESTKEY, TESTVAL);
String value = lookup.lookup(TESTKEY);
assertEquals(TESTVAL, value);
@@ -128,7 +142,7 @@ private void assertLookupNotEmpty(final StrLookup lookup, final String key) {
@Test
public void testLookupWithDefaultInterpolator() {
- final StrLookup lookup = new Interpolator();
+ final StrLookup lookup = new Interpolator(new PropertiesLookup(Map.of()), LOOKUP_PLUGINS);
String value = lookup.lookup("sys:" + TESTKEY);
assertEquals(TESTVAL, value);
value = lookup.lookup("env:PATH");
@@ -152,7 +166,7 @@ public void testLookupWithDefaultInterpolator() {
public void testInterpolatorMapMessageWithNoPrefix() {
final HashMap configProperties = new HashMap<>();
configProperties.put("key", "configProperties");
- final Interpolator interpolator = new Interpolator(configProperties);
+ final Interpolator interpolator = new Interpolator(new PropertiesLookup(configProperties), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
@@ -166,7 +180,8 @@ public void testInterpolatorMapMessageWithNoPrefix() {
@Test
public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() {
- final Interpolator interpolator = new Interpolator(Collections.emptyMap());
+ final Interpolator interpolator =
+ new Interpolator(new PropertiesLookup(Collections.emptyMap()), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
@@ -182,7 +197,7 @@ public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() {
public void testInterpolatorMapMessageWithMapPrefix() {
final HashMap configProperties = new HashMap<>();
configProperties.put("key", "configProperties");
- final Interpolator interpolator = new Interpolator(configProperties);
+ final Interpolator interpolator = new Interpolator(new PropertiesLookup(configProperties), LOOKUP_PLUGINS);
final HashMap map = new HashMap<>();
map.put("key", "mapMessage");
final LogEvent event = Log4jLogEvent.newBuilder()
diff --git a/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java b/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java
index b23ed36c224..025e78567a4 100644
--- a/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java
+++ b/log4j-jndi/src/main/java/org/apache/logging/log4j/jndi/selector/JndiContextSelector.java
@@ -27,11 +27,15 @@
import javax.naming.NamingException;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.impl.ContextAnchor;
+import org.apache.logging.log4j.core.selector.AbstractContextSelector;
import org.apache.logging.log4j.core.selector.NamedContextSelector;
import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.jndi.JndiManager;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Singleton;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Lazy;
/**
* This class can be used to define a custom logger repository. It makes use of the fact that in J2EE environments, each
@@ -87,15 +91,18 @@
*
*/
@Singleton
-public class JndiContextSelector implements NamedContextSelector {
+public class JndiContextSelector extends AbstractContextSelector implements NamedContextSelector {
- private static final LoggerContext CONTEXT = new LoggerContext("Default");
+ private final Lazy defaultContextLazy =
+ Lazy.lazy(() -> createContext("Default", null, JndiContextSelector.class.getClassLoader()));
- private static final ConcurrentMap CONTEXT_MAP = new ConcurrentHashMap<>();
+ private final ConcurrentMap CONTEXT_MAP = new ConcurrentHashMap<>();
private static final StatusLogger LOGGER = StatusLogger.getLogger();
- public JndiContextSelector() {
+ @Inject
+ public JndiContextSelector(final ConfigurableInstanceFactory instanceFactory) {
+ super(instanceFactory);
if (!JndiManager.isJndiContextSelectorEnabled()) {
throw new IllegalStateException("JNDI must be enabled by setting log4j2.enableJndiContextSelector=true");
}
@@ -145,7 +152,9 @@ public LoggerContext getContext(
final String loggingContextName = getContextName();
- return loggingContextName == null ? CONTEXT : locateContext(loggingContextName, null, configLocation);
+ return loggingContextName == null
+ ? defaultContextLazy.get()
+ : locateContext(loggingContextName, null, configLocation);
}
private static String getContextName() {
@@ -166,7 +175,7 @@ public LoggerContext locateContext(final String name, final Object externalConte
return null;
}
if (!CONTEXT_MAP.containsKey(name)) {
- final LoggerContext ctx = new LoggerContext(name, externalContext, configLocation);
+ final LoggerContext ctx = createContext(name, configLocation, JndiContextSelector.class.getClassLoader());
CONTEXT_MAP.putIfAbsent(name, ctx);
}
return CONTEXT_MAP.get(name);
diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
index e58d2c81ed5..6ce34c37bc8 100644
--- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
+++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
@@ -59,7 +59,7 @@ public Configuration getConfiguration(
* @return An array of File extensions.
*/
@Override
- public String[] getSupportedTypes() {
+ protected String[] getSupportedTypes() {
return SUFFIXES;
}
}
diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsConditionTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsConditionTest.java
new file mode 100644
index 00000000000..6bb52d6778d
--- /dev/null
+++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsConditionTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.plugins.condition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.logging.log4j.plugins.Factory;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Key;
+import org.junit.jupiter.api.Test;
+
+class OnPresentBindingsConditionTest {
+
+ static class Dependency {
+
+ Dependency() {}
+ }
+
+ static class Dependent {
+ final Dependency dependency;
+
+ Dependent(final Dependency dependency) {
+ this.dependency = dependency;
+ }
+ }
+
+ static class DependencyFactory {
+ @Factory
+ Dependency defaultDependency() {
+ return new Dependency();
+ }
+ }
+
+ static class DependentFactory {
+ @Factory
+ @ConditionalOnPresentBindings(bindings = Dependency.class)
+ Dependent defaultDependent(final Dependency dependency) {
+ return new Dependent(dependency);
+ }
+ }
+
+ final ConfigurableInstanceFactory instanceFactory = DI.createInitializedFactory();
+
+ @Test
+ void when_dependency_present_dependent_present() {
+ instanceFactory.registerBundle(DependencyFactory.class);
+ instanceFactory.registerBundle(DependentFactory.class);
+ assertThat(instanceFactory.hasBinding(Key.forClass(Dependent.class))).isTrue();
+ }
+
+ @Test
+ void when_dependency_absent_dependent_absent() {
+ instanceFactory.registerBundle(DependentFactory.class);
+ assertThat(instanceFactory.hasBinding(Key.forClass(Dependent.class))).isFalse();
+ }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/ConditionalOnPresentBindings.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/ConditionalOnPresentBindings.java
new file mode 100644
index 00000000000..c09f19ec3ea
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/ConditionalOnPresentBindings.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.plugins.condition;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Only creates a binding if all the requested dependencies exist.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+@Conditional(OnPresentBindingsCondition.class)
+public @interface ConditionalOnPresentBindings {
+
+ /**
+ * @return The set of classes that must have a binding.
+ */
+ Class>[] bindings();
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsCondition.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsCondition.java
new file mode 100644
index 00000000000..396beeb027c
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/condition/OnPresentBindingsCondition.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.plugins.condition;
+
+import java.lang.reflect.AnnotatedElement;
+import org.apache.logging.log4j.plugins.di.InstanceFactory;
+import org.apache.logging.log4j.plugins.di.Key;
+
+public class OnPresentBindingsCondition implements Condition {
+ @Override
+ public boolean matches(final ConditionContext context, final AnnotatedElement element) {
+ final InstanceFactory instanceFactory = context.getInstanceFactory();
+ for (final Class> requiredClass :
+ element.getAnnotation(ConditionalOnPresentBindings.class).bindings()) {
+ if (!instanceFactory.hasBinding(Key.forClass(requiredClass))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ConfigurableInstanceFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ConfigurableInstanceFactory.java
index fd165fa0912..60a0316a693 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ConfigurableInstanceFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ConfigurableInstanceFactory.java
@@ -33,10 +33,11 @@
import org.apache.logging.log4j.plugins.validation.ConstraintValidationException;
import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
import org.apache.logging.log4j.util.Cast;
+import org.apache.logging.log4j.util.PropertyEnvironment;
/**
* Configuration manager for the state of an instance factory. Configurable instance factories can form a
- * hierarchy by {@linkplain #newChildInstanceFactory() creating children factories} to enable inheritance
+ * hierarchy by {@linkplain #newChildInstanceFactory} creating children factories} to enable inheritance
* of bindings, scopes, factory resolvers, instance post-processors, and reflection agents.
*/
public interface ConfigurableInstanceFactory extends InstanceFactory {
@@ -131,6 +132,15 @@ default void registerBundles(final Object... bundles) {
*/
ConfigurableInstanceFactory newChildInstanceFactory();
+ /**
+ * Creates a new child instance factory from this factory which uses bindings from this factory as fallback
+ * bindings.
+ *
+ * @return new child instance factory
+ */
+ ConfigurableInstanceFactory newChildInstanceFactory(
+ Supplier environment, Supplier loader);
+
/**
* Sets the {@link ReflectionAgent} used for invoking {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
* from an appropriate caller class. Customizing this allows for changing the base module that other modules should
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInstanceFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInstanceFactory.java
index f0d95ba9bc5..1a7ddb90e87 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInstanceFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInstanceFactory.java
@@ -73,15 +73,26 @@ public class DefaultInstanceFactory implements ConfigurableInstanceFactory {
private ReflectionAgent agent = object -> object.setAccessible(true);
protected DefaultInstanceFactory() {
- this(BindingMap.newRootMap(), HierarchicalMap.newRootMap(), new ArrayList<>(), List.of());
+ this(
+ BindingMap.newRootMap(),
+ HierarchicalMap.newRootMap(),
+ new ArrayList<>(),
+ List.of(),
+ PropertiesUtil::getProperties,
+ LoaderUtil::getClassLoader);
}
- protected DefaultInstanceFactory(final DefaultInstanceFactory parent) {
+ private DefaultInstanceFactory(
+ final DefaultInstanceFactory parent,
+ final Supplier environment,
+ final Supplier loader) {
this(
parent.bindings.newChildMap(),
parent.scopes.newChildMap(),
parent.factoryResolvers,
- parent.instancePostProcessors);
+ parent.instancePostProcessors,
+ environment,
+ loader);
this.agent = parent.agent;
}
@@ -89,7 +100,9 @@ private DefaultInstanceFactory(
final BindingMap bindings,
final HierarchicalMap, Scope> scopes,
final List> factoryResolvers,
- final Collection instancePostProcessors) {
+ final Collection instancePostProcessors,
+ final Supplier environment,
+ final Supplier loader) {
this.bindings = bindings;
this.scopes = scopes;
this.factoryResolvers = factoryResolvers;
@@ -97,8 +110,8 @@ private DefaultInstanceFactory(
this.bindings.put(InjectionPoint.CURRENT_INJECTION_POINT, currentInjectionPoint::get);
this.bindings.put(Key.forClass(ConfigurableInstanceFactory.class), () -> this);
this.bindings.put(Key.forClass(InstanceFactory.class), () -> this);
- this.bindings.put(Key.forClass(PropertyEnvironment.class), PropertiesUtil::getProperties);
- this.bindings.put(Key.forClass(ClassLoader.class), LoaderUtil::getClassLoader);
+ this.bindings.put(Key.forClass(PropertyEnvironment.class), environment);
+ this.bindings.put(Key.forClass(ClassLoader.class), loader);
}
@Override
@@ -336,7 +349,16 @@ public void registerInstancePostProcessor(final InstancePostProcessor instancePo
@Override
public ConfigurableInstanceFactory newChildInstanceFactory() {
- return new DefaultInstanceFactory(this);
+ return new DefaultInstanceFactory(
+ this,
+ bindings.get(Key.forClass(PropertyEnvironment.class), List.of()),
+ bindings.get(Key.forClass(ClassLoader.class), List.of()));
+ }
+
+ @Override
+ public ConfigurableInstanceFactory newChildInstanceFactory(
+ final Supplier environment, final Supplier loader) {
+ return new DefaultInstanceFactory(this, environment, loader);
}
@Override