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/master Commit: e975a89f75f3d0200d5033b7286daded67756d6d Parents: bb64f45 Author: Ralph Goers <[email protected]> Authored: Mon Apr 25 06:31:13 2016 -0700 Committer: Ralph Goers <[email protected]> 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>
