You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2022/09/06 19:30:20 UTC
[logging-log4j2] 02/02: LOG4J2-3589 - Allow Plugins to be injected with the LoggerContext reference
This is an automated email from the ASF dual-hosted git repository.
rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit bb0c70ec1afe867a52efee873fabb3197dabeae8
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Tue Sep 6 11:45:48 2022 -0700
LOG4J2-3589 - Allow Plugins to be injected with the LoggerContext reference
---
.../apache/logging/log4j/core/LoggerContext.java | 11 +++-
.../log4j/core/config/AbstractConfiguration.java | 8 ++-
.../log4j/core/config/LoggerContextAware.java | 35 +++++++++++
.../core/config/plugins/PluginLoggerContext.java | 40 +++++++++++++
.../plugins/visit/PluginLoggerContextVisitor.java | 70 ++++++++++++++++++++++
.../lookup/AbstractLoggerContextAwareLookup.java | 35 +++++++++++
.../logging/log4j/core/lookup/Interpolator.java | 25 +++++++-
.../core/selector/ClassLoaderContextSelector.java | 1 +
.../logging/log4j/spring/boot/SpringLookup.java | 44 ++++++++------
.../log4j/spring/boot/SpringProfileArbiter.java | 39 ++++++++++--
.../spring/boot/Log4j2SpringBootInitTest.java | 2 +
.../log4j/spring/boot/SpringLookupTest.java | 12 +++-
src/changes/changes.xml | 3 +
13 files changed, 296 insertions(+), 29 deletions(-)
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 abdd68cfa6..62d30eb666 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
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.NullConfiguration;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.core.jmx.Server;
+import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.ExecutorServices;
import org.apache.logging.log4j.core.util.NetUtils;
@@ -32,6 +33,7 @@ import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.di.Key;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.spi.LoggerContextShutdownAware;
@@ -70,6 +72,7 @@ public class LoggerContext extends AbstractLifeCycle
* Property name of the property change event fired if the configuration is changed.
*/
public static final String PROPERTY_CONFIG = "config";
+ public static final Key<LoggerContext> KEY = new Key<>() {};
private static final Configuration NULL_CONFIGURATION = new NullConfiguration();
@@ -120,6 +123,7 @@ public class LoggerContext extends AbstractLifeCycle
public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
this(name, externalContext, configLocn, DI.createInjector());
injector.init();
+ injector.registerBindingIfAbsent(KEY, () -> this);
}
/**
@@ -136,7 +140,8 @@ public class LoggerContext extends AbstractLifeCycle
externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
}
this.configLocation = configLocn;
- this.injector = injector;
+ this.injector = injector.copy();
+ injector.registerBindingIfAbsent(KEY, () -> this);
}
/**
@@ -150,6 +155,7 @@ public class LoggerContext extends AbstractLifeCycle
public LoggerContext(final String name, final Object externalContext, final String configLocn) {
this(name, externalContext, configLocn, DI.createInjector());
injector.init();
+ injector.registerBindingIfAbsent(KEY, () -> this);
}
/**
@@ -177,7 +183,8 @@ public class LoggerContext extends AbstractLifeCycle
} else {
configLocation = null;
}
- this.injector = injector;
+ this.injector = injector.copy();
+ this.injector.registerBindingIfAbsent(KEY, () -> this);
}
public void addShutdownListener(final LoggerContextShutdownAware listener) {
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 8c3adced80..a42cf31263 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
@@ -138,7 +138,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
private List<CustomLevelConfig> customLevels = List.of();
private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<>();
private final InterpolatorFactory interpolatorFactory;
- private final StrLookup tempLookup;
+ private final Interpolator tempLookup;
private final StrSubstitutor runtimeStrSubstitutor;
private final StrSubstitutor configurationStrSubstitutor;
private LoggerConfig root = new LoggerConfig();
@@ -168,6 +168,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
componentMap.put(Configuration.CONTEXT_PROPERTIES, properties);
interpolatorFactory = injector.getInstance(InterpolatorFactory.class);
tempLookup = interpolatorFactory.newInterpolator(new PropertiesLookup(properties));
+ tempLookup.setLoggerContext(loggerContext);
runtimeStrSubstitutor = new RuntimeStrSubstitutor(tempLookup);
configurationStrSubstitutor = new ConfigurationStrSubstitutor(runtimeStrSubstitutor);
configurationScheduler = injector.getInstance(ConfigurationScheduler.class);
@@ -641,6 +642,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
protected void doConfigure() {
injector.registerBinding(Keys.SUBSTITUTOR_KEY, () -> configurationStrSubstitutor::replace);
+ injector.registerBinding(LoggerContext.KEY, () -> loggerContext.get());
processConditionals(rootNode);
preConfigure(rootNode);
configurationScheduler.start();
@@ -649,6 +651,9 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
createConfiguration(first, null);
if (first.getObject() != null) {
StrLookup lookup = first.getObject();
+ if (lookup instanceof LoggerContextAware) {
+ ((LoggerContextAware) lookup).setLoggerContext(loggerContext.get());
+ }
runtimeStrSubstitutor.setVariableResolver(lookup);
configurationStrSubstitutor.setVariableResolver(lookup);
}
@@ -656,6 +661,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
final Map<String, String> map = this.getComponent(CONTEXT_PROPERTIES);
final StrLookup lookup = map == null ? null : new PropertiesLookup(map);
Interpolator interpolator = interpolatorFactory.newInterpolator(lookup);
+ interpolator.setLoggerContext(loggerContext.get());
runtimeStrSubstitutor.setVariableResolver(interpolator);
configurationStrSubstitutor.setVariableResolver(interpolator);
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextAware.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextAware.java
new file mode 100644
index 0000000000..e68af4c277
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerContextAware.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.core.config;
+
+import org.apache.logging.log4j.core.LoggerContext;
+
+/**
+ * Indicates that a class requests the current LoggerContext to be injected.
+ *
+ * @since 2.19.0
+ */
+public interface LoggerContextAware {
+
+ /**
+ * Injects the current LoggerContext into this object.
+ *
+ * @param loggerContext the current LoggerContext
+ */
+ void setLoggerContext(LoggerContext loggerContext);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginLoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginLoggerContext.java
new file mode 100644
index 0000000000..2e68001705
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginLoggerContext.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugins;
+
+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;
+
+import org.apache.logging.log4j.core.config.plugins.visit.PluginLoggerContextVisitor;
+import org.apache.logging.log4j.plugins.QualifierType;
+import org.apache.logging.log4j.plugins.visit.NodeVisitor;
+
+/**
+ * Identifies a parameter or field as a LoggerContext.
+ * @see org.apache.logging.log4j.core.LoggerContext
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@NodeVisitor.Kind(PluginLoggerContextVisitor.class)
+@QualifierType
+public @interface PluginLoggerContext {
+ // empty
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginLoggerContextVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginLoggerContextVisitor.java
new file mode 100644
index 0000000000..3306544328
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginLoggerContextVisitor.java
@@ -0,0 +1,70 @@
+/*
+ * 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.plugins.visit;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Parameter;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
+import org.apache.logging.log4j.plugins.visit.NodeVisitor;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.StringBuilders;
+
+/**
+ * PluginVisitor implementation for {@link PluginConfiguration}.
+ */
+public class PluginLoggerContextVisitor implements NodeVisitor {
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private LoggerContext loggerContext;
+
+ @Inject
+ public PluginLoggerContextVisitor(final LoggerContext loggerContext) {
+ this.loggerContext = loggerContext;
+ }
+
+ @Override
+ public Object visitField(final Field field, final Node node, final StringBuilder debugLog) {
+ if (TypeUtil.isAssignable(field.getGenericType(), LoggerContext.class)) {
+ StringBuilders.appendKeyDqValueWithJoiner(debugLog, "loggerContext", loggerContext, ", ");
+ return TypeUtil.cast(loggerContext);
+ } else {
+ LOGGER.error("Field {} annotated with @PluginLoggerContext is not compatible with type {}", field,
+ loggerContext.getClass());
+ return null;
+ }
+ }
+
+ @Override
+ public Object visitParameter(final Parameter parameter, final Node node, final StringBuilder debugLog) {
+ if (TypeUtil.isAssignable(parameter.getParameterizedType(), loggerContext.getClass())) {
+ StringBuilders.appendKeyDqValueWithJoiner(debugLog, "loggerContext", loggerContext, ", ");
+ return TypeUtil.cast(loggerContext);
+ } else {
+ LOGGER.error("Parameter {} annotated with @PluginLoggerContext is not compatible with type {}",
+ parameter, loggerContext.getClass());
+ return null;
+ }
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/AbstractLoggerContextAwareLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/AbstractLoggerContextAwareLookup.java
new file mode 100644
index 0000000000..bec6b4cc9f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/AbstractLoggerContextAwareLookup.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.core.lookup;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.LoggerContextAware;
+
+/**
+ * StrLookup that is ConfigurationAware. Handles saving the Configuration.
+ *
+ * @since 2.6
+ */
+public abstract class AbstractLoggerContextAwareLookup extends AbstractLookup implements LoggerContextAware {
+ protected LoggerContext loggerContext;
+
+ @Override
+ public void setLoggerContext(final LoggerContext loggerContext) {
+ this.loggerContext = loggerContext;
+ }
+}
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 8ccdc51f62..647b6ecb40 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,7 +18,10 @@ 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.LoggerContext;
import org.apache.logging.log4j.core.config.ConfigurationAware;
+import org.apache.logging.log4j.core.config.LoggerContextAware;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Keys;
@@ -34,7 +37,7 @@ import java.util.stream.Collectors;
/**
* Proxies other {@link StrLookup}s using a keys within ${} markers.
*/
-public class Interpolator extends AbstractConfigurationAwareLookup {
+public class Interpolator extends AbstractConfigurationAwareLookup implements LoggerContextAware {
/** Constant for the prefix separator. */
public static final char PREFIX_SEPARATOR = ':';
@@ -57,12 +60,16 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
private final StrLookup defaultLookup;
+ private LoggerContext loggerContext = null;
+
+ // Used by tests
public Interpolator(final StrLookup defaultLookup) {
this(defaultLookup, List.of());
}
/**
* 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
* @param pluginPackages a list of packages to scan for Lookup plugins
@@ -82,6 +89,12 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
});
}
+ /**
+ * Used by interpolatrorFactory.
+ *
+ * @param defaultLookup The default Lookup.
+ * @param strLookupPlugins The Lookup Plugins.
+ */
public Interpolator(final StrLookup defaultLookup, final Map<String, Supplier<StrLookup>> strLookupPlugins) {
this.defaultLookup = defaultLookup;
strLookups.putAll(strLookupPlugins);
@@ -172,6 +185,9 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
if (lookup instanceof ConfigurationAware) {
((ConfigurationAware) lookup).setConfiguration(configuration);
}
+ if (lookup instanceof LoggerContextAware) {
+ ((LoggerContextAware) lookup).setLoggerContext(loggerContext);
+ }
value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
}
@@ -186,6 +202,13 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
return null;
}
+ public void setLoggerContext(final LoggerContext loggerContext) {
+ if (loggerContext == null) {
+ return;
+ }
+ this.loggerContext = loggerContext;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
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 5cc1d36544..372a6103ee 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
@@ -282,6 +282,7 @@ public class ClassLoaderContextSelector implements ContextSelector, LoggerContex
}
protected LoggerContext createContext(final String name, final URI configLocation, final Injector injector) {
+
return new LoggerContext(name, null, configLocation, injector);
}
diff --git a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringLookup.java b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringLookup.java
index 6243d111d3..69e9f41cfb 100644
--- a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringLookup.java
+++ b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringLookup.java
@@ -18,8 +18,11 @@ package org.apache.logging.log4j.spring.boot;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.lookup.AbstractLoggerContextAwareLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.Lookup;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.status.StatusLogger;
import org.springframework.core.env.Environment;
@@ -32,7 +35,7 @@ import java.util.regex.Pattern;
*/
@Lookup
@Plugin("spring")
-public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
+public class SpringLookup extends AbstractLoggerContextAwareLookup {
private static final Logger LOGGER = StatusLogger.getLogger();
private static final String ACTIVE = "profiles.active";
@@ -41,30 +44,27 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
private static final Pattern ACTIVE_PATTERN = Pattern.compile(ACTIVE + PATTERN);
private static final Pattern DEFAULT_PATTERN = Pattern.compile(DEFAULT + PATTERN);
- public SpringLookup() {
- getEnvironment();
- }
+ private Environment environment = null;
@Override
public String lookup(String key) {
- Environment env = getEnvironment();
- if (env != null) {
+ if (environment != null) {
String lowerKey = key.toLowerCase();
if (lowerKey.startsWith(ACTIVE)) {
- switch (env.getActiveProfiles().length) {
+ switch (environment.getActiveProfiles().length) {
case 0: {
return null;
}
case 1: {
- return env.getActiveProfiles()[0];
+ return environment.getActiveProfiles()[0];
}
default: {
Matcher matcher = ACTIVE_PATTERN.matcher(key);
if (matcher.matches()) {
try {
int index = Integer.parseInt(matcher.group(1));
- if (index < env.getActiveProfiles().length) {
- return env.getActiveProfiles()[index];
+ if (index < environment.getActiveProfiles().length) {
+ return environment.getActiveProfiles()[index];
} else {
LOGGER.warn("Index out of bounds for Spring active profiles: {}", index);
return null;
@@ -76,7 +76,7 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
} else {
StringBuilder sb = new StringBuilder();
- for (String profile : env.getActiveProfiles()) {
+ for (String profile : environment.getActiveProfiles()) {
if (sb.length() > 0) {
sb.append(",");
}
@@ -87,20 +87,20 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
}
}
} else if (lowerKey.startsWith(DEFAULT)) {
- switch (env.getDefaultProfiles().length) {
+ switch (environment.getDefaultProfiles().length) {
case 0: {
return null;
}
case 1: {
- return env.getDefaultProfiles()[0];
+ return environment.getDefaultProfiles()[0];
}
default: {
Matcher matcher = DEFAULT_PATTERN.matcher(key);
if (matcher.matches()) {
try {
int index = Integer.parseInt(matcher.group(1));
- if (index < env.getDefaultProfiles().length) {
- return env.getDefaultProfiles()[index];
+ if (index < environment.getDefaultProfiles().length) {
+ return environment.getDefaultProfiles()[index];
} else {
LOGGER.warn("Index out of bounds for Spring default profiles: {}", index);
return null;
@@ -112,7 +112,7 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
} else {
StringBuilder sb = new StringBuilder();
- for (String profile : env.getDefaultProfiles()) {
+ for (String profile : environment.getDefaultProfiles()) {
if (sb.length() > 0) {
sb.append(",");
}
@@ -124,7 +124,7 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
}
}
- return env.getProperty(key);
+ return environment.getProperty(key);
}
return null;
@@ -134,4 +134,14 @@ public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
public String lookup(LogEvent event, String key) {
return lookup((key));
}
+
+ @Override
+ public void setLoggerContext(final LoggerContext loggerContext) {
+ if (loggerContext != null) {
+ super.setLoggerContext(loggerContext);
+ environment = (Environment) loggerContext.getObject(Log4j2SpringBootLoggingSystem.ENVIRONMENT_KEY);
+ } else {
+ LOGGER.warn("Attempt to set LoggerContext reference to null in SpringLookup");
+ }
+ }
}
diff --git a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringProfileArbiter.java b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringProfileArbiter.java
index 8c7a513790..32afc36714 100644
--- a/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringProfileArbiter.java
+++ b/log4j-spring-boot/src/main/java/org/apache/logging/log4j/spring/boot/SpringProfileArbiter.java
@@ -16,13 +16,18 @@
*/
package org.apache.logging.log4j.spring.boot;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.arbiters.Arbiter;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.config.plugins.PluginLoggerContext;
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.status.StatusLogger;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.util.StringUtils;
@@ -32,18 +37,18 @@ import org.springframework.util.StringUtils;
*/
@Configurable(elementType = Arbiter.ELEMENT_TYPE, deferChildren = true, printObject = true)
@Plugin("SpringProfile")
-public class SpringProfileArbiter extends SpringEnvironmentHolder implements Arbiter {
+public class SpringProfileArbiter implements Arbiter {
private final String[] profileNames;
+ private Environment environment;
- private SpringProfileArbiter(final String[] profiles) {
+ private SpringProfileArbiter(final String[] profiles, Environment environment) {
this.profileNames = profiles;
-
+ this.environment = environment;
}
@Override
public boolean isCondition() {
- Environment environment = getEnvironment();
if (environment == null) {
return false;
}
@@ -61,13 +66,18 @@ public class SpringProfileArbiter extends SpringEnvironmentHolder implements Arb
public static class Builder implements org.apache.logging.log4j.core.util.Builder<SpringProfileArbiter> {
+ private final Logger LOGGER = StatusLogger.getLogger();
public static final String ATTR_NAME = "name";
@PluginBuilderAttribute(ATTR_NAME)
private String name;
+ @PluginLoggerContext
+ private LoggerContext loggerContext;
+
@PluginConfiguration
- private Configuration configuration;;
+ private Configuration configuration;
+
/**
* Sets the Profile Name or Names.
@@ -84,6 +94,11 @@ public class SpringProfileArbiter extends SpringEnvironmentHolder implements Arb
return asBuilder();
}
+ public Builder setLoggerContext(final LoggerContext loggerContext) {
+ this.loggerContext = loggerContext;
+ return asBuilder();
+ }
+
private Builder asBuilder() {
return this;
}
@@ -91,7 +106,19 @@ public class SpringProfileArbiter extends SpringEnvironmentHolder implements Arb
public SpringProfileArbiter build() {
String[] profileNames = StringUtils.trimArrayElements(
StringUtils.commaDelimitedListToStringArray(configuration.getStrSubstitutor().replace(name)));
- return new SpringProfileArbiter(profileNames);
+ Environment environment = null;
+ if (loggerContext != null) {
+ environment = (Environment) loggerContext.getObject(Log4j2SpringBootLoggingSystem.ENVIRONMENT_KEY);
+ if (environment == null) {
+ LOGGER.warn("Cannot create Arbiter, no Spring Environment provided");
+ return null;
+ }
+
+ return new SpringProfileArbiter(profileNames, environment);
+ } else {
+ LOGGER.warn("Cannot create Arbiter, LoggerContext is not available");
+ }
+ return null;
}
}
}
diff --git a/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootInitTest.java b/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootInitTest.java
index d909c672db..93077df3dc 100644
--- a/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootInitTest.java
+++ b/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/Log4j2SpringBootInitTest.java
@@ -54,7 +54,9 @@ public class Log4j2SpringBootInitTest {
@Override
public void run(ApplicationArguments args) throws Exception {
+ LoggerContext loggerContext = ((org.apache.logging.log4j.core.Logger) LOGGER).getContext();
SpringLookup lookup = new SpringLookup();
+ lookup.setLoggerContext(loggerContext);
LOGGER.info("Started: {}", lookup.lookup("spring.application.name"));
}
}
diff --git a/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/SpringLookupTest.java b/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/SpringLookupTest.java
index a10e6d9f0e..fba952d793 100644
--- a/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/SpringLookupTest.java
+++ b/log4j-spring-boot/src/test/java/org/apache/logging/log4j/spring/boot/SpringLookupTest.java
@@ -16,9 +16,14 @@
*/
package org.apache.logging.log4j.spring.boot;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
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.junit.Test;
import org.springframework.mock.env.MockEnvironment;
@@ -41,6 +46,7 @@ public class SpringLookupTest {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
context.putObject(Log4j2SpringBootLoggingSystem.ENVIRONMENT_KEY, env);
SpringLookup lookup = new SpringLookup();
+ lookup.setLoggerContext(context);
String result = lookup.lookup("profiles.active");
assertNotNull("No active profiles", result);
assertEquals("Incorrect active profile", "test", result);
@@ -67,8 +73,10 @@ public class SpringLookupTest {
env.setProperty("app.property", "test");
LoggerContext context = (LoggerContext) LogManager.getContext(false);
context.putObject(Log4j2SpringBootLoggingSystem.ENVIRONMENT_KEY, env);
-
- StrLookup lookup = new Interpolator();
+ InterpolatorFactory interpolatorFactory = context.getInjector().getInstance(InterpolatorFactory.class);
+ Map<String, String> properties = new HashMap<>();
+ Interpolator lookup = interpolatorFactory.newInterpolator(new PropertiesLookup(properties));
+ lookup.setLoggerContext(context);
String result = lookup.lookup("spring:profiles.active");
assertNotNull("No active profiles", result);
assertEquals("Incorrect active profile", "test", result);
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a2a0066824..b76a274924 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -202,6 +202,9 @@
</action>
</release>
<release version="2.19.0" date="2022-MM-DD" description="GA Release 2.19.0">
+ <action issue="LOG4J2-3589" dev="rgoers" type="update">
+ Allow Plugins to be injected with the LoggerContext reference.
+ </action>
<action issue="LOG4J2-3588" dev="rgoers" type="update">
Allow PropertySources to be added.
</action>