From 8803ecbd1d5d556c0e94cb2cdef561c5e7ea4606 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Wed, 3 Jan 2024 13:59:25 +0100 Subject: [PATCH 1/3] Remove Jackson dependency from `MutableThreadContextMapFilter` --- .../filter/MutableThreadContextMapFilter.java | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java index e26e81245a2..6727d78c82e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java @@ -16,8 +16,8 @@ */ package org.apache.logging.log4j.core.filter; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; +import static java.nio.charset.StandardCharsets.UTF_8; + import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.File; import java.io.FileInputStream; @@ -38,7 +38,6 @@ import org.apache.logging.log4j.core.config.ConfigurationException; import org.apache.logging.log4j.core.config.ConfigurationScheduler; import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; -import org.apache.logging.log4j.core.filter.mutable.KeyValuePairConfig; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; import org.apache.logging.log4j.core.util.AuthorizationProvider; @@ -52,6 +51,7 @@ import org.apache.logging.log4j.plugins.PluginAliases; import org.apache.logging.log4j.plugins.PluginAttribute; import org.apache.logging.log4j.plugins.PluginFactory; +import org.apache.logging.log4j.util.JsonReader; import org.apache.logging.log4j.util.PerformanceSensitive; import org.apache.logging.log4j.util.PropertyEnvironment; @@ -64,8 +64,6 @@ @PerformanceSensitive("allocation") public class MutableThreadContextMapFilter extends AbstractFilter { - private static final ObjectMapper MAPPER = - new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static final KeyValuePair[] EMPTY_ARRAY = {}; private volatile Filter filter; @@ -456,44 +454,64 @@ private static ConfigResult getConfig( final ConfigResult configResult = new ConfigResult(); if (result.getStatus() == Status.SUCCESS) { LOGGER.debug("Processing Debug key/value pairs from: {}", source.toString()); - try { - final KeyValuePairConfig keyValuePairConfig = MAPPER.readValue(inputStream, KeyValuePairConfig.class); - if (keyValuePairConfig != null) { - final Map configs = keyValuePairConfig.getConfigs(); - if (configs != null && configs.size() > 0) { - final List pairs = new ArrayList<>(); - for (Map.Entry entry : configs.entrySet()) { - final String key = entry.getKey(); - for (final String value : entry.getValue()) { - if (value != null) { - pairs.add(new KeyValuePair(key, value)); + parseJsonConfiguration(inputStream, configResult); + } else { + configResult.status = result.getStatus(); + } + return configResult; + } + + /** + * Parses a JSON configuration file. + *
+     *   {
+     *     "config": {
+     *       "loginId": ["rgoers", "adam"],
+     *       "accountNumber": ["30510263"]
+     *   }
+     * }
+     * 
+ */ + private static void parseJsonConfiguration(final InputStream inputStream, final ConfigResult configResult) { + try { + final Object wrapper = JsonReader.read(new String(inputStream.readAllBytes(), UTF_8)); + if (wrapper instanceof Map wrapperMap) { + final Object config = wrapperMap.get("configs"); + if (config instanceof Map configMap && configMap.size() > 0) { + final List pairs = new ArrayList<>(); + for (Map.Entry entry : configMap.entrySet()) { + final String key = String.valueOf(entry.getKey()); + final Object jsonArray = entry.getValue(); + if (jsonArray instanceof List valueList) { + for (final Object value : valueList) { + if (value instanceof String stringValue) { + pairs.add(new KeyValuePair(key, stringValue)); } else { - LOGGER.warn("Ignoring null value for {}", key); + LOGGER.warn("Ignoring null value for {}: {}", key, value); } } - } - if (pairs.size() > 0) { - configResult.pairs = pairs.toArray(EMPTY_ARRAY); - configResult.status = Status.SUCCESS; } else { - configResult.status = Status.EMPTY; + LOGGER.warn("Ignoring the value for {}, which is not an array: {}", key, jsonArray); } + } + if (pairs.size() > 0) { + configResult.pairs = pairs.toArray(EMPTY_ARRAY); + configResult.status = Status.SUCCESS; } else { - LOGGER.debug("No configuration data in {}", source.toString()); configResult.status = Status.EMPTY; } } else { - LOGGER.warn("No configs element in MutableThreadContextMapFilter configuration"); - configResult.status = Status.ERROR; + LOGGER.debug("No configuration data in {}", wrapper); + configResult.status = Status.EMPTY; } - } catch (Exception ex) { - LOGGER.warn("Invalid key/value pair configuration, input ignored: {}", ex.getMessage()); + } else { + LOGGER.warn("No configs element in MutableThreadContextMapFilter configuration"); configResult.status = Status.ERROR; } - } else { - configResult.status = result.getStatus(); + } catch (Exception ex) { + LOGGER.warn("Invalid key/value pair configuration, input ignored: {}", ex.getMessage()); + configResult.status = Status.ERROR; } - return configResult; } private static class NoOpFilter extends AbstractFilter { From 01b6e2d6583387ff0ba906bdba1381e61cd08e50 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Wed, 3 Jan 2024 16:51:25 +0100 Subject: [PATCH 2/3] Fix resource leak --- .../filter/MutableThreadContextMapFilter.java | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java index 6727d78c82e..1918d92c297 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java @@ -21,6 +21,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; @@ -425,38 +426,49 @@ private static ConfigResult getConfig( final PropertyEnvironment props, final SslConfiguration sslConfiguration) { final File inputFile = source.getFile(); + final ConfigResult configResult = new ConfigResult(); InputStream inputStream = null; HttpInputStreamUtil.Result result = null; final long lastModified = source.getLastModified(); - if (inputFile != null && inputFile.exists()) { - try { - final long modified = inputFile.lastModified(); - if (modified > lastModified) { - source.setLastModified(modified); - inputStream = new FileInputStream(inputFile); - result = new HttpInputStreamUtil.Result(Status.SUCCESS); - } else { - result = new HttpInputStreamUtil.Result(Status.NOT_MODIFIED); + try { + if (inputFile != null && inputFile.exists()) { + try { + final long modified = inputFile.lastModified(); + if (modified > lastModified) { + source.setLastModified(modified); + inputStream = new FileInputStream(inputFile); + result = new HttpInputStreamUtil.Result(Status.SUCCESS); + } else { + result = new HttpInputStreamUtil.Result(Status.NOT_MODIFIED); + } + } catch (Exception ex) { + result = new HttpInputStreamUtil.Result(Status.ERROR); + } + } else if (source.getURI() != null) { + try { + result = HttpInputStreamUtil.getInputStream(source, props, authorizationProvider, sslConfiguration); + inputStream = result.getInputStream(); + } catch (ConfigurationException ex) { + result = new HttpInputStreamUtil.Result(Status.ERROR); } - } catch (Exception ex) { - result = new HttpInputStreamUtil.Result(Status.ERROR); + } else { + result = new HttpInputStreamUtil.Result(Status.NOT_FOUND); } - } else if (source.getURI() != null) { - try { - result = HttpInputStreamUtil.getInputStream(source, props, authorizationProvider, sslConfiguration); - inputStream = result.getInputStream(); - } catch (ConfigurationException ex) { - result = new HttpInputStreamUtil.Result(Status.ERROR); + if (result.getStatus() == Status.SUCCESS) { + LOGGER.debug("Processing Debug key/value pairs from: {}", source.toString()); + parseJsonConfiguration(inputStream, configResult); + } else { + configResult.status = result.getStatus(); + } + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close {}.", source, e); + configResult.status = Status.ERROR; + } } - } else { - result = new HttpInputStreamUtil.Result(Status.NOT_FOUND); - } - final ConfigResult configResult = new ConfigResult(); - if (result.getStatus() == Status.SUCCESS) { - LOGGER.debug("Processing Debug key/value pairs from: {}", source.toString()); - parseJsonConfiguration(inputStream, configResult); - } else { - configResult.status = result.getStatus(); } return configResult; } From b642f1ad174fea1549db966e62153102feac623a Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sat, 30 Dec 2023 18:08:45 +0100 Subject: [PATCH 3/3] Split off YAML configuration into its own module This splits `YamlConfiguration` into its own module and removes `jackson-dataformat-yaml` from `log4j-core`'s optional dependencies. --- log4j-config-yaml/pom.xml | 66 ++++++++++++++ .../core/config/yaml/YamlConfiguration.java | 0 .../config/yaml/YamlConfigurationFactory.java | 0 .../log4j/core/config/yaml/package-info.java | 0 .../yaml}/MultipleTriggeringPolicyTest.java | 3 +- .../yaml/YamlConfigurationFactoryTest.java | 39 +++++++++ .../resources/LOG4J2-1100/log4j2-bad.yaml | 0 .../resources/LOG4J2-1100/log4j2-good.yaml | 0 .../test/resources/LOG4J2-1100/log4j2.json | 0 .../src/test/resources/LOG4J2-1100/log4j2.xml | 0 .../YamlConfigurationFactoryTest.yaml | 0 .../AbstractConfigurationFactoryTest.java | 86 +++++++++++++++++++ .../core/config/ConfigurationFactoryTest.java | 70 +-------------- .../core/config/JiraLog4j2_2134Test.java | 4 - .../core/lookup/MarkerLookupConfigTest.java | 54 ++++++------ .../SequenceNumberPatternConverterTest.java | 2 +- ...eNumberPatternConverterZeroPaddedTest.java | 2 +- .../SequenceNumberPatternConverterTest.yaml | 31 ------- ...eNumberPatternConverterZeroPaddedTest.yaml | 31 ------- .../test/resources/log4j-marker-lookup.yaml | 55 ------------ .../src/test/resources/log4j2-2134.yaml | 30 ------- .../core/lookup/MarkerLookupConfigTest.xml | 36 ++++++++ .../SequenceNumberPatternConverterTest.xml | 29 +++++++ ...ceNumberPatternConverterZeroPaddedTest.xml | 29 +++++++ log4j-core/pom.xml | 23 ----- log4j-layout-template-json-test/pom.xml | 5 ++ pom.xml | 7 ++ src/changelog/.3.x.x/create_config_yaml.xml | 9 ++ 28 files changed, 337 insertions(+), 274 deletions(-) create mode 100644 log4j-config-yaml/pom.xml rename {log4j-core => log4j-config-yaml}/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfiguration.java (100%) rename {log4j-core => log4j-config-yaml}/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfigurationFactory.java (100%) rename {log4j-core => log4j-config-yaml}/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java (100%) rename {log4j-core-test/src/test/java/org/apache/logging/log4j/core/config => log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml}/MultipleTriggeringPolicyTest.java (97%) create mode 100644 log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactoryTest.java rename {log4j-core-test => log4j-config-yaml}/src/test/resources/LOG4J2-1100/log4j2-bad.yaml (100%) rename {log4j-core-test => log4j-config-yaml}/src/test/resources/LOG4J2-1100/log4j2-good.yaml (100%) rename {log4j-core-test => log4j-config-yaml}/src/test/resources/LOG4J2-1100/log4j2.json (100%) rename {log4j-core-test => log4j-config-yaml}/src/test/resources/LOG4J2-1100/log4j2.xml (100%) rename log4j-core-test/src/test/resources/log4j-test1.yaml => log4j-config-yaml/src/test/resources/YamlConfigurationFactoryTest.yaml (100%) create mode 100644 log4j-core-test/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactoryTest.java delete mode 100644 log4j-core-test/src/test/resources/SequenceNumberPatternConverterTest.yaml delete mode 100644 log4j-core-test/src/test/resources/SequenceNumberPatternConverterZeroPaddedTest.yaml delete mode 100644 log4j-core-test/src/test/resources/log4j-marker-lookup.yaml delete mode 100644 log4j-core-test/src/test/resources/log4j2-2134.yaml create mode 100644 log4j-core-test/src/test/resources/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.xml create mode 100644 log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.xml create mode 100644 log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.xml create mode 100644 src/changelog/.3.x.x/create_config_yaml.xml diff --git a/log4j-config-yaml/pom.xml b/log4j-config-yaml/pom.xml new file mode 100644 index 00000000000..2a916ebe431 --- /dev/null +++ b/log4j-config-yaml/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + org.apache.logging.log4j + log4j + ${revision} + ../log4j-parent + + + log4j-config-yaml + + + + + org.apache.logging.log4j + log4j-core + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + + org.apache.logging.log4j + log4j-core-test + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.logging.log4j + log4j-plugin-processor + ${project.version} + + + + + + + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfiguration.java b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfiguration.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfiguration.java rename to log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfiguration.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfigurationFactory.java b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfigurationFactory.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfigurationFactory.java rename to log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/YamlConfigurationFactory.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java rename to log4j-config-yaml/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MultipleTriggeringPolicyTest.java b/log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/MultipleTriggeringPolicyTest.java similarity index 97% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MultipleTriggeringPolicyTest.java rename to log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/MultipleTriggeringPolicyTest.java index 8ddac378400..2d35516f3e2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MultipleTriggeringPolicyTest.java +++ b/log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/MultipleTriggeringPolicyTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.config; +package org.apache.logging.log4j.config.yaml; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -24,6 +24,7 @@ import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy; import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy; import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy; +import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; diff --git a/log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactoryTest.java b/log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactoryTest.java new file mode 100644 index 00000000000..02d21323ab7 --- /dev/null +++ b/log4j-config-yaml/src/test/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactoryTest.java @@ -0,0 +1,39 @@ +/* + * 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.config.yaml; + +import java.io.IOException; +import java.nio.file.Path; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AbstractConfigurationFactoryTest; +import org.apache.logging.log4j.core.test.junit.LoggerContextSource; +import org.apache.logging.log4j.test.junit.TempLoggingDir; +import org.junit.jupiter.api.Test; + +class YamlConfigurationFactoryTest extends AbstractConfigurationFactoryTest { + + @TempLoggingDir + private static Path loggingPath; + + @Test + @LoggerContextSource("YamlConfigurationFactoryTest.yaml") + void yamlConfiguration(final LoggerContext context) throws IOException { + checkConfiguration(context); + final Path logFile = loggingPath.resolve("test-yaml.log"); + checkFileLogger(context, logFile); + } +} diff --git a/log4j-core-test/src/test/resources/LOG4J2-1100/log4j2-bad.yaml b/log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2-bad.yaml similarity index 100% rename from log4j-core-test/src/test/resources/LOG4J2-1100/log4j2-bad.yaml rename to log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2-bad.yaml diff --git a/log4j-core-test/src/test/resources/LOG4J2-1100/log4j2-good.yaml b/log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2-good.yaml similarity index 100% rename from log4j-core-test/src/test/resources/LOG4J2-1100/log4j2-good.yaml rename to log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2-good.yaml diff --git a/log4j-core-test/src/test/resources/LOG4J2-1100/log4j2.json b/log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2.json similarity index 100% rename from log4j-core-test/src/test/resources/LOG4J2-1100/log4j2.json rename to log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2.json diff --git a/log4j-core-test/src/test/resources/LOG4J2-1100/log4j2.xml b/log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2.xml similarity index 100% rename from log4j-core-test/src/test/resources/LOG4J2-1100/log4j2.xml rename to log4j-config-yaml/src/test/resources/LOG4J2-1100/log4j2.xml diff --git a/log4j-core-test/src/test/resources/log4j-test1.yaml b/log4j-config-yaml/src/test/resources/YamlConfigurationFactoryTest.yaml similarity index 100% rename from log4j-core-test/src/test/resources/log4j-test1.yaml rename to log4j-config-yaml/src/test/resources/YamlConfigurationFactoryTest.yaml diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactoryTest.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactoryTest.java new file mode 100644 index 00000000000..52f8ff9ee3c --- /dev/null +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactoryTest.java @@ -0,0 +1,86 @@ +/* + * 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.apache.logging.log4j.util.Unbox.box; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.filter.ThreadContextMapFilter; +import org.apache.logging.log4j.util.Strings; + +/** + * Common base class for configuration factory tests. + */ +public abstract class AbstractConfigurationFactoryTest { + + private static final String LOGGER_NAME = "org.apache.logging.log4j.test1.Test"; + private static final String FILE_LOGGER_NAME = "org.apache.logging.log4j.test2.Test"; + private static final String APPENDER_NAME = "STDOUT"; + + /** + * Runs various configuration checks on a configured LoggerContext that should match the equivalent configuration in + * {@code log4j-test1.xml}. + */ + protected static void checkConfiguration(final LoggerContext context) { + final Configuration configuration = context.getConfiguration(); + final Map appenders = configuration.getAppenders(); + // these used to be separate tests + assertAll( + () -> assertNotNull(appenders), + () -> assertEquals(3, appenders.size()), + () -> assertNotNull(configuration.getLoggerContext()), + () -> assertEquals(configuration.getRootLogger(), configuration.getLoggerConfig(Strings.EMPTY)), + () -> assertThrows(NullPointerException.class, () -> configuration.getLoggerConfig(null))); + + final Logger logger = context.getLogger(LOGGER_NAME); + assertEquals(Level.DEBUG, logger.getLevel()); + + assertEquals(1, logger.filterCount()); + final Iterator filterIterator = logger.getFilters(); + assertTrue(filterIterator.hasNext()); + assertTrue(filterIterator.next() instanceof ThreadContextMapFilter); + + final Appender appender = appenders.get(APPENDER_NAME); + assertTrue(appender instanceof ConsoleAppender); + assertEquals(APPENDER_NAME, appender.getName()); + } + + protected static void checkFileLogger(final LoggerContext context, final Path logFile) throws IOException { + final long currentThreadId = Thread.currentThread().getId(); + final Logger logger = context.getLogger(FILE_LOGGER_NAME); + logger.debug("Greetings from ConfigurationFactoryTest in thread#{}", box(currentThreadId)); + final List lines = Files.readAllLines(logFile); + assertEquals(1, lines.size()); + assertTrue(lines.get(0).endsWith(Long.toString(currentThreadId))); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java index 5db114e7398..2556f73e581 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java @@ -16,78 +16,19 @@ */ package org.apache.logging.log4j.core.config; -import static org.apache.logging.log4j.util.Unbox.box; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.filter.ThreadContextMapFilter; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.test.junit.TempLoggingDir; -import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -class ConfigurationFactoryTest { - - static final String LOGGER_NAME = "org.apache.logging.log4j.test1.Test"; - static final String FILE_LOGGER_NAME = "org.apache.logging.log4j.test2.Test"; - static final String APPENDER_NAME = "STDOUT"; +class ConfigurationFactoryTest extends AbstractConfigurationFactoryTest { @TempLoggingDir private static Path loggingPath; - /** - * Runs various configuration checks on a configured LoggerContext that should match the equivalent configuration in - * {@code log4j-test1.xml}. - */ - static void checkConfiguration(final LoggerContext context) { - final Configuration configuration = context.getConfiguration(); - final Map appenders = configuration.getAppenders(); - // these used to be separate tests - assertAll( - () -> assertNotNull(appenders), - () -> assertEquals(3, appenders.size()), - () -> assertNotNull(configuration.getLoggerContext()), - () -> assertEquals(configuration.getRootLogger(), configuration.getLoggerConfig(Strings.EMPTY)), - () -> assertThrows(NullPointerException.class, () -> configuration.getLoggerConfig(null))); - - final Logger logger = context.getLogger(LOGGER_NAME); - assertEquals(Level.DEBUG, logger.getLevel()); - - assertEquals(1, logger.filterCount()); - final Iterator filterIterator = logger.getFilters(); - assertTrue(filterIterator.hasNext()); - assertTrue(filterIterator.next() instanceof ThreadContextMapFilter); - - final Appender appender = appenders.get(APPENDER_NAME); - assertTrue(appender instanceof ConsoleAppender); - assertEquals(APPENDER_NAME, appender.getName()); - } - - static void checkFileLogger(final LoggerContext context, final Path logFile) throws IOException { - final long currentThreadId = Thread.currentThread().getId(); - final Logger logger = context.getLogger(FILE_LOGGER_NAME); - logger.debug("Greetings from ConfigurationFactoryTest in thread#{}", box(currentThreadId)); - final List lines = Files.readAllLines(logFile); - assertEquals(1, lines.size()); - assertTrue(lines.get(0).endsWith(Long.toString(currentThreadId))); - } - @Test @LoggerContextSource("log4j-test1.xml") void xml(final LoggerContext context) throws IOException { @@ -113,15 +54,6 @@ void json(final LoggerContext context) throws IOException { checkFileLogger(context, logFile); } - @Test - @Tag("yaml") - @LoggerContextSource("log4j-test1.yaml") - void yaml(final LoggerContext context) throws IOException { - checkConfiguration(context); - final Path logFile = loggingPath.resolve("test-yaml.log"); - checkFileLogger(context, logFile); - } - @Test @LoggerContextSource("log4j-test1.properties") void properties(final LoggerContext context) throws IOException { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java index 641326d5645..2b80472a263 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/JiraLog4j2_2134Test.java @@ -25,12 +25,8 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -@Tag("yaml") -@LoggerContextSource("log4j2-2134.yaml") public class JiraLog4j2_2134Test { @Test diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.java index 2ca4cfb1715..d4cb197c58f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.java @@ -16,19 +16,20 @@ */ package org.apache.logging.log4j.core.lookup; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; -import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import org.apache.commons.io.FileUtils; -import org.apache.logging.log4j.LogManager; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; -import org.junit.jupiter.api.Tag; +import org.apache.logging.log4j.test.junit.TempLoggingDir; +import org.apache.logging.log4j.test.junit.UsingStatusListener; import org.junit.jupiter.api.Test; /** @@ -36,43 +37,40 @@ * * @since 2.4 */ -@LoggerContextSource("log4j-marker-lookup.yaml") -@Tag("yaml") -public class MarkerLookupConfigTest { +@UsingStatusListener +class MarkerLookupConfigTest { - public static final Marker PAYLOAD = MarkerManager.getMarker("PAYLOAD"); + private static final Marker PAYLOAD = MarkerManager.getMarker("PAYLOAD"); private static final String PAYLOAD_LOG = "Message in payload.log"; - public static final Marker PERFORMANCE = MarkerManager.getMarker("PERFORMANCE"); + private static final Marker PERFORMANCE = MarkerManager.getMarker("PERFORMANCE"); private static final String PERFORMANCE_LOG = "Message in performance.log"; - public static final Marker SQL = MarkerManager.getMarker("SQL"); + private static final Marker SQL = MarkerManager.getMarker("SQL"); private static final String SQL_LOG = "Message in sql.log"; + @TempLoggingDir + private static Path loggingPath; + @Test - public void test() throws IOException { - final Logger logger = LogManager.getLogger(); + @LoggerContextSource + void test(final LoggerContext context) throws IOException { + final Logger logger = context.getLogger(getClass()); logger.info(SQL, SQL_LOG); logger.info(PAYLOAD, PAYLOAD_LOG); logger.info(PERFORMANCE, PERFORMANCE_LOG); + context.stop(1, TimeUnit.SECONDS); { - final String log = FileUtils.readFileToString(new File("target/logs/sql.log"), StandardCharsets.UTF_8); - assertTrue(log.contains(SQL_LOG)); - assertFalse(log.contains(PAYLOAD_LOG)); - assertFalse(log.contains(PERFORMANCE_LOG)); + final List lines = Files.readAllLines(loggingPath.resolve("sql.log")); + assertThat(lines).hasSize(1).contains(SQL_LOG); } { - final String log = FileUtils.readFileToString(new File("target/logs/payload.log"), StandardCharsets.UTF_8); - assertFalse(log.contains(SQL_LOG)); - assertTrue(log.contains(PAYLOAD_LOG)); - assertFalse(log.contains(PERFORMANCE_LOG)); + final List lines = Files.readAllLines(loggingPath.resolve("payload.log")); + assertThat(lines).hasSize(1).contains(PAYLOAD_LOG); } { - final String log = - FileUtils.readFileToString(new File("target/logs/performance.log"), StandardCharsets.UTF_8); - assertFalse(log.contains(SQL_LOG)); - assertFalse(log.contains(PAYLOAD_LOG)); - assertTrue(log.contains(PERFORMANCE_LOG)); + final List lines = Files.readAllLines(loggingPath.resolve("performance.log")); + assertThat(lines).hasSize(1).contains(PERFORMANCE_LOG); } } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.java index 60ff42bc98e..eb424e84813 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.java @@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.test.junit.Named; import org.junit.jupiter.api.Test; -@LoggerContextSource("SequenceNumberPatternConverterTest.yaml") +@LoggerContextSource public class SequenceNumberPatternConverterTest { @Test diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.java index 049fe51c720..6552a357563 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.java @@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.test.junit.Named; import org.junit.jupiter.api.Test; -@LoggerContextSource("SequenceNumberPatternConverterZeroPaddedTest.yaml") +@LoggerContextSource public class SequenceNumberPatternConverterZeroPaddedTest { @Test diff --git a/log4j-core-test/src/test/resources/SequenceNumberPatternConverterTest.yaml b/log4j-core-test/src/test/resources/SequenceNumberPatternConverterTest.yaml deleted file mode 100644 index 330d31415e6..00000000000 --- a/log4j-core-test/src/test/resources/SequenceNumberPatternConverterTest.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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: OFF - name: SequenceNumberPatternConverterTest - - Appenders: - List: - name: List - PatternLayout: - pattern: '%sn' - - Loggers: - Root: - level: INFO - AppenderRef: - ref: List diff --git a/log4j-core-test/src/test/resources/SequenceNumberPatternConverterZeroPaddedTest.yaml b/log4j-core-test/src/test/resources/SequenceNumberPatternConverterZeroPaddedTest.yaml deleted file mode 100644 index 7bb9a692925..00000000000 --- a/log4j-core-test/src/test/resources/SequenceNumberPatternConverterZeroPaddedTest.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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: OFF - name: SequenceNumberPatternConverterTest - - Appenders: - List: - - name: Padded - PatternLayout: - pattern: '%03sn' - - Loggers: - Root: - level: INFO - AppenderRef: - - ref: Padded diff --git a/log4j-core-test/src/test/resources/log4j-marker-lookup.yaml b/log4j-core-test/src/test/resources/log4j-marker-lookup.yaml deleted file mode 100644 index 32cb12836ed..00000000000 --- a/log4j-core-test/src/test/resources/log4j-marker-lookup.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# -# 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: 'off' - - Appenders: - Console: - RandomAccessFile: - - name: SQL_APPENDER - fileName: target/logs/sql.log - append: false - PatternLayout: - Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n" - - name: PAYLOAD_APPENDER - fileName: target/logs/payload.log - append: false - PatternLayout: - Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n" - - name: PERFORMANCE_APPENDER - fileName: target/logs/performance.log - append: false - PatternLayout: - Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n" - - Routing: - name: ROUTING_APPENDER - Routes: - pattern: "$${marker:}" - Route: - - key: PERFORMANCE - ref: PERFORMANCE_APPENDER - - key: PAYLOAD - ref: PAYLOAD_APPENDER - - key: SQL - ref: SQL_APPENDER - - Loggers: - Root: - level: trace - AppenderRef: - - ref: ROUTING_APPENDER diff --git a/log4j-core-test/src/test/resources/log4j2-2134.yaml b/log4j-core-test/src/test/resources/log4j2-2134.yaml deleted file mode 100644 index fd66830408d..00000000000 --- a/log4j-core-test/src/test/resources/log4j2-2134.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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: off - name: NUAR_DEFAULT_LOGGING - Appenders: - Console: - name: CONSOLE - target: SYSTEM_OUT - PatternLayout: - pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" - Loggers: - Root: - level: info - AppenderRef: - - ref: "CONSOLE" diff --git a/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.xml b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.xml new file mode 100644 index 00000000000..811a7d81999 --- /dev/null +++ b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/lookup/MarkerLookupConfigTest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.xml b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.xml new file mode 100644 index 00000000000..f1336b0df2d --- /dev/null +++ b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterTest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.xml b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.xml new file mode 100644 index 00000000000..91333203afd --- /dev/null +++ b/log4j-core-test/src/test/resources/org/apache/logging/log4j/core/pattern/SequenceNumberPatternConverterZeroPaddedTest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 991ba157f32..cdbbeca83c3 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -36,7 +36,6 @@ com.conversantmedia.util.concurrent;resolution:=optional; - com.fasterxml.jackson.*;resolution:=optional, com.lmax.disruptor.*;resolution:=optional, org.apache.commons.compress.*;resolution:=optional, org.fusesource.jansi;resolution:=optional, @@ -62,10 +61,6 @@ java.xml;transitive=false, jdk.unsupported;transitive=false, org.fusesource.jansi;transitive=false, - - com.fasterxml.jackson.core;substitute="jackson-core";transitive=false, - com.fasterxml.jackson.databind;substitute="jackson-databind";transitive=false, - com.fasterxml.jackson.dataformat.yaml;substitute="jackson-dataformat-yaml";transitive=false @@ -103,24 +98,6 @@ disruptor true - - - com.fasterxml.jackson.core - jackson-core - true - - - - com.fasterxml.jackson.core - jackson-databind - true - - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - true - org.fusesource.jansi diff --git a/log4j-layout-template-json-test/pom.xml b/log4j-layout-template-json-test/pom.xml index f0945107da8..94d8664cada 100644 --- a/log4j-layout-template-json-test/pom.xml +++ b/log4j-layout-template-json-test/pom.xml @@ -48,6 +48,11 @@ log4j-1.2-api test + + org.apache.logging.log4j + log4j-config-yaml + test + org.apache.logging.log4j log4j-core-test diff --git a/pom.xml b/pom.xml index 52affcc90ce..4cb3c1a5ec7 100644 --- a/pom.xml +++ b/pom.xml @@ -236,6 +236,7 @@ log4j-api log4j-api-test log4j-appserver + log4j-config-yaml log4j-core log4j-core-its log4j-core-test @@ -374,6 +375,12 @@ ${project.version} + + org.apache.logging.log4j + log4j-config-yaml + ${project.version} + + org.apache.logging.log4j log4j-core diff --git a/src/changelog/.3.x.x/create_config_yaml.xml b/src/changelog/.3.x.x/create_config_yaml.xml new file mode 100644 index 00000000000..ac564f50703 --- /dev/null +++ b/src/changelog/.3.x.x/create_config_yaml.xml @@ -0,0 +1,9 @@ + + + + Split off YAML configuration into a new `log4j-config-yaml` module. + +