Skip to content

Commit

Permalink
add test in relation to variable subsitions for levels, report substi…
Browse files Browse the repository at this point in the history
…tions, LOGBACK-1519

Signed-off-by: Ceki Gulcu <ceki@qos.ch>
  • Loading branch information
ceki committed Aug 13, 2024
1 parent 7c29474 commit c1f21e9
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 52 deletions.
46 changes: 46 additions & 0 deletions logback-classic/src/test/input/joran/levelFromAProperty.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ Logback: the reliable, generic, fast and flexible logging framework.
~ Copyright (C) 1999-2024, 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)
~
~ under the terms of the GNU Lesser General Public License version 2.1
~ as published by the Free Software Foundation.
-->

<!DOCTYPE configuration>

<configuration>
<import class="ch.qos.logback.core.read.ListAppender"/>
<import class="ch.qos.logback.core.status.OnConsoleStatusListener"/>

<!-- <statusListener class="OnConsoleStatusListener"/>-->


<appender name="LIST_ROOT" class="ListAppender"/>

<variable name="ROOT_LEVEL" value="TRACE"/>
<variable name="LOGGER_A_LEVEL" value="WARN"/>
<variable name="LOGGER_NESTED_LEVEL" value="ERROR"/>

<logger name="A" level="${LOGGER_A_LEVEL}"/>

<logger name="A_SYS" level="${LOGGER_A_SYS_LEVEL}"/>

<logger name="NESTED">
<level value="${LOGGER_NESTED_LEVEL}" />
</logger>

<logger name="NESTED_SYS">
<level value="${LOGGER_NESTED_SYS_LEVEL}" />
</logger>

<root level="${ROOT_LEVEL}">
<appender-ref ref="LIST_ROOT"/>
</root>
</configuration>
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* <p>
* 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)
*
* <p>
* or (per the licensee's choosing)
* <p>
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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 <configuration> 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
Expand Down Expand Up @@ -296,7 +296,6 @@ public void testLevelFilter() throws JoranException {
}



@Test
public void testTurboDynamicThreshold() throws JoranException {
configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold.xml");
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<ILoggingEvent> listAppender= (ListAppender<ILoggingEvent>) root.getAppender("LIST");
final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
assertNotNull(listAppender);

logger.atDebug().setMessage("hello").log();
Expand All @@ -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<ILoggingEvent> listAppender= (ListAppender<ILoggingEvent>) root.getAppender("LIST");
final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) 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");

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand All @@ -700,62 +699,98 @@ 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);
//StatusPrinter.print(loggerContext);
}

@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\"");
//StatusPrinter.print(loggerContext);
}

@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");
Expand All @@ -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());

// <serializeModel file="${targetModelFile}"/>
// <logger name="ModelSerializationTest" level="DEBUG"/>



}






// reproduction requires placing a binary properties file. Probably not worth the effort.
// @Test
// public void ossFuzz_47249() throws JoranException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


Expand Down

0 comments on commit c1f21e9

Please sign in to comment.