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 2016/04/25 15:31:02 UTC

logging-log4j2 git commit: LOG4J2-494 - Support reconfiguration. Fix status logging issues

Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4j2-494 bb64f4577 -> e975a89f7


LOG4J2-494 - Support reconfiguration. Fix status logging issues


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e975a89f
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e975a89f
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e975a89f

Branch: refs/heads/LOG4j2-494
Commit: e975a89f75f3d0200d5033b7286daded67756d6d
Parents: bb64f45
Author: Ralph Goers <rg...@nextiva.com>
Authored: Mon Apr 25 06:31:13 2016 -0700
Committer: Ralph Goers <rg...@nextiva.com>
Committed: Mon Apr 25 06:31:13 2016 -0700

----------------------------------------------------------------------
 .../logging/log4j/status/StatusLogger.java      |   6 +
 .../log4j/core/config/ConfigurationFactory.java |   2 +-
 .../logging/log4j/core/config/Configurator.java |   2 +-
 .../builder/api/ConfigurationBuilder.java       |  17 ++
 .../impl/DefaultConfigurationBuilder.java       |  16 +-
 .../composite/CompositeConfiguration.java       |  63 +++---
 .../config/composite/DefaultMergeStrategy.java  |  38 ++--
 .../core/config/composite/MergeStrategy.java    |   8 +
 .../properties/PropertiesConfiguration.java     |   2 +-
 .../PropertiesConfigurationBuilder.java         |   9 +-
 .../core/config/status/StatusConfiguration.java |   1 +
 .../core/config/CompositeConfigurationTest.java | 191 +++++++++++--------
 .../log4j/core/config/TestConfigurator.java     |  11 +-
 .../src/test/resources/log4j-comp-appender.xml  |   2 +-
 .../src/test/resources/log4j-comp-filter.xml    |   2 +-
 .../test/resources/log4j-comp-properties.xml    |   2 +-
 .../resources/log4j-comp-reconfig.properties    |  59 ++++++
 .../src/test/resources/log4j-comp-reconfig.xml  |  39 ++++
 18 files changed, 339 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
index ebd44d4..902b444 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
@@ -141,6 +141,12 @@ public final class StatusLogger extends AbstractLogger {
         }
     }
 
+    public void updateListenerLevel(final Level status) {
+        if (status.intLevel() > listenersLevel) {
+            listenersLevel = status.intLevel();
+        }
+    }
+
     /**
      * Returns a thread safe Iterable for the StatusListener.
      *

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
----------------------------------------------------------------------
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 41f3571..32cfe90 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
@@ -397,7 +397,7 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
                     if (sources.length > 1) {
                         List<AbstractConfiguration> configs = new ArrayList<>();
                         for (String sourceLocation : sources) {
-                            Configuration config = getConfiguration(sourceLocation);
+                            Configuration config = getConfiguration(sourceLocation.trim());
                             if (config != null && config instanceof AbstractConfiguration) {
                                 configs.add((AbstractConfiguration) config);
                             } else {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
index f0e462e..147c20f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
@@ -119,7 +119,7 @@ public final class Configurator {
             String scheme = null;
             List<URI> uris = new ArrayList<>(parts.length);
             for (String part : parts) {
-                URI uri = NetUtils.toURI(scheme != null ? scheme + ":" + part : part);
+                URI uri = NetUtils.toURI(scheme != null ? scheme + ":" + part.trim() : part.trim());
                 if (scheme == null && uri.getScheme() != null) {
                     scheme = uri.getScheme();
                 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
index 4b4473d..eab7044 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.config.builder.api;
 
+import java.util.Map;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -379,4 +380,20 @@ public interface ConfigurationBuilder<T extends Configuration> extends Builder<T
      * @return this builder instance.
      */
     ConfigurationBuilder<T> setVerbosity(String verbosity);
+
+    /**
+     * Add the properties for the root node.
+     * @param key The property key.
+     * @param value The property value.
+     * @return this builder instance.
+     */
+    ConfigurationBuilder<T> addRootProperty(String key, String value);
+
+    /**
+     * Build the configuration and optionally initialize it.
+     * @param initialize true if the configuration should be initialized, false otherwise. Generally, Configurations
+     *                   should not be initialized when they are constructed.
+     * @return The constructed Configuration.
+     */
+    T build(boolean initialize);
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
index 8e4364f..8043ff5 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
@@ -141,6 +141,11 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
 
     @Override
     public T build() {
+        return build(true);
+    }
+
+    @Override
+    public T build(boolean initialize) {
         T configuration;
         try {
             if (source == null) {
@@ -149,6 +154,7 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
             final Constructor<T> constructor = clazz.getConstructor(ConfigurationSource.class, Component.class);
             configuration = constructor.newInstance(source, root);
             configuration.setMonitorInterval(monitorInterval);
+            configuration.getRootNode().getAttributes().putAll(root.getAttributes());
             if (name != null) {
                 configuration.setName(name);
             }
@@ -171,7 +177,9 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
             throw new IllegalArgumentException("Invalid Configuration class specified", ex);
         }
         configuration.getStatusConfiguration().initialize();
-        configuration.initialize();
+        if (initialize) {
+            configuration.initialize();
+        }
         return configuration;
     }
 
@@ -380,4 +388,10 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
         this.verbosity = verbosity;
         return this;
     }
+
+    @Override
+    public ConfigurationBuilder<T> addRootProperty(String key, String value) {
+        root.getAttributes().put(key, value);
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index 8b416b3..68fbc3b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
@@ -63,6 +63,7 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
      */
     public CompositeConfiguration(List<? extends AbstractConfiguration> configurations) {
         super(ConfigurationSource.NULL_SOURCE);
+        rootNode = configurations.get(0).getRootNode();
         this.configurations = configurations;
         String mergeStrategyClassName = PropertiesUtil.getProperties().getStringProperty(MERGE_STRATEGY_PROPERTY,
                 DefaultMergeStrategy.class.getName());
@@ -72,14 +73,47 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
                 InstantiationException ex) {
             mergeStrategy = new DefaultMergeStrategy();
         }
+        for (AbstractConfiguration config : configurations) {
+            mergeStrategy.mergeRootProperties(rootNode, config);
+        }
+        final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
+                .withStatus(getDefaultStatus());
+        for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
+            final String key = entry.getKey();
+            final String value = getStrSubstitutor().replace(entry.getValue());
+            if ("status".equalsIgnoreCase(key)) {
+                statusConfig.withStatus(value.toUpperCase());
+            } else if ("dest".equalsIgnoreCase(key)) {
+                statusConfig.withDestination(value);
+            } else if ("shutdownHook".equalsIgnoreCase(key)) {
+                isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+            } else if ("verbose".equalsIgnoreCase(key)) {
+                statusConfig.withVerbosity(value);
+            } else if ("packages".equalsIgnoreCase(key)) {
+                pluginPackages.addAll(Arrays.asList(value.split(Patterns.COMMA_SEPARATOR)));
+            } else if ("name".equalsIgnoreCase(key)) {
+                setName(value);
+            }
+        }
+        statusConfig.initialize();
     }
 
     @Override
     public void setup() {
         AbstractConfiguration targetConfiguration = configurations.get(0);
         staffChildConfiguration(targetConfiguration);
-        WatchManager watchManager = targetConfiguration.getWatchManager();
-        rootNode = targetConfiguration.getRootNode();
+        WatchManager watchManager = getWatchManager();
+        WatchManager targetWatchManager = targetConfiguration.getWatchManager();
+        FileWatcher fileWatcher = new ConfiguratonFileWatcher(this, listeners);
+        if (targetWatchManager.getIntervalSeconds() > 0) {
+            watchManager.setIntervalSeconds(targetWatchManager.getIntervalSeconds());
+            Map<File, FileWatcher> watchers = targetWatchManager.getWatchers();
+            for (Map.Entry<File, FileWatcher> entry : watchers.entrySet()) {
+                if (entry.getValue() instanceof ConfiguratonFileWatcher) {
+                    watchManager.watchFile(entry.getKey(), fileWatcher);
+                }
+            }
+        }
         for (AbstractConfiguration sourceConfiguration : configurations.subList(1, configurations.size())) {
             staffChildConfiguration(sourceConfiguration);
             Node sourceRoot = sourceConfiguration.getRootNode();
@@ -91,12 +125,12 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
             }
             int monitorInterval = sourceConfiguration.getWatchManager().getIntervalSeconds();
             if (monitorInterval > 0) {
-                if (monitorInterval < watchManager.getIntervalSeconds()) {
+                int currentInterval = watchManager.getIntervalSeconds();
+                if (currentInterval <= 0 || monitorInterval < currentInterval) {
                     watchManager.setIntervalSeconds(monitorInterval);
                 }
                 WatchManager sourceWatchManager = sourceConfiguration.getWatchManager();
                 Map<File, FileWatcher> watchers = sourceWatchManager.getWatchers();
-                FileWatcher fileWatcher = new ConfiguratonFileWatcher(this, listeners);
                 for (Map.Entry<File, FileWatcher> entry : watchers.entrySet()) {
                     if (entry.getValue() instanceof ConfiguratonFileWatcher) {
                         watchManager.watchFile(entry.getKey(), fileWatcher);
@@ -104,30 +138,11 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
                 }
             }
         }
-        final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
-                .withStatus(getDefaultStatus());
-        for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
-            final String key = entry.getKey();
-            final String value = getStrSubstitutor().replace(entry.getValue());
-            if ("status".equalsIgnoreCase(key)) {
-                statusConfig.withStatus(value);
-            } else if ("dest".equalsIgnoreCase(key)) {
-                statusConfig.withDestination(value);
-            } else if ("shutdownHook".equalsIgnoreCase(key)) {
-                isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
-            } else if ("verbose".equalsIgnoreCase(key)) {
-                statusConfig.withVerbosity(value);
-            } else if ("packages".equalsIgnoreCase(key)) {
-                pluginPackages.addAll(Arrays.asList(value.split(Patterns.COMMA_SEPARATOR)));
-            } else if ("name".equalsIgnoreCase(key)) {
-                setName(value);
-            }
-        }
-        statusConfig.initialize();
     }
 
     @Override
     public Configuration reconfigure() {
+        LOGGER.debug("Reconfiguring composite configuration");
         List<AbstractConfiguration> configs = new ArrayList<>();
         ConfigurationFactory factory = ConfigurationFactory.getInstance();
         for (AbstractConfiguration config : configurations) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
index 7b123a0..bcd719f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
 import org.apache.logging.log4j.core.config.Node;
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
@@ -62,25 +63,27 @@ public class DefaultMergeStrategy implements MergeStrategy {
     private static final String REF = "ref";
 
     /**
-     * Merge the source Configuration into the target Configuration.
-     *
-     * @param target        The target node to merge into.
-     * @param source        The source node.
-     * @param pluginManager The PluginManager.
+     * Merge the root properties.
+     * @param rootNode The composite root node.
+     * @param configuration The configuration to merge.
      */
-    public void mergConfigurations(Node target, Node source, PluginManager pluginManager) {
-        for (Map.Entry<String, String> attribute : source.getAttributes().entrySet()) {
+    @Override
+    public void mergeRootProperties(Node rootNode, AbstractConfiguration configuration) {
+        for (Map.Entry<String, String> attribute : configuration.getRootNode().getAttributes().entrySet()) {
             boolean isFound = false;
-            for (Map.Entry<String, String> targetAttribute : target.getAttributes().entrySet()) {
+            for (Map.Entry<String, String> targetAttribute : rootNode.getAttributes().entrySet()) {
                 if (targetAttribute.getKey().equalsIgnoreCase(attribute.getKey())) {
                     if (attribute.getKey().equalsIgnoreCase(STATUS)) {
-                        Level targetLevel = Level.getLevel(targetAttribute.getValue());
-                        Level sourceLevel = Level.getLevel(attribute.getValue());
+                        Level targetLevel = Level.getLevel(targetAttribute.getValue().toUpperCase());
+                        Level sourceLevel = Level.getLevel(attribute.getValue().toUpperCase());
                         if (targetLevel != null && sourceLevel != null) {
                             if (sourceLevel.isLessSpecificThan(targetLevel)) {
                                 targetAttribute.setValue(attribute.getValue());
                             }
-                        }
+                        } else
+                            if (sourceLevel != null) {
+                                targetAttribute.setValue(attribute.getValue());
+                            }
                     } else {
                         if (attribute.getKey().equalsIgnoreCase("monitorInterval")) {
                             int sourceInterval = Integer.parseInt(attribute.getValue());
@@ -96,9 +99,20 @@ public class DefaultMergeStrategy implements MergeStrategy {
                 }
             }
             if (!isFound) {
-                target.getAttributes().put(attribute.getKey(), attribute.getValue());
+                rootNode.getAttributes().put(attribute.getKey(), attribute.getValue());
             }
         }
+    }
+
+    /**
+     * Merge the source Configuration into the target Configuration.
+     *
+     * @param target        The target node to merge into.
+     * @param source        The source node.
+     * @param pluginManager The PluginManager.
+     */
+    @Override
+    public void mergConfigurations(Node target, Node source, PluginManager pluginManager) {
         for (Node sourceChildNode : source.getChildren()) {
             boolean isFilter = isFilterNode(sourceChildNode);
             boolean isMerged = false;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/MergeStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/MergeStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/MergeStrategy.java
index 130a6f0..a01f6a3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/MergeStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/MergeStrategy.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.config.composite;
 
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
 import org.apache.logging.log4j.core.config.Node;
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 
@@ -25,6 +26,13 @@ import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 public interface MergeStrategy {
 
     /**
+     * Merge the root node properties into the configuration.
+     * @param rootNode The composite root node.
+     * @param configuration The configuration to merge.
+     */
+    void mergeRootProperties(Node rootNode, AbstractConfiguration configuration);
+
+    /**
      * Merge the soure node tree into the target node tree.
      * @param target The target Node tree.
      * @param source The source Node tree.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfiguration.java
index aa9eb59..90abf56 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfiguration.java
@@ -43,7 +43,7 @@ public class PropertiesConfiguration extends BuiltConfiguration implements Recon
             }
             final PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory();
             final PropertiesConfiguration config = factory.getConfiguration(source);
-            return config == null || config.getState() != State.INITIALIZED ? null : config;
+            return config == null || config.getState() != State.INITIALIZING ? null : config;
         } catch (final IOException ex) {
             LOGGER.error("Cannot locate file {}: {}", getConfigurationSource(), ex);
         }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
index 14a061f..51bdcca 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
@@ -17,6 +17,7 @@
 
 package org.apache.logging.log4j.core.config.properties;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
@@ -77,6 +78,12 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory
 
     @Override
     public PropertiesConfiguration build() {
+        Map<String, String> rootProps = new HashMap<>();
+        for (String key : rootProperties.stringPropertyNames()) {
+            if (!key.contains(".")) {
+                builder.addRootProperty(key, rootProperties.getProperty(key));
+            }
+        }
         builder
             .setStatusLevel(Level.toLevel(rootProperties.getProperty(STATUS_KEY), Level.ERROR))
             .setShutdownHook(rootProperties.getProperty(SHUTDOWN_HOOK))
@@ -139,7 +146,7 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory
             builder.add(createRootLogger(props));
         }
 
-        return builder.build();
+        return builder.build(false);
     }
 
     private ScriptComponentBuilder createScript(final Properties properties) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
index ae15583..a6f4d1f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
@@ -197,6 +197,7 @@ public class StatusConfiguration {
             if (statusListener instanceof StatusConsoleListener) {
                 final StatusConsoleListener listener = (StatusConsoleListener) statusListener;
                 listener.setLevel(this.status);
+                this.logger.updateListenerLevel(this.status);
                 if (this.verbosity == Verbosity.QUIET) {
                     listener.setFilters(this.verboseClasses);
                 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
----------------------------------------------------------------------
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 f17c941..be38342 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
@@ -1,10 +1,29 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
+import java.io.File;
 import java.util.Map;
 
+import java.util.concurrent.TimeUnit;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
 import org.apache.logging.log4j.core.appender.FileAppender;
@@ -17,133 +36,141 @@ import org.junit.Test;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-public class CompositeConfigurationTest
-{
+public class CompositeConfigurationTest {
 
     @Test
-    public void compositeConfigurationUsed()
-    {
-        final LoggerContextRule lcr =
-            new LoggerContextRule( "classpath:log4j-comp-appender.xml,log4j-comp-appender.json" );
-        Statement test = new Statement()
-        {
+    public void compositeConfigurationUsed() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
+        Statement test = new Statement() {
             @Override
-            public void evaluate()
-                throws Throwable
-            {
-                assertTrue( lcr.getConfiguration() instanceof CompositeConfiguration);
+            public void evaluate() throws Throwable {
+                assertTrue(lcr.getConfiguration() instanceof CompositeConfiguration);
             }
         };
-        runTest( lcr, test );
+        runTest(lcr, test);
     }
 
     @Test
-    public void compositeProperties()
-    {
-        final LoggerContextRule lcr =
-            new LoggerContextRule( "classpath:log4j-comp-properties.xml,log4j-comp-properties.json" );
-        Statement test = new Statement()
-        {
+    public void compositeProperties() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-properties.xml,log4j-comp-properties.json");
+        Statement test = new Statement() {
             @Override
-            public void evaluate()
-                throws Throwable
-            {
+            public void evaluate() throws Throwable {
                 CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                assertEquals( "json", config.getStrSubstitutor().replace( "${propertyShared}" ) );
-                assertEquals( "xml", config.getStrSubstitutor().replace( "${propertyXml}" ) );
-                assertEquals( "json", config.getStrSubstitutor().replace( "${propertyJson}" ) );
+                assertEquals("json", config.getStrSubstitutor().replace("${propertyShared}"));
+                assertEquals("xml", config.getStrSubstitutor().replace("${propertyXml}"));
+                assertEquals("json", config.getStrSubstitutor().replace("${propertyJson}"));
             }
         };
-        runTest( lcr, test );
+        runTest(lcr, test);
     }
 
     @Test
-    public void compositeAppenders()
-    {
-        final LoggerContextRule lcr =
-            new LoggerContextRule( "classpath:log4j-comp-appender.xml,log4j-comp-appender.json" );
-        Statement test = new Statement()
-        {
+    public void compositeAppenders() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
+        Statement test = new Statement() {
             @Override
-            public void evaluate()
-                throws Throwable
-            {
+            public void evaluate() throws Throwable {
                 CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
                 Map<String, Appender> appender = config.getAppenders();
-                assertEquals( 3, appender.size() );
-                assertTrue( appender.get( "STDOUT" ) instanceof ConsoleAppender );
-                assertTrue( appender.get( "File" ) instanceof FileAppender );
-                assertTrue( appender.get( "Override" ) instanceof RollingFileAppender );
+                assertEquals(3, appender.size());
+                assertTrue(appender.get("STDOUT") instanceof ConsoleAppender);
+                assertTrue(appender.get("File") instanceof FileAppender);
+                assertTrue(appender.get("Override") instanceof RollingFileAppender);
             }
         };
-        runTest( lcr, test );
+        runTest(lcr, test);
     }
 
     @Test
-    public void compositeLogger()
-    {
-        final LoggerContextRule lcr = new LoggerContextRule( "classpath:log4j-comp-logger.xml,log4j-comp-logger.json" );
-        Statement test = new Statement()
-        {
+    public void compositeLogger() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger.xml,log4j-comp-logger.json");
+        Statement test = new Statement() {
             @Override
-            public void evaluate()
-                throws Throwable
-            {
+            public void evaluate() throws Throwable {
                 CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                Map<String, Appender> appendersMap = config.getLogger( "cat1" ).getAppenders();
+                Map<String, Appender> appendersMap = config.getLogger("cat1").getAppenders();
                 assertEquals("Expected 2 Appender references for cat1 but got " + appendersMap.size(), 2,
-                        appendersMap.size() );
-                assertTrue( appendersMap.get( "STDOUT" ) instanceof ConsoleAppender );
+                        appendersMap.size());
+                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
 
-                appendersMap = config.getLogger( "cat2" ).getAppenders();
+                appendersMap = config.getLogger("cat2").getAppenders();
                 assertEquals("Expected 1 Appender reference for cat2 but got " + appendersMap.size(), 1,
-                        appendersMap.size() );
-                assertTrue( appendersMap.get( "File" ) instanceof FileAppender );
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
 
-                appendersMap = config.getLogger( "cat3" ).getAppenders();
+                appendersMap = config.getLogger("cat3").getAppenders();
                 assertEquals("Expected 1 Appender reference for cat3 but got " + appendersMap.size(), 1,
-                        appendersMap.size() );
-                assertTrue( appendersMap.get( "File" ) instanceof FileAppender );
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
 
                 appendersMap = config.getRootLogger().getAppenders();
                 assertEquals("Expected 2 Appender references for the root logger but got " + appendersMap.size(), 2,
-                        appendersMap.size() );
-                assertTrue( appendersMap.get( "File" ) instanceof FileAppender );
-                assertTrue( appendersMap.get( "STDOUT" ) instanceof ConsoleAppender );
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
+                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
             }
         };
-        runTest( lcr, test );
+        runTest(lcr, test);
     }
 
     @Test
-    public void overrideFilter()
-    {
-        final LoggerContextRule lcr = new LoggerContextRule( "classpath:log4j-comp-filter.xml,log4j-comp-filter.json" );
-        Statement test = new Statement()
-        {
+    public void overrideFilter() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-filter.xml,log4j-comp-filter.json");
+        Statement test = new Statement() {
             @Override
-            public void evaluate()
-                throws Throwable
-            {
+            public void evaluate() throws Throwable {
                 CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                assertTrue( config.getFilter() instanceof CompositeFilter);
+                assertTrue(config.getFilter() instanceof CompositeFilter);
                 CompositeFilter filter = (CompositeFilter) config.getFilter();
-                assertTrue( filter.getFiltersArray().length == 2);
+                assertTrue(filter.getFiltersArray().length == 2);
             }
         };
-        runTest( lcr, test );
+        runTest(lcr, test);
     }
 
-    private void runTest( LoggerContextRule rule, Statement statement )
-    {
-        try
-        {
-            rule.apply( statement, Description.createTestDescription( getClass(),
-                Thread.currentThread().getStackTrace()[1].getMethodName() ) ).evaluate();
-        }
-        catch ( Throwable throwable )
-        {
-            throw new RuntimeException( throwable );
+    @Test
+    public void testReconfiguration() throws Exception {
+        final LoggerContextRule rule =
+                new LoggerContextRule("classpath:log4j-comp-reconfig.xml,log4j-comp-reconfig.properties");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final Configuration oldConfig = rule.getConfiguration();
+                final org.apache.logging.log4j.Logger logger = rule.getLogger("LoggerTest");
+                final int MONITOR_INTERVAL_SECONDS = 5;
+                final File file = new File("target/test-classes/log4j-comp-reconfig.properties");
+                final long orig = file.lastModified();
+                final long newTime = orig + 10000;
+                assertTrue("setLastModified should have succeeded.", file.setLastModified(newTime));
+                TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS + 1);
+                for (int i = 0; i < 17; ++i) {
+                    logger.debug("Reconfigure");
+                }
+                int loopCount = 0;
+                Configuration newConfig;
+                do {
+                    Thread.sleep(100);
+                    newConfig = rule.getConfiguration();
+                    ++loopCount;
+                } while (newConfig == oldConfig && loopCount <= 5);
+                assertNotSame("Reconfiguration failed", newConfig, oldConfig);
+            }
+        };
+        runTest(rule, test);
+
+    }
+
+    private void runTest(LoggerContextRule rule, Statement statement) {
+        try {
+            rule.apply(statement, Description
+                    .createTestDescription(getClass(), Thread.currentThread().getStackTrace()[1].getMethodName()))
+                    .evaluate();
+        } catch (Throwable throwable) {
+            throw new RuntimeException(throwable);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java
index b5a22b1..94e7420 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/TestConfigurator.java
@@ -240,7 +240,7 @@ public class TestConfigurator {
         assertNotNull("Appenders map should not be null.", map);
         assertThat(map, hasSize(greaterThan(0)));
         assertThat("Wrong configuration", map, hasKey("List"));
-        
+
         // Sleep and check
         Thread.sleep(50);
         if (!file.setLastModified(System.currentTimeMillis())) {
@@ -251,11 +251,11 @@ public class TestConfigurator {
         for (int i = 0; i < 17; ++i) {
             logger.debug("Test message " + i);
         }
-        
-        // Sleep and check        
-        Thread.sleep(50);            
+
+        // Sleep and check
+        Thread.sleep(50);
         if (is(theInstance(config)).matches(ctx.getConfiguration())) {
-            Thread.sleep(500);            
+            Thread.sleep(500);
         }
         final Configuration newConfig = ctx.getConfiguration();
         assertThat("Configuration not reset", newConfig, is(not(theInstance(config))));
@@ -421,6 +421,7 @@ public class TestConfigurator {
         builder.add( builder.newRootLogger( Level.DEBUG )
                 .add( builder.newAppenderRef( "rolling" ) ) );
         Configuration config = builder.build();
+        config.initialize();
         assertNotNull("No rolling file appender", config.getAppender("rolling"));
         assertEquals("Unexpected Configuration", "RollingBuilder", config.getName());
         // Initialize the new configuration

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/resources/log4j-comp-appender.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-appender.xml b/log4j-core/src/test/resources/log4j-comp-appender.xml
index 7cd71a2..fe71bea 100644
--- a/log4j-core/src/test/resources/log4j-comp-appender.xml
+++ b/log4j-core/src/test/resources/log4j-comp-appender.xml
@@ -16,7 +16,7 @@
  limitations under the License.
 
 -->
-<Configuration status="ERROR" name="XMLConfigTest">
+<Configuration status="ERROR" name="XMLCompositeAppenderTest">
     <Appenders>
         <File name="File" fileName="target/log4j-comp-appender.log" bufferedIO="false">
             <PatternLayout>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/resources/log4j-comp-filter.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-filter.xml b/log4j-core/src/test/resources/log4j-comp-filter.xml
index 553d448..e8f5ae5 100644
--- a/log4j-core/src/test/resources/log4j-comp-filter.xml
+++ b/log4j-core/src/test/resources/log4j-comp-filter.xml
@@ -16,7 +16,7 @@
  limitations under the License.
 
 -->
-<Configuration status="ERROR" name="XMLConfigTest">
+<Configuration status="ERROR" name="XMLCompositeFilterTest">
   <BurstFilter level="INFO" rate="16" maxBurst="100"/>
 
   <Appenders>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/resources/log4j-comp-properties.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-properties.xml b/log4j-core/src/test/resources/log4j-comp-properties.xml
index 6fa9c6b..a896f34 100644
--- a/log4j-core/src/test/resources/log4j-comp-properties.xml
+++ b/log4j-core/src/test/resources/log4j-comp-properties.xml
@@ -16,7 +16,7 @@
  limitations under the License.
 
 -->
-<Configuration status="OFF" name="XMLConfigTest">
+<Configuration status="OFF" name="XMLCompositePropertiesTest">
   <Properties>
     <Property name="propertyShared">xml</Property>
     <Property name="propertyXml">xml</Property>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/resources/log4j-comp-reconfig.properties
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-reconfig.properties b/log4j-core/src/test/resources/log4j-comp-reconfig.properties
new file mode 100644
index 0000000..94f939a
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-comp-reconfig.properties
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+status = error
+name = PropertiesConfigTest
+monitorInterval = 1
+
+property.filename = target/test-properties.log
+
+filter.threshold.type = ThresholdFilter
+filter.threshold.level = debug
+
+appender.console.name = STDOUT
+appender.console.type = Console
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %m%n
+
+appender.file.name = File
+appender.file.type = File
+appender.file.fileName = ${filename}
+appender.file.bufferedIO = false
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d %p %C{1.} [%t] %m%n
+
+appender.list.name = List
+appender.list.type = List
+appender.list.filter.threshold.type = ThresholdFilter
+appender.list.filter.threshold.level = error
+
+logger.test1.name = org.apache.logging.log4j.test1
+logger.test1.level = debug
+logger.test1.additivity = false
+logger.test1.filter.mdc.type = ThreadContextMapFilter
+logger.test1.filter.mdc.pair.type = KeyValuePair
+logger.test1.filter.mdc.pair.key = test
+logger.test1.filter.mdc.pair.value = 123
+logger.test1.appenderRef.console.ref = STDOUT
+
+logger.test2.name = org.apache.logging.log4j.test2
+logger.test2.level = debug
+logger.test2.additivity = false
+logger.test2.appenderRef.file.ref = File
+
+rootLogger.level = error
+rootLogger.appenderRef.console.ref = STDOUT

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e975a89f/log4j-core/src/test/resources/log4j-comp-reconfig.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-reconfig.xml b/log4j-core/src/test/resources/log4j-comp-reconfig.xml
new file mode 100644
index 0000000..a0376df
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-comp-reconfig.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<Configuration status="ERROR" name="XMLReconfigTest">
+    <Appenders>
+        <File name="File" fileName="target/log4j-comp-appender.log" bufferedIO="false">
+            <PatternLayout>
+                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+            </PatternLayout>
+        </File>
+        <File name="Override" fileName="target/log4j-comp-appender.log" bufferedIO="false">
+            <PatternLayout>
+                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+            </PatternLayout>
+        </File>
+    </Appenders>
+
+    <Loggers>
+        <Root level="ERROR">
+            <AppenderRef ref="File"/>
+        </Root>
+    </Loggers>
+
+</Configuration>