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 2020/08/01 19:31:56 UTC

[logging-log4j2] branch master updated: LOG4J2-2901 - Missing configuration files should be ignored when creating a composite configuration

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


The following commit(s) were added to refs/heads/master by this push:
     new 5f67313  LOG4J2-2901 - Missing configuration files should be ignored when creating a composite configuration
5f67313 is described below

commit 5f67313e61599fd18452932068afd04e48fb866c
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sat Aug 1 12:31:46 2020 -0700

    LOG4J2-2901 - Missing configuration files should be ignored when creating a composite configuration
---
 .../log4j/core/config/ConfigurationFactory.java    | 18 +++++--
 .../log4j/core/config/ConfigurationSource.java     | 56 +++++++++++++++-------
 .../log4j/core/impl/Log4jContextFactory.java       | 35 ++++++++++----
 .../config/CompositeConfigurationMissingTest.java  | 48 +++++++++++++++++++
 .../core/config/CompositeConfigurationTest.java    | 19 ++++++++
 .../src/test/resources/log4j-comp-logger-root.xml  |  4 +-
 .../log4j/web/Log4jWebInitializerImplTest.java     |  2 +-
 .../src/test/resources/log4j2-combined.xml         | 39 +++++----------
 .../src/test/resources/log4j2-override.xml         | 31 ++----------
 src/changes/changes.xml                            |  3 ++
 10 files changed, 169 insertions(+), 86 deletions(-)

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 7112f56..f89d11f 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
@@ -403,14 +403,22 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
                         final List<AbstractConfiguration> configs = new ArrayList<>();
                         for (final String sourceLocation : sources) {
                             final Configuration config = getConfiguration(loggerContext, sourceLocation.trim());
-                            if (config != null && config instanceof AbstractConfiguration) {
-                                configs.add((AbstractConfiguration) config);
+                            if (config != null) {
+                                if (config instanceof AbstractConfiguration) {
+                                    configs.add((AbstractConfiguration) config);
+                                } else {
+                                    LOGGER.error("Failed to created configuration at {}", sourceLocation);
+                                    return null;
+                                }
                             } else {
-                                LOGGER.error("Failed to created configuration at {}", sourceLocation);
-                                return null;
+                                LOGGER.warn("Unable to create configuration for {}, ignoring", sourceLocation);
                             }
                         }
-                        return new CompositeConfiguration(configs);
+                        if (configs.size() > 1) {
+                            return new CompositeConfiguration(configs);
+                        } else if (configs.size() == 1) {
+                            return configs.get(0);
+                        }
                     }
                     return getConfiguration(loggerContext, configLocationStr);
                 } else {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
index ad94891..4db5ce3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
@@ -31,12 +31,18 @@ import java.net.URL;
 import java.net.URLConnection;
 import java.util.Objects;
 
-import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.net.UrlConnectionFactory;
+import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier;
+import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
+import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
+import org.apache.logging.log4j.core.util.AuthorizationProvider;
 import org.apache.logging.log4j.core.util.FileUtils;
 import org.apache.logging.log4j.core.util.Loader;
 import org.apache.logging.log4j.core.util.Source;
 import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+import javax.net.ssl.HttpsURLConnection;
 
 /**
  * Represents the source for the logging configuration.
@@ -320,6 +326,7 @@ public class ConfigurationSource {
             if (source != null) {
                 return source;
             }
+            return null;
         }
         if (!configLocation.isAbsolute()) { // LOG4J2-704 avoid confusing error message thrown by uri.toURL()
             ConfigurationFactory.LOGGER.error("File not found in file system or classpath: {}", configLocation.toString());
@@ -331,6 +338,8 @@ public class ConfigurationSource {
             InputStream is = urlConnection.getInputStream();
             long lastModified = urlConnection.getLastModified();
             return new ConfigurationSource(is, configLocation.toURL(), lastModified);
+        } catch (final FileNotFoundException ex) {
+            ConfigurationFactory.LOGGER.warn("Could not locate file {}", configLocation.toString());
         } catch (final MalformedURLException ex) {
             ConfigurationFactory.LOGGER.error("Invalid URL {}", configLocation.toString(), ex);
         } catch (final Exception ex) {
@@ -350,25 +359,38 @@ public class ConfigurationSource {
         if (url == null) {
             return null;
         }
-        InputStream is = null;
+        return getConfigurationSource(url);
+    }
+
+    private static ConfigurationSource getConfigurationSource(URL url) {
         try {
-            is = url.openStream();
-        } catch (final IOException ioe) {
-            ConfigurationFactory.LOGGER.catching(Level.DEBUG, ioe);
-            return null;
-        }
-        if (is == null) {
-            return null;
-        }
-    
-        if (FileUtils.isFile(url)) {
+            URLConnection urlConnection = url.openConnection();
+            AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties());
+            provider.addAuthorization(urlConnection);
+            if (url.getProtocol().equals(HTTPS)) {
+                SslConfiguration sslConfiguration = SslConfigurationFactory.getSslConfiguration();
+                if (sslConfiguration != null) {
+                    ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory());
+                    if (!sslConfiguration.isVerifyHostName()) {
+                        ((HttpsURLConnection) urlConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
+                    }
+                }
+            }
+            File file = FileUtils.fileFromUri(url.toURI());
             try {
-                return new ConfigurationSource(is, FileUtils.fileFromUri(url.toURI()));
-            } catch (final URISyntaxException ex) {
-                // Just ignore the exception.
-                ConfigurationFactory.LOGGER.catching(Level.DEBUG, ex);
+                if (file != null) {
+                    return new ConfigurationSource(urlConnection.getInputStream(), FileUtils.fileFromUri(url.toURI()));
+                } else {
+                    return new ConfigurationSource(urlConnection.getInputStream(), url, urlConnection.getLastModified());
+                }
+            } catch (FileNotFoundException ex) {
+                ConfigurationFactory.LOGGER.info("Unable to locate file {}, ignoring.", url.toString());
+                return null;
             }
+        } catch (IOException | URISyntaxException ex) {
+            ConfigurationFactory.LOGGER.warn("Error accessing {} due to {}, ignoring.", url.toString(),
+                    ex.getMessage());
+            return null;
         }
-        return new ConfigurationSource(is, url);
     }
 }
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 1ca8280..56d0e78 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
@@ -24,6 +24,7 @@ import java.util.Objects;
 import org.apache.logging.log4j.core.LifeCycle;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
@@ -265,18 +266,34 @@ public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallba
                 for (final URI configLocation : configLocations) {
                     final Configuration currentReadConfiguration = ConfigurationFactory.getInstance()
                             .getConfiguration(ctx, name, configLocation);
-                    if (currentReadConfiguration instanceof AbstractConfiguration) {
-                        configurations.add((AbstractConfiguration) currentReadConfiguration);
+                    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());
                     }
                 }
-                final CompositeConfiguration compositeConfiguration = new CompositeConfiguration(configurations);
-                LOGGER.debug("Starting LoggerContext[name={}] from configurations at {}", ctx.getName(),
-                        configLocations);
-                ctx.start(compositeConfiguration);
+                if (configurations.size() == 0) {
+                    LOGGER.error("No configurations could be created for {}", configLocations.toString());
+                } else if (configurations.size() == 1) {
+                    AbstractConfiguration config = configurations.get(0);
+                    LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(),
+                            config.getConfigurationSource().getLocation());
+                    ctx.start(config);
+                } else {
+                    final CompositeConfiguration compositeConfiguration = new CompositeConfiguration(configurations);
+                    LOGGER.debug("Starting LoggerContext[name={}] from configurations at {}", ctx.getName(),
+                            configLocations);
+                    ctx.start(compositeConfiguration);
+                }
                 ContextAnchor.THREAD_CONTEXT.remove();
             } else {
                 ctx.start();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationMissingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationMissingTest.java
new file mode 100644
index 0000000..81693a4
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationMissingTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class CompositeConfigurationMissingTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("log4j2.configurationFile", "classpath:log4j-comp-logger-root.xml,log4j-does-not-exist.json");
+    }
+
+    @Test
+    public void testMissingConfig() {
+        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+
+        final AbstractConfiguration config = (AbstractConfiguration) ctx.getConfiguration();
+        assertNotNull("No configuration returned", config);
+        //Test for Root log level override
+        assertEquals("Expected Root logger log level to be ERROR", Level.ERROR, config.getRootLogger().getLevel());
+
+        //Test for no cat2 level override
+        final LoggerConfig cat2 = config.getLogger("cat2");
+        assertEquals("Expected cat2 log level to be INFO", Level.DEBUG, cat2.getLevel());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
index 845573c..ae59552 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
@@ -168,6 +168,25 @@ public class CompositeConfigurationTest {
     }
 
     @Test
+    public void testMissingConfig() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger-root.xml,log4j-does-not-exist.json");
+        final Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final AbstractConfiguration config =  (AbstractConfiguration) lcr.getConfiguration();
+                assertNotNull("No configuration returned", config);
+                //Test for Root log level override
+                assertEquals("Expected Root logger log level to be ERROR", Level.ERROR, config.getRootLogger().getLevel());
+
+                //Test for no cat2 level override
+                final LoggerConfig cat2 = config.getLogger("cat2");
+                assertEquals("Expected cat2 log level to be INFO", Level.DEBUG, cat2.getLevel());
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
     public void testAppenderRefFilterMerge() {
         final LoggerContextRule lcr = new LoggerContextRule(
                 "classpath:log4j-comp-logger-ref.xml,log4j-comp-logger-ref.json");
diff --git a/log4j-core/src/test/resources/log4j-comp-logger-root.xml b/log4j-core/src/test/resources/log4j-comp-logger-root.xml
index dcf2605..407b3c6 100644
--- a/log4j-core/src/test/resources/log4j-comp-logger-root.xml
+++ b/log4j-core/src/test/resources/log4j-comp-logger-root.xml
@@ -16,12 +16,12 @@
  limitations under the License.
 
 -->
-<Configuration status="ERROR" name="LoggerConfigTest">
+<Configuration status="INFO" name="LoggerConfigTest">
     <Appenders>
         <Console name="STDOUT">
             <PatternLayout pattern="%m%n"/>
         </Console>
-        <File name="File" fileName="${filename}" bufferedIO="false">
+        <File name="File" fileName="target/test.log" bufferedIO="false">
             <PatternLayout>
                 <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
             </PatternLayout>
diff --git a/log4j-web/src/test/java/org/apache/logging/log4j/web/Log4jWebInitializerImplTest.java b/log4j-web/src/test/java/org/apache/logging/log4j/web/Log4jWebInitializerImplTest.java
index 9da3ba1..71d0cf2 100644
--- a/log4j-web/src/test/java/org/apache/logging/log4j/web/Log4jWebInitializerImplTest.java
+++ b/log4j-web/src/test/java/org/apache/logging/log4j/web/Log4jWebInitializerImplTest.java
@@ -393,7 +393,7 @@ public class Log4jWebInitializerImplTest {
     public void testCompositeLocationParameterSetsCompositeConfiguration() {
         given(servletContext.getInitParameter(eq(Log4jWebSupport.LOG4J_CONTEXT_NAME))).willReturn("mycontext");
         given(servletContext.getInitParameter(eq(Log4jWebSupport.LOG4J_CONFIG_LOCATION))).willReturn(
-                "/a.txt,,/WEB-INF/log4j2-mycontext.xml");
+                "log4j2-combined.xml,log4j2-override.xml");
 
         this.initializerImpl.start();
 
diff --git a/log4j-core/src/test/resources/log4j-comp-logger-root.xml b/log4j-web/src/test/resources/log4j2-combined.xml
similarity index 52%
copy from log4j-core/src/test/resources/log4j-comp-logger-root.xml
copy to log4j-web/src/test/resources/log4j2-combined.xml
index dcf2605..043d972 100644
--- a/log4j-core/src/test/resources/log4j-comp-logger-root.xml
+++ b/log4j-web/src/test/resources/log4j2-combined.xml
@@ -16,29 +16,16 @@
  limitations under the License.
 
 -->
-<Configuration status="ERROR" name="LoggerConfigTest">
-    <Appenders>
-        <Console name="STDOUT">
-            <PatternLayout pattern="%m%n"/>
-        </Console>
-        <File name="File" fileName="${filename}" bufferedIO="false">
-            <PatternLayout>
-                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
-            </PatternLayout>
-        </File>
-    </Appenders>
-
-    <Loggers>
-        <Logger name="cat1" level="debug" additivity="false">
-            <AppenderRef ref="File"/>
-        </Logger>
-
-        <Logger name="cat2" level="debug" additivity="false">
-            <AppenderRef ref="File"/>
-        </Logger>
-        <Root>
-            <AppenderRef ref="STDOUT" />
-        </Root>
-    </Loggers>
-
-</Configuration>
+<Configuration status="OFF">
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" />
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.foo" level="DEBUG" />
+    <Root level="TRACE">
+      <AppenderRef ref="Console" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-core/src/test/resources/log4j-comp-logger-root.xml b/log4j-web/src/test/resources/log4j2-override.xml
similarity index 52%
copy from log4j-core/src/test/resources/log4j-comp-logger-root.xml
copy to log4j-web/src/test/resources/log4j2-override.xml
index dcf2605..bba8f9d 100644
--- a/log4j-core/src/test/resources/log4j-comp-logger-root.xml
+++ b/log4j-web/src/test/resources/log4j2-override.xml
@@ -16,29 +16,8 @@
  limitations under the License.
 
 -->
-<Configuration status="ERROR" name="LoggerConfigTest">
-    <Appenders>
-        <Console name="STDOUT">
-            <PatternLayout pattern="%m%n"/>
-        </Console>
-        <File name="File" fileName="${filename}" bufferedIO="false">
-            <PatternLayout>
-                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
-            </PatternLayout>
-        </File>
-    </Appenders>
-
-    <Loggers>
-        <Logger name="cat1" level="debug" additivity="false">
-            <AppenderRef ref="File"/>
-        </Logger>
-
-        <Logger name="cat2" level="debug" additivity="false">
-            <AppenderRef ref="File"/>
-        </Logger>
-        <Root>
-            <AppenderRef ref="STDOUT" />
-        </Root>
-    </Loggers>
-
-</Configuration>
+<Configuration>
+  <Loggers>
+    <Logger name="org.foo" level="ERROR" />
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ad89e8b..ead2719 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -181,6 +181,9 @@
       </action>
     </release>
     <release version="2.14.0" date="2020-MM-DD" description="GA Release 2.14.0">
+      <action issue="LOG4J2-2901" dev="rgoers" type="fix">
+        Missing configuration files should be ignored when creating a composite configuration.
+      </action>
       <action issue="LOG4J2-2883" dev="rgoers" type="fix">
         When using DirectFileRolloverStrategy the file pattern was not being recalculated on
         size based rollover after a time based rollover had occurred.