diff --git a/logback-classic/src/test/input/joran/levelFromAProperty.xml b/logback-classic/src/test/input/joran/levelFromAProperty.xml new file mode 100644 index 0000000000..89ad6cced3 --- /dev/null +++ b/logback-classic/src/test/input/joran/levelFromAProperty.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java index 18d7ade3c4..2e497d0e99 100644 --- a/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java +++ b/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java @@ -1,13 +1,13 @@ /** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2015, QOS.ch. All rights reserved. - * + *

* This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation - * - * or (per the licensee's choosing) - * + *

+ * or (per the licensee's choosing) + *

* under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ @@ -121,7 +121,7 @@ public void asyncWithMultipleAppendersInRoot() throws JoranException { String msg = "hello world"; logger.warn(msg); } - + @Test public void simpleListWithImports() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleListWithImports.xml"); @@ -225,31 +225,31 @@ public void contextRename() throws JoranException { @Test public void missingConfigurationElement() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/noConfig.xml"); - - String msg1 = "Exception in body\\(\\) method for action \\["+ParamAction.class.getName()+"\\]"; + + String msg1 = "Exception in body\\(\\) method for action \\[" + ParamAction.class.getName() + "\\]"; checker.assertContainsMatch(Status.ERROR, msg1); - + String msg2 = "current model is null. Is element missing?"; - checker.assertContainsException(ActionException.class, msg2 ); + checker.assertContainsException(ActionException.class, msg2); } @Test public void ignoreUnknownProperty() throws JoranException { - + configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/unknownProperty.xml"); - String msg = IGNORING_UNKNOWN_PROP+" \\[a\\] in \\[ch.qos.logback.classic.LoggerContext\\]"; + String msg = IGNORING_UNKNOWN_PROP + " \\[a\\] in \\[ch.qos.logback.classic.LoggerContext\\]"; checker.assertContainsMatch(Status.WARN, msg); } - + // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46995 @Test public void complexCollectionWihhNoKnownClass() throws JoranException { - - configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/nestedComplexWithNoKnownClass.xml"); - String msg = "Could not find an appropriate class for property \\[listener\\]"; - checker.assertContainsMatch(Status.ERROR, msg); + + configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/nestedComplexWithNoKnownClass.xml"); + String msg = "Could not find an appropriate class for property \\[listener\\]"; + checker.assertContainsMatch(Status.ERROR, msg); } - + @Test public void turboFilter() throws JoranException { // Although this test uses turbo filters, it only checks @@ -296,7 +296,6 @@ public void testLevelFilter() throws JoranException { } - @Test public void testTurboDynamicThreshold() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold.xml"); @@ -452,7 +451,7 @@ public void unreferencedAppenderShouldNotTriggerUnknownPropertyMessages() throws configure(configFileAsStr); checker.assertContainsMatch(Status.WARN, "Appender named \\[EMAIL\\] not referenced. Skipping further processing."); - checker.assertNoMatch(IGNORING_UNKNOWN_PROP+" \\[evaluator\\]"); + checker.assertNoMatch(IGNORING_UNKNOWN_PROP + " \\[evaluator\\]"); } @Test @@ -546,7 +545,7 @@ public void nestedAppendersDisallowed() throws JoranException { String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1674.xml"; configure(configFileAsStr); checker.assertContainsMatch(Status.WARN, NESTED_APPENDERS_WARNING); - checker.assertContainsMatch(Status.WARN,"Appender at line "); + checker.assertContainsMatch(Status.WARN, "Appender at line "); } @Test @@ -622,13 +621,13 @@ public void missingPropertyErrorHandling() throws JoranException { assertNotNull(listAppender); assertTrue(listAppender.isStarted()); checker.assertContainsMatch(Status.WARN, - IGNORING_UNKNOWN_PROP+" \\[inexistent\\] in \\[ch.qos.logback.core.read.ListAppender\\]"); + IGNORING_UNKNOWN_PROP + " \\[inexistent\\] in \\[ch.qos.logback.core.read.ListAppender\\]"); } @Test public void sequenceNumberGenerator() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "sequenceNumberGenerator.xml"); - final ListAppender listAppender= (ListAppender) root.getAppender("LIST"); + final ListAppender listAppender = (ListAppender) root.getAppender("LIST"); assertNotNull(listAppender); logger.atDebug().setMessage("hello").log(); @@ -646,12 +645,12 @@ public void sequenceNumberGenerator() throws JoranException { public void sequenceNumberGenerator_missingClass() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "sequenceNumberGenerator-missingClass.xml"); //StatusPrinter.print(loggerContext); - final ListAppender listAppender= (ListAppender) root.getAppender("LIST"); + final ListAppender listAppender = (ListAppender) root.getAppender("LIST"); assertNotNull(listAppender); checker.assertContainsMatch(Status.ERROR, "Missing attribute \\[class\\]. See element \\[sequenceNumberGenerator\\]"); } - @Test + @Test public void kvp() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "pattern/kvp.xml"); @@ -680,7 +679,7 @@ public void kvp() throws JoranException { // See LOGBACK-1746 @Test - public void inclusionWithVariables() throws JoranException { + public void inclusionWithVariables() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "include/topLevel0.xml"); Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); //statusPrinter2.print(loggerContext); @@ -689,9 +688,9 @@ public void inclusionWithVariables() throws JoranException { // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46697 @Test - public void ossFuzz_46697() throws JoranException { + public void ossFuzz_46697() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-46697.xml"); - + checker.assertContainsMatch(Status.ERROR, ErrorCodes.EMPTY_MODEL_STACK); } @@ -700,14 +699,14 @@ public void ossFuzz_46697() throws JoranException { // escape sequences for the 'value' attribute named 'value'. After // analysis this was deemed superfluous. @Test - public void ossFuzz_47093() throws JoranException { + public void ossFuzz_47093() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47093.xml"); assertEquals("a\\t", loggerContext.getProperty("fuzz-47093-a")); assertEquals("a\\\\", loggerContext.getProperty("fuzz-47093-b")); } @Test - public void ossFuzz_41117() throws JoranException { + public void ossFuzz_41117() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117.xml"); checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL); checker.assertErrorCount(2); @@ -715,26 +714,26 @@ public void ossFuzz_41117() throws JoranException { } @Test - public void ossFuzz_41117_bis() throws JoranException { + public void ossFuzz_41117_bis() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117-bis.xml"); checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL); } @Test - public void ossFuzz_41117_bis2() throws JoranException { + public void ossFuzz_41117_bis2() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117-bis2.xml"); checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL); } @Test - public void ossFuzz_47293() throws JoranException { + public void ossFuzz_47293() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47293.xml"); checker.assertContainsMatch(Status.ERROR, ErrorCodes.MISSING_IF_EMPTY_MODEL_STACK); } @Test - public void dateConverterWithLocale() throws JoranException { + public void dateConverterWithLocale() throws JoranException { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "dateWithLocale.xml"); checker.assertContainsMatch(Status.INFO, "Setting zoneId to \"Australia/Perth\""); checker.assertContainsMatch(Status.INFO, "Setting locale to \"en_AU\""); @@ -742,20 +741,56 @@ public void dateConverterWithLocale() throws JoranException { } @Test - public void consoleCharsetTest() throws JoranException { - if(EnvUtil.isJDK21OrHigher()) { + public void consoleCharsetTest() throws JoranException { + if (EnvUtil.isJDK21OrHigher()) { configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "consoleCharset.xml"); checker.assertContainsMatch(Status.INFO, "About to instantiate property definer of type \\[ch.qos.logback.core.property.ConsoleCharsetPropertyDefiner\\]"); checker.assertContainsMatch(Status.WARN, "System.console\\(\\) returned null. Cannot compute console's charset, returning"); - checker.assertContainsMatch("Setting property consoleCharset=null in scope LOCAL" ); + checker.assertContainsMatch("Setting property consoleCharset=null in scope LOCAL"); checker.assertContainsMatch("Converting the string \\\"null. as Charset.defaultCharset\\(\\)"); //StatusPrinter.print(loggerContext); } } + @Test + public void levelFromAPropertyTest() throws JoranException { + + + String loggerASysLevelKey = "LOGGER_A_SYS_LEVEL"; + String loggerNestedSysLevelKey = "LOGGER_NESTED_SYS_LEVEL"; + System.setProperty(loggerASysLevelKey, "WARN"); + System.setProperty(loggerNestedSysLevelKey, "ERROR"); + configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "levelFromAProperty.xml"); + + + Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); + + + Logger loggerA = loggerContext.getLogger("A"); + Logger loggerA_SYS = loggerContext.getLogger("A_SYS"); + + Logger loggerNESTED = loggerContext.getLogger("NESTED"); + + Logger loggerNESTED_SYS = loggerContext.getLogger("NESTED_SYS"); + + + assertEquals(Level.TRACE, root.getLevel()); + assertEquals(Level.WARN, loggerA.getLevel()); + assertEquals(Level.WARN, loggerA_SYS.getLevel()); + + assertEquals(Level.ERROR, loggerNESTED.getLevel()); + assertEquals(Level.ERROR, loggerNESTED_SYS.getLevel()); + + checker.assertContainsMatch(Status.INFO, "value \\\"WARN\\\" substituted for \\\"\\$\\{LOGGER_A_LEVEL\\}\\\""); + + System.clearProperty(loggerASysLevelKey); + System.clearProperty(loggerNestedSysLevelKey); + + } + @Test public void modelSerialization() throws JoranException, IOException, ClassNotFoundException { - String outputPath = OUTPUT_DIR_PREFIX+"minimal_"+diff+ MODEL_CONFIG_FILE_EXTENSION; + String outputPath = OUTPUT_DIR_PREFIX + "minimal_" + diff + MODEL_CONFIG_FILE_EXTENSION; loggerContext.putProperty("targetModelFile", outputPath); configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "model/minimal.xml"); @@ -775,25 +810,20 @@ public void modelSerialization() throws JoranException, IOException, ClassNotFou assertEquals(2, configurationModel.getSubModels().size()); - SerializeModelModel smm = (SerializeModelModel) configurationModel.getSubModels().get(0); + SerializeModelModel smm = (SerializeModelModel) configurationModel.getSubModels().get(0); assertEquals("${targetModelFile}", smm.getFile()); - LoggerModel loggerModel = (LoggerModel) configurationModel.getSubModels().get(1); + LoggerModel loggerModel = (LoggerModel) configurationModel.getSubModels().get(1); assertEquals("ModelSerializationTest", loggerModel.getName()); // // - } - - - - // reproduction requires placing a binary properties file. Probably not worth the effort. // @Test // public void ossFuzz_47249() throws JoranException { diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/util/StringToObjectConverter.java b/logback-core/src/main/java/ch/qos/logback/core/joran/util/StringToObjectConverter.java index 08fd9cb6ad..1ed396f11c 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/joran/util/StringToObjectConverter.java +++ b/logback-core/src/main/java/ch/qos/logback/core/joran/util/StringToObjectConverter.java @@ -13,18 +13,14 @@ */ package ch.qos.logback.core.joran.util; -import java.io.Console; +import ch.qos.logback.core.CoreConstants; +import ch.qos.logback.core.spi.ContextAware; + import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; -import ch.qos.logback.core.Context; -import ch.qos.logback.core.CoreConstants; -import ch.qos.logback.core.spi.ContextAware; -import ch.qos.logback.core.spi.ContextAwareBase; - -import static ch.qos.logback.core.CoreConstants.CONSOLE; import static ch.qos.logback.core.CoreConstants.NULL_STR; /** diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java index e8c44438fb..a0e899ad76 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java @@ -163,7 +163,12 @@ public BeanDescriptionCache getBeanDescriptionCache() { } public String subst(String ref) { - return variableSubstitutionsHelper.subst(ref); + + String substituted = variableSubstitutionsHelper.subst(ref); + if(ref != null && !ref.equals(substituted)) { + addInfo("value \""+substituted+"\" substituted for \""+ref+"\""); + } + return substituted; }