You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2022/03/28 01:32:16 UTC
[logging-log4j2] 03/03: Add lazy loading support for StrLookup plugins
This is an automated email from the ASF dual-hosted git repository.
mattsicker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e3a462a9be8942b4dfac21a725fb8c509794dc48
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sun Mar 27 20:29:51 2022 -0500
Add lazy loading support for StrLookup plugins
This introduces an InterpolatorFactory binding for reusing bound PluginManager instances to create Interpolator instances from a default StrLookup. This indirection allows for lazy loading of StrLookup plugins while allowing for them to be created via Injector as well.
Signed-off-by: Matt Sicker <ma...@apache.org>
---
.../log4j/core/config/AbstractConfiguration.java | 12 ++--
.../log4j/core/config/ConfigurationFactory.java | 6 +-
.../log4j/core/config/PropertiesPlugin.java | 5 +-
.../logging/log4j/core/impl/DefaultCallback.java | 14 +++++
.../logging/log4j/core/lookup/Interpolator.java | 66 +++++++++-------------
.../log4j/core/lookup/InterpolatorFactory.java | 22 ++++++++
6 files changed, 76 insertions(+), 49 deletions(-)
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 5acf726..266e7af 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
@@ -35,6 +35,7 @@ import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.layout.PatternLayout;
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.PropertiesLookup;
import org.apache.logging.log4j.core.lookup.RuntimeStrSubstitutor;
import org.apache.logging.log4j.core.lookup.StrLookup;
@@ -80,6 +81,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
+import java.util.function.Supplier;
/**
* The base Configuration. Many configuration implementations will extend this class.
@@ -133,6 +135,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
private ConcurrentMap<String, LoggerConfig> loggerConfigs = new ConcurrentHashMap<>();
private List<CustomLevelConfig> customLevels = List.of();
private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<>();
+ private final InterpolatorFactory interpolatorFactory;
private final StrLookup tempLookup;
private final StrSubstitutor runtimeStrSubstitutor;
private final StrSubstitutor configurationStrSubstitutor;
@@ -160,7 +163,8 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
injector.init();
}
componentMap.put(Configuration.CONTEXT_PROPERTIES, properties);
- tempLookup = new Interpolator(new PropertiesLookup(properties), this);
+ interpolatorFactory = injector.getInstance(InterpolatorFactory.class);
+ tempLookup = interpolatorFactory.newInterpolator(new PropertiesLookup(properties));
runtimeStrSubstitutor = new RuntimeStrSubstitutor(tempLookup);
configurationStrSubstitutor = new ConfigurationStrSubstitutor(runtimeStrSubstitutor);
pluginManager = injector.getInstance(Core.PLUGIN_MANAGER_KEY);
@@ -519,8 +523,8 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
}
@Override
- public <T> T getComponent(final Key<T> key) {
- return injector.getInstance(key);
+ public <T> Supplier<T> getFactory(final Key<T> key) {
+ return injector.getFactory(key);
}
@Override
@@ -652,7 +656,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
} else {
final Map<String, String> map = this.getComponent(CONTEXT_PROPERTIES);
final StrLookup lookup = map == null ? null : new PropertiesLookup(map);
- Interpolator interpolator = new Interpolator(lookup, this);
+ Interpolator interpolator = interpolatorFactory.newInterpolator(lookup);
runtimeStrSubstitutor.setVariableResolver(interpolator);
configurationStrSubstitutor.setVariableResolver(interpolator);
}
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 37fd8f1..fc204fa 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
@@ -20,13 +20,12 @@ import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
-import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
-import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
import org.apache.logging.log4j.core.util.AuthorizationProvider;
import org.apache.logging.log4j.core.util.BasicAuthorizationProvider;
import org.apache.logging.log4j.core.util.FileUtils;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.status.StatusLogger;
@@ -147,7 +146,8 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
return provider;
}
- protected final StrSubstitutor substitutor = new ConfigurationStrSubstitutor(new Interpolator());
+ @Inject
+ protected StrSubstitutor substitutor;
protected abstract String[] getSupportedTypes();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java
index 94fede4..52c7904 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/PropertiesPlugin.java
@@ -17,13 +17,14 @@
package org.apache.logging.log4j.core.config;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.core.lookup.Interpolator;
+import org.apache.logging.log4j.core.lookup.InterpolatorFactory;
import org.apache.logging.log4j.core.lookup.PropertiesLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginElement;
import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.di.Key;
import java.util.HashMap;
import java.util.Map;
@@ -56,6 +57,6 @@ public final class PropertiesPlugin {
map.put(prop.getName(), prop.getValue());
}
}
- return new Interpolator(new PropertiesLookup(map), config);
+ return config.getComponent(Key.forClass(InterpolatorFactory.class)).newInterpolator(new PropertiesLookup(map));
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
index 4264355..590222f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
@@ -23,6 +23,10 @@ import org.apache.logging.log4j.ThreadContext;
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.lookup.Interpolator;
+import org.apache.logging.log4j.core.lookup.InterpolatorFactory;
+import org.apache.logging.log4j.core.lookup.StrLookup;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.time.Clock;
@@ -41,6 +45,8 @@ import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.plugins.PluginException;
import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.InjectorCallback;
+import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.plugins.util.PluginManager;
import org.apache.logging.log4j.spi.CopyOnWrite;
import org.apache.logging.log4j.spi.DefaultThreadContextMap;
import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
@@ -119,6 +125,14 @@ public class DefaultCallback implements InjectorCallback {
() -> loader.getInstance(Constants.LOG4J_LOG_EVENT_FACTORY, LogEventFactory.class,
() -> Constants.ENABLE_THREADLOCALS ? ReusableLogEventFactory.class :
DefaultLogEventFactory.class))
+ .registerBindingIfAbsent(Key.forClass(InterpolatorFactory.class),
+ () -> defaultLookup -> {
+ final PluginManager pluginManager = injector.getInstance(StrLookup.PLUGIN_MANAGER_KEY);
+ pluginManager.collectPlugins();
+ return new Interpolator(defaultLookup, pluginManager.getPlugins(), injector::getInstance);
+ })
+ .registerBindingIfAbsent(Key.forClass(StrSubstitutor.class),
+ () -> new StrSubstitutor(injector.getInstance(InterpolatorFactory.class).newInterpolator(null)))
.registerBindingIfAbsent(ConfigurationFactory.KEY, injector.getFactory(DefaultConfigurationFactory.class))
.registerBindingIfAbsent(Constants.DEFAULT_STATUS_LEVEL_KEY, () -> {
final String statusLevel =
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 ca84caf..e238826 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
@@ -18,20 +18,20 @@ package org.apache.logging.log4j.core.lookup;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationAware;
-import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.plugins.di.Key;
-import org.apache.logging.log4j.plugins.util.PluginManager;
import org.apache.logging.log4j.plugins.util.PluginType;
import org.apache.logging.log4j.plugins.util.PluginUtil;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LazyValue;
import org.apache.logging.log4j.util.ReflectionUtil;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
/**
* Proxies other {@link StrLookup}s using a keys within ${} markers.
@@ -55,9 +55,7 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
private static final Logger LOGGER = StatusLogger.getLogger();
- private static final String JNDI_LOOKUP = "org.apache.logging.log4j.jndi.lookup.JndiLookup";
-
- private final Map<String, StrLookup> strLookupMap = new HashMap<>();
+ private final Map<String, Supplier<StrLookup>> strLookups = new ConcurrentHashMap<>();
private final StrLookup defaultLookup;
@@ -73,37 +71,22 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
* @since 2.1
*/
public Interpolator(final StrLookup defaultLookup, final List<String> pluginPackages) {
- this.defaultLookup = defaultLookup == null ? new PropertiesLookup(Map.of()) : defaultLookup;
- final Map<String, PluginType<?>> plugins =
- PluginUtil.collectPluginsByCategoryAndPackage(CATEGORY, pluginPackages);
-
- for (final Map.Entry<String, PluginType<?>> entry : plugins.entrySet()) {
- try {
- final Class<? extends StrLookup> clazz = entry.getValue().getPluginClass().asSubclass(StrLookup.class);
- if (!clazz.getName().equals(JNDI_LOOKUP) || Constants.JNDI_LOOKUP_ENABLED) {
- strLookupMap.put(entry.getKey().toLowerCase(), ReflectionUtil.instantiate(clazz));
- }
- } catch (final Throwable t) {
- handleError(entry.getKey(), t);
- }
- }
+ this(defaultLookup, PluginUtil.collectPluginsByCategoryAndPackage(CATEGORY, pluginPackages), ReflectionUtil::instantiate);
}
- public Interpolator(final StrLookup defaultLookup, final Configuration configuration) {
+ public Interpolator(
+ final StrLookup defaultLookup, final Map<String, PluginType<?>> strLookupPlugins,
+ final Function<Class<? extends StrLookup>, StrLookup> pluginLoader) {
this.defaultLookup = defaultLookup == null ? new PropertiesLookup(Map.of()) : defaultLookup;
- final PluginManager pluginManager = configuration.getComponent(StrLookup.PLUGIN_MANAGER_KEY);
- pluginManager.collectPlugins(configuration.getPluginPackages());
- for (final Map.Entry<String, PluginType<?>> entry : pluginManager.getPlugins().entrySet()) {
+ strLookupPlugins.forEach((key, value) -> {
try {
- final Class<? extends StrLookup> strLookupClass = entry.getValue().getPluginClass().asSubclass(StrLookup.class);
- // TODO: this could use @RequiredProperty on JndiLookup instead
- if (!strLookupClass.getName().equals(JNDI_LOOKUP) || Constants.JNDI_LOOKUP_ENABLED) {
- strLookupMap.put(entry.getKey().toLowerCase(Locale.ROOT), configuration.getComponent(Key.forClass(strLookupClass)));
- }
+ final Class<? extends StrLookup> strLookupClass = value.getPluginClass().asSubclass(StrLookup.class);
+ final Supplier<StrLookup> strLookupSupplier = LazyValue.from(() -> pluginLoader.apply(strLookupClass));
+ strLookups.put(key.toLowerCase(Locale.ROOT), strLookupSupplier);
} catch (final Throwable t) {
- handleError(entry.getKey(), t);
+ handleError(key, t);
}
- }
+ });
}
/**
@@ -125,7 +108,9 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
}
public Map<String, StrLookup> getStrLookupMap() {
- return strLookupMap;
+ return strLookups.entrySet()
+ .stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get()));
}
private void handleError(final String lookupKey, final Throwable t) {
@@ -182,12 +167,13 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
if (prefixPos >= 0) {
final String prefix = var.substring(0, prefixPos).toLowerCase(Locale.US);
final String name = var.substring(prefixPos + 1);
- final StrLookup lookup = strLookupMap.get(prefix);
- if (lookup instanceof ConfigurationAware) {
- ((ConfigurationAware) lookup).setConfiguration(configuration);
- }
+ final Supplier<StrLookup> lookupSupplier = strLookups.get(prefix);
String value = null;
- if (lookup != null) {
+ if (lookupSupplier != null) {
+ final StrLookup lookup = lookupSupplier.get();
+ if (lookup instanceof ConfigurationAware) {
+ ((ConfigurationAware) lookup).setConfiguration(configuration);
+ }
value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
}
@@ -205,7 +191,7 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- for (final String name : strLookupMap.keySet()) {
+ for (final String name : strLookups.keySet()) {
if (sb.length() == 0) {
sb.append('{');
} else {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java
new file mode 100644
index 0000000..3700fe1
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/InterpolatorFactory.java
@@ -0,0 +1,22 @@
+/*
+ * 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.lookup;
+
+public interface InterpolatorFactory {
+ Interpolator newInterpolator(final StrLookup defaultLookup);
+}