This is an automated email from the ASF dual-hosted git repository. mattsicker pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e22e5227209688de5452de0fc746e9108bfeb5c8 Author: Matt Sicker <[email protected]> AuthorDate: Fri Jan 28 21:42:11 2022 -0600 [LOG4J2-3341] Support logger level and appender refs shorthand This adds a properties format feature where the property names "rootLogger" and "logger.<key>" can be set to a level and one or more appender refs. This ports the changes from #733. Signed-off-by: Matt Sicker <[email protected]> --- .../properties/PropertiesConfigurationTest.java | 24 ++++++++++++ .../resources/LoggerLevelAppenderTest.properties | 24 ++++++++++++ .../RootLoggerLevelAppenderTest.properties | 21 +++++++++++ .../properties/PropertiesConfigurationBuilder.java | 43 ++++++++++++++++------ 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java index 52c62ef..59d2d09 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java @@ -22,12 +22,17 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.filter.ThresholdFilter; +import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.core.test.junit.Named; import org.junit.jupiter.api.Test; +import java.util.List; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; @@ -106,4 +111,23 @@ class PropertiesConfigurationTest { logger.debug("Welcome to Log4j!"); } + + @Test + @LoggerContextSource("RootLoggerLevelAppenderTest.properties") + void testRootLoggerLevelAppender(final LoggerContext context, @Named final ListAppender app) { + context.getRootLogger().info("Hello world!"); + final List<LogEvent> events = app.getEvents(); + assertEquals(1, events.size()); + assertEquals("Hello world!", events.get(0).getMessage().getFormattedMessage()); + } + + @Test + @LoggerContextSource("LoggerLevelAppenderTest.properties") + void testLoggerLevelAppender(final LoggerContext context, @Named final ListAppender first, @Named final ListAppender second) { + context.getLogger(getClass()).atInfo().log("message"); + final List<LogEvent> firstEvents = first.getEvents(); + final List<LogEvent> secondEvents = second.getEvents(); + assertEquals(firstEvents, secondEvents); + assertEquals(1, firstEvents.size()); + } } diff --git a/log4j-core-test/src/test/resources/LoggerLevelAppenderTest.properties b/log4j-core-test/src/test/resources/LoggerLevelAppenderTest.properties new file mode 100644 index 0000000..231bb98 --- /dev/null +++ b/log4j-core-test/src/test/resources/LoggerLevelAppenderTest.properties @@ -0,0 +1,24 @@ +# +# 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 = off +name = LoggerLevelAppenderTest +logger.core-config-properties.name = org.apache.logging.log4j.core.config.properties +# whitespace added for testing trimming +logger.core-config-properties = INFO , first , second +appender.first.type = List +appender.second.type = List diff --git a/log4j-core-test/src/test/resources/RootLoggerLevelAppenderTest.properties b/log4j-core-test/src/test/resources/RootLoggerLevelAppenderTest.properties new file mode 100644 index 0000000..3e08203 --- /dev/null +++ b/log4j-core-test/src/test/resources/RootLoggerLevelAppenderTest.properties @@ -0,0 +1,21 @@ +# +# 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 = off +name = RootLoggerLevelAppenderTest +rootLogger = INFO,app +appender.app.type = List 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 34e816c..25f305f 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,11 +17,8 @@ package org.apache.logging.log4j.core.config.properties; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationException; @@ -42,9 +39,15 @@ import org.apache.logging.log4j.core.config.builder.api.ScriptComponentBuilder; import org.apache.logging.log4j.core.config.builder.api.ScriptFileComponentBuilder; import org.apache.logging.log4j.core.filter.AbstractFilter.AbstractFilterBuilder; import org.apache.logging.log4j.plugins.util.Builder; +import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Strings; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + /** * Helper builder for parsing properties files into a PropertiesConfiguration. * @@ -53,6 +56,7 @@ import org.apache.logging.log4j.util.Strings; public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory implements Builder<PropertiesConfiguration> { + private static final Logger LOGGER = StatusLogger.getLogger(); private static final String ADVERTISER_KEY = "advertiser"; private static final String STATUS_KEY = "status"; private static final String SHUTDOWN_HOOK = "shutdownHook"; @@ -170,17 +174,20 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory } } } else { - final Map<String, Properties> loggers = PropertiesUtil - .partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties, "logger")); + final Properties context = PropertiesUtil.extractSubset(rootProperties, "logger"); + final Map<String, Properties> loggers = PropertiesUtil.partitionOnCommonPrefixes(context); for (final Map.Entry<String, Properties> entry : loggers.entrySet()) { final String name = entry.getKey().trim(); if (!name.equals(LoggerConfig.ROOT)) { - builder.add(createLogger(name, entry.getValue())); + final Properties loggerProps = entry.getValue(); + useSyntheticLevelAndAppenderRefs(name, loggerProps, context); + builder.add(createLogger(name, loggerProps)); } } } final Properties props = PropertiesUtil.extractSubset(rootProperties, "rootLogger"); + useSyntheticLevelAndAppenderRefs("rootLogger", props, rootProperties); if (props.size() > 0) { builder.add(createRootLogger(props)); } @@ -190,6 +197,23 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory return builder.build(false); } + private static void useSyntheticLevelAndAppenderRefs(final String propertyName, final Properties loggerProps, final Properties context) { + final String propertyValue = (String) context.remove(propertyName); + if (propertyValue != null) { + final String[] parts = propertyValue.split(","); + if (parts.length > 0) { + final String level = parts[0].trim(); + loggerProps.setProperty("level", level); + LOGGER.debug("Using log level '{}' for logger '{}'", level, propertyName); + for (int i = 1; i < parts.length; i++) { + final String appenderRef = parts[i].trim(); + LOGGER.debug("Adding synthetic appender ref '{}' for logger '{}'", appenderRef, propertyName); + loggerProps.setProperty("appenderRef.$" + i + ".ref", appenderRef); + } + } + } + } + private ScriptComponentBuilder createScript(final Properties properties) { final String name = (String) properties.remove("name"); final String language = (String) properties.remove("language"); @@ -207,10 +231,7 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory } private AppenderComponentBuilder createAppender(final String key, final Properties properties) { - final String name = (String) properties.remove(CONFIG_NAME); - if (Strings.isEmpty(name)) { - throw new ConfigurationException("No name attribute provided for Appender " + key); - } + final String name = Objects.toString(properties.remove(CONFIG_NAME), key); final String type = (String) properties.remove(CONFIG_TYPE); if (Strings.isEmpty(type)) { throw new ConfigurationException("No type attribute provided for Appender " + key);
