This is an automated email from the ASF dual-hosted git repository. rgoers pushed a commit to branch Spring-33450 in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 7c4452bca03b38203e0a3c9a7322fd25ed289c5f Author: Ralph Goers <[email protected]> AuthorDate: Mon Dec 4 20:15:38 2023 -0700 1799 - Spring shutdown fails due to ClassCastException. Spring 33450 - Spring shutdown fails due to IllegalStateException --- .../logging/log4j/util/PropertiesUtilTest.java | 38 +++ .../apache/logging/log4j/util/PropertiesUtil.java | 58 ++++- .../logging/log4j/util/PropertyEnvironment.java | 6 + .../logging/log4j/core/LoggerContextTest.java | 46 ++++ .../log4j/core/config/MissingRootLoggerTest.java | 6 +- .../java/org/apache/logging/log4j/core/Logger.java | 11 + .../apache/logging/log4j/core/LoggerContext.java | 10 + .../log4j/core/config/ConfigurationFactory.java | 12 + .../log4j/core/impl/Log4jContextFactory.java | 219 +++++++++------- .../core/impl/internal/InternalLoggerContext.java | 290 +++++++++++++++++++++ .../org/apache/logging/log4j/core/jmx/Server.java | 12 +- .../.3.x.x/1799_ignore _propertysource_errors.xml | 10 + 12 files changed, 608 insertions(+), 110 deletions(-) diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/PropertiesUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/PropertiesUtilTest.java index 5aef842655..cb836fd617 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/PropertiesUtilTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/PropertiesUtilTest.java @@ -140,6 +140,23 @@ public class PropertiesUtilTest { assertEquals("Log4j", value); } + @Test + @ResourceLock(Resources.SYSTEM_PROPERTIES) + public void testBadPropertysource() { + final String key1 = "testKey"; + System.getProperties().put(key1, "test"); + final PropertiesUtil util = new PropertiesUtil(new Properties()); + ErrorPropertySource source = new ErrorPropertySource(); + util.addPropertySource(source); + try { + assertEquals("test", util.getStringProperty(key1)); + assertTrue(source.exceptionThrown); + } finally { + util.removePropertySource(source); + System.getProperties().remove(key1); + } + } + private static final String[][] data = { {null, "org.apache.logging.log4j.level"}, {null, "Log4jAnotherProperty"}, @@ -184,4 +201,25 @@ public class PropertiesUtilTest { final PropertiesUtil util = new PropertiesUtil(props); assertNull(util.getStringProperty(correct)); } + + private class ErrorPropertySource implements PropertySource { + public boolean exceptionThrown = false; + + @Override + public int getPriority() { + return Integer.MIN_VALUE; + } + + @Override + public String getProperty(String key) { + exceptionThrown = true; + throw new InstantiationError("Test"); + } + + @Override + public boolean containsProperty(String key) { + exceptionThrown = true; + throw new InstantiationError("Test"); + } + } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java index cf4e011ab5..dcb1a4fbad 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java @@ -199,6 +199,13 @@ public class PropertiesUtil implements PropertyEnvironment { } } + @Override + public void removePropertySource(final PropertySource propertySource) { + if (environment != null) { + environment.removePropertySource(propertySource); + } + } + /** * Returns {@code true} if the specified property is defined, regardless of its value (it may not have a value). * @@ -683,6 +690,11 @@ public class PropertiesUtil implements PropertyEnvironment { sources.add(propertySource); } + @Override + public void removePropertySource(final PropertySource propertySource) { + sources.remove(propertySource); + } + private void reload() { literal.clear(); sources.forEach((s) -> { @@ -700,14 +712,14 @@ public class PropertiesUtil implements PropertyEnvironment { sources.forEach(source -> { if (source instanceof ContextAwarePropertySource) { final ContextAwarePropertySource src = Cast.cast(source); - if (src.containsProperty(contextName, contextKey)) { + if (sourceContainsProperty(src, contextName, contextKey)) { literal.putIfAbsent(key, src.getProperty(contextName, contextKey)); } } }); } sources.forEach(source -> { - if (source.containsProperty(contextKey)) { + if (sourceContainsProperty(source, contextKey)) { literal.putIfAbsent(key, source.getProperty(contextKey)); } }); @@ -727,7 +739,7 @@ public class PropertiesUtil implements PropertyEnvironment { while (source != null) { if (source instanceof ContextAwarePropertySource) { final ContextAwarePropertySource src = Cast.cast(source); - result = src.getProperty(contextName, contextKey); + result = sourceGetProperty(src, contextName, contextKey); } if (result != null) { return result; @@ -737,7 +749,7 @@ public class PropertiesUtil implements PropertyEnvironment { } PropertySource source = sources.first(); while (source != null) { - result = source.getProperty(contextKey); + result = sourceGetProperty(source, contextKey); if (result != null) { return result; } @@ -746,6 +758,22 @@ public class PropertiesUtil implements PropertyEnvironment { return result; } + private String sourceGetProperty(ContextAwarePropertySource source, String contextName, String key) { + try { + return source.getProperty(contextName, key); + } catch (Throwable ex) { + return null; + } + } + + private String sourceGetProperty(PropertySource source, String key) { + try { + return source.getProperty(key); + } catch (Throwable ex) { + return null; + } + } + @Override public boolean hasProperty(final String key) { if (literal.containsKey(key)) { @@ -758,7 +786,7 @@ public class PropertiesUtil implements PropertyEnvironment { while (source != null) { if (source instanceof ContextAwarePropertySource) { final ContextAwarePropertySource src = Cast.cast(source); - if (src.containsProperty(contextName, contextKey)) { + if (sourceContainsProperty(src, contextName, contextKey)) { return true; } } @@ -769,9 +797,9 @@ public class PropertiesUtil implements PropertyEnvironment { while (source != null) { if (source instanceof ContextAwarePropertySource) { final ContextAwarePropertySource src = Cast.cast(source); - if (src.containsProperty(contextName, contextKey) + if (sourceContainsProperty(src, contextName, contextKey) || (!contextName.equals(PropertySource.SYSTEM_CONTEXT) - && src.containsProperty(PropertySource.SYSTEM_CONTEXT, contextKey))) { + && sourceContainsProperty(src, PropertySource.SYSTEM_CONTEXT, contextKey))) { return true; } } else { @@ -784,6 +812,22 @@ public class PropertiesUtil implements PropertyEnvironment { return false; } + private boolean sourceContainsProperty(ContextAwarePropertySource source, String contextName, String key) { + try { + return source.containsProperty(contextName, key); + } catch (Throwable ex) { + return false; + } + } + + private boolean sourceContainsProperty(PropertySource source, String key) { + try { + return source.containsProperty(key); + } catch (Throwable ex) { + return false; + } + } + private String getContextKey(final String key) { String keyToCheck = key; if (keyToCheck.startsWith(PropertySource.PREFIX)) { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyEnvironment.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyEnvironment.java index 3947e7ab62..701bcf6955 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyEnvironment.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyEnvironment.java @@ -28,6 +28,12 @@ public interface PropertyEnvironment { */ void addPropertySource(PropertySource propertySource); + /** + * Allows a PropertySource that was added to be removed. + * @param propertySource the PropertySource to remove. + */ + void removePropertySource(PropertySource propertySource); + /** * Returns {@code true} if the specified property is defined, regardless of its value (it may not have a value). * 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 new file mode 100644 index 0000000000..4b2f417de1 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerContextTest.java @@ -0,0 +1,46 @@ +/* + * 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(); + LoggerContext loggerContext = factory.getContext(LoggerContextTest.class.getName(), null, null, false); + assertTrue(loggerContext instanceof InternalLoggerContext); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MissingRootLoggerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MissingRootLoggerTest.java index de0ce39370..b1d5778e97 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MissingRootLoggerTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MissingRootLoggerTest.java @@ -21,6 +21,7 @@ import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.*; import java.util.Map; @@ -48,7 +49,7 @@ public class MissingRootLoggerTest { assertNotNull(map, "Appenders not null"); assertThat("There should only be two appenders", map, hasSize(2)); assertThat(map, hasKey("List")); - assertThat(map, hasKey("DefaultConsole-2")); + assertThat(map, hasKey(startsWith("DefaultConsole-"))); final Map<String, LoggerConfig> loggerMap = config.getLoggers(); assertNotNull(loggerMap, "loggerMap not null"); @@ -67,7 +68,8 @@ public class MissingRootLoggerTest { final Map<String, Appender> rootAppenders = root.getAppenders(); assertThat("The root logger should only have one appender", rootAppenders, hasSize(1)); // root only has Console appender! - assertThat("The root appender should be a ConsoleAppender", rootAppenders, hasKey("DefaultConsole-2")); + assertThat( + "The root appender should be a ConsoleAppender", rootAppenders, hasKey(startsWith("DefaultConsole-"))); assertEquals(Level.ERROR, root.getLevel()); } } 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 d7a0c532ce..1ab8eae227 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 @@ -66,6 +66,17 @@ public class Logger extends AbstractLogger implements Supplier<LoggerConfig> { privateConfig = new PrivateConfig(context.getConfiguration(), this); } + /** + * This is used to construct an InternalLoggerContext, which makes SimpleLoggerContext conmpatible with core. + * @param context the InternalLoggerContext. + * @param name the Logger name. + */ + protected Logger(final LoggerContext context, final String name) { + super(name); + this.context = context; + privateConfig = null; + } + /** * This method is only used for 1.x compatibility. Returns the parent of this Logger. If it doesn't already exist * return a temporary Logger. 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 c0da220b40..7a70e0a61c 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 @@ -99,6 +99,15 @@ 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. * @@ -428,6 +437,7 @@ public class LoggerContext extends AbstractLifeCycle } this.setStopping(); + String name = getName(); try { Server.unregisterLoggerContext(getName()); // LOG4J2-406, LOG4J2-500 } catch (final LinkageError | Exception e) { 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 257a61a5d6..0898b7a98f 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 @@ -21,12 +21,15 @@ 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.impl.Log4jPropertyKey; +import org.apache.logging.log4j.core.util.AuthorizationProvider; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory; import org.apache.logging.log4j.plugins.di.Key; import org.apache.logging.log4j.plugins.model.PluginNamespace; 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; /** @@ -118,6 +121,15 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory { return true; } + /** + * Required for Spring Boot. + * @param props PropertiesUtil. + * @return the AuthorizationProvider, if any. + */ + public static AuthorizationProvider authorizationProvider(final PropertiesUtil props) { + return AuthorizationProvider.getAuthorizationProvider((PropertyEnvironment) props); + } + public abstract Configuration getConfiguration(final LoggerContext loggerContext, ConfigurationSource source); /** 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 59e2de4ac6..e805c843f0 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 @@ -30,6 +30,7 @@ import org.apache.logging.log4j.core.config.Configuration; 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; @@ -54,6 +55,8 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba private final ContextSelector selector; private final ShutdownCallbackRegistry shutdownCallbackRegistry; + private final LoggerContext internalContext = new InternalLoggerContext(); + /** * Initializes the ContextSelector from system property {@link Log4jPropertyKey#CONTEXT_SELECTOR_CLASS_NAME}. */ @@ -146,8 +149,12 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } - if (ctx.getState() == LifeCycle.State.INITIALIZED) { - startContext(ctx, classLoader); + try { + if (ctx.getState() == LifeCycle.State.INITIALIZED) { + startContext(ctx, classLoader); + } + } catch (IllegalStateException ex) { + return internalContext; } return ctx; } @@ -223,23 +230,27 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba if (externalContext != null && ctx.getExternalContext() == null) { ctx.setExternalContext(externalContext); } - 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(); + try { + 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(); } - ContextAnchor.THREAD_CONTEXT.remove(); } + } catch (IllegalStateException ex) { + return internalContext; } return ctx; } @@ -271,29 +282,34 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba if (name != null) { ctx.setName(name); } - 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(); + try { + 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(); } - ContextAnchor.THREAD_CONTEXT.remove(); + } else { + startContext(ctx, classLoader); } - } else { - startContext(ctx, classLoader); } + } catch (IllegalStateException ex) { + return internalContext; } return ctx; } @@ -311,29 +327,34 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba if (name != null) { ctx.setName(name); } - 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(); + try { + 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(); } - ContextAnchor.THREAD_CONTEXT.remove(); + } else { + startContext(ctx, classLoader); } - } else { - startContext(ctx, classLoader); } + } catch (IllegalStateException ex) { + return internalContext; } return ctx; } @@ -355,52 +376,58 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba if (name != null) { ctx.setName(name); } - if (ctx.getState() == LifeCycle.State.INITIALIZED) { - if ((configLocations != null && !configLocations.isEmpty())) { - ContextAnchor.THREAD_CONTEXT.set(ctx); - boolean setProperties = false; - try { - final List<AbstractConfiguration> 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) { - if (currentReadConfiguration instanceof DefaultConfiguration) { - LOGGER.warn("Unable to locate configuration {}, ignoring", configLocation.toString()); - } else if (currentReadConfiguration instanceof AbstractConfiguration) { - configurations.add((AbstractConfiguration) currentReadConfiguration); + try { + if (ctx.getState() == LifeCycle.State.INITIALIZED) { + if ((configLocations != null && !configLocations.isEmpty())) { + ContextAnchor.THREAD_CONTEXT.set(ctx); + boolean setProperties = false; + try { + final List<AbstractConfiguration> 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) { + if (currentReadConfiguration instanceof DefaultConfiguration) { + LOGGER.warn( + "Unable to locate configuration {}, ignoring", configLocation.toString()); + } else if (currentReadConfiguration instanceof AbstractConfiguration) { + configurations.add((AbstractConfiguration) currentReadConfiguration); + } else { + LOGGER.error( + "Found configuration {}, which is not an AbstractConfiguration and can't be handled by CompositeConfiguration", + configLocation); + } } else { - LOGGER.error( - "Found configuration {}, which is not an AbstractConfiguration and can't be handled by CompositeConfiguration", - configLocation); + LOGGER.info("Unable to access configuration {}, ignoring", configLocation.toString()); } + } + if (configurations.isEmpty()) { + LOGGER.error("No configurations could be created for {}", configLocations.toString()); + } else if (configurations.size() == 1) { + ctx.start(configurations.get(0)); } else { - LOGGER.info("Unable to access configuration {}, ignoring", configLocation.toString()); + final CompositeConfiguration compositeConfiguration = + new CompositeConfiguration(configurations); + ctx.start(compositeConfiguration); } + } finally { + if (setProperties) { + PropertiesUtil.clearThreadProperties(); + } + ContextAnchor.THREAD_CONTEXT.remove(); } - if (configurations.isEmpty()) { - LOGGER.error("No configurations could be created for {}", configLocations.toString()); - } else if (configurations.size() == 1) { - ctx.start(configurations.get(0)); - } else { - final CompositeConfiguration compositeConfiguration = - new CompositeConfiguration(configurations); - ctx.start(compositeConfiguration); - } - } finally { - if (setProperties) { - PropertiesUtil.clearThreadProperties(); - } - ContextAnchor.THREAD_CONTEXT.remove(); + } else { + startContext(ctx, classLoader); } - } else { - startContext(ctx, classLoader); } + } catch (IllegalStateException ex) { + return internalContext; } return ctx; } 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 new file mode 100644 index 0000000000..9f7f247721 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/internal/InternalLoggerContext.java @@ -0,0 +1,290 @@ +/* + * 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.Message; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.simple.SimpleLoggerContext; +import org.apache.logging.log4j.spi.ExtendedLogger; + +/** + * Creates a SimpleLoggerContext compatible with log4j-core. This class is internal to Log4j. + */ +public class InternalLoggerContext extends LoggerContext { + + private final SimpleLoggerContext simpleLoggerContext = new SimpleLoggerContext(); + + private static final LoggerConfig LOGGER_CONFIG = new LoggerConfig.RootLogger(); + + public InternalLoggerContext() { + super(); + setStarted(); + } + + @Override + protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) { + 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(InternalLoggerContext loggerContext, String name) { + super(loggerContext, name); + this.loggerContext = loggerContext; + this.logger = simpleLoggerContext.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 + public void logMessage(String fqcn, Level level, Marker marker, Message message, Throwable t) {} + + @Override + protected void log( + Level level, + Marker marker, + String fqcn, + StackTraceElement location, + Message message, + 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<String, Appender> getAppenders() { + return Collections.emptyMap(); + } + + @Override + public Iterator<Filter> 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/jmx/Server.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java index 1a4a7ed744..e7ee25c3d4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java @@ -238,12 +238,14 @@ public final class Server { * @param loggerContextName name of the logger context to unregister */ public static void unregisterLoggerContext(final String loggerContextName) { - if (isJmxDisabled()) { - LOGGER.debug("JMX disabled for Log4j2. Not unregistering MBeans."); - return; + if (loggerContextName != null) { + if (isJmxDisabled()) { + LOGGER.debug("JMX disabled for Log4j2. Not unregistering MBeans."); + return; + } + final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + unregisterLoggerContext(loggerContextName, mbs); } - final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - unregisterLoggerContext(loggerContextName, mbs); } /** diff --git a/src/changelog/.3.x.x/1799_ignore _propertysource_errors.xml b/src/changelog/.3.x.x/1799_ignore _propertysource_errors.xml new file mode 100644 index 0000000000..5810ca6b6f --- /dev/null +++ b/src/changelog/.3.x.x/1799_ignore _propertysource_errors.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://logging.apache.org/log4j/changelog" + xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.2.xsd" + type="changed"> + <issue id="Spring-33450" link="https://github.com/spring-projects/spring-boot/issues/33450"/> + <issue id="1799" link="https://github.com/apache/logging-log4j2/issues/1799"/> + <author id="rgoers"/> + <description format="asciidoc">Ignore exceptions thrown by PropertySources. Eliminate ClassCastException when SimpleLoggerContext is used.</description> +</entry>
