Prevent status messages from logging when Logback is being configured

There's a window where the deny-all turbo filter has been removed but
Logback has not yet been configured. If any logging that would have
reached an appender is performed in this window, unwanted status
messages will be logged. This window can be closed by ensuring that
the turbo filter is in place while Logback is being configured.

Closes gh-34505
3.0.x
Andy Wilkinson 1 year ago
parent 4e40ff8341
commit 688a69b9b1

@ -30,6 +30,7 @@ import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.jul.LevelChangePropagator; import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.spi.TurboFilterList;
import ch.qos.logback.classic.turbo.TurboFilter; import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.spi.FilterReply; import ch.qos.logback.core.spi.FilterReply;
@ -218,33 +219,37 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) {
LoggerContext context = getLoggerContext(); LoggerContext context = getLoggerContext();
stopAndReset(context); stopAndReset(context);
boolean debug = Boolean.getBoolean("logback.debug"); withLoggingSuppressed(() -> {
if (debug) { boolean debug = Boolean.getBoolean("logback.debug");
StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); if (debug) {
} StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
Environment environment = initializationContext.getEnvironment(); }
// Apply system properties directly in case the same JVM runs multiple apps Environment environment = initializationContext.getEnvironment();
new LogbackLoggingSystemProperties(environment, context::putProperty).apply(logFile); // Apply system properties directly in case the same JVM runs multiple apps
LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(context) new LogbackLoggingSystemProperties(environment, context::putProperty).apply(logFile);
: new LogbackConfigurator(context); LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(context)
new DefaultLogbackConfiguration(logFile).apply(configurator); : new LogbackConfigurator(context);
context.setPackagingDataEnabled(true); new DefaultLogbackConfiguration(logFile).apply(configurator);
context.setPackagingDataEnabled(true);
});
} }
@Override @Override
protected void loadConfiguration(LoggingInitializationContext initializationContext, String location, protected void loadConfiguration(LoggingInitializationContext initializationContext, String location,
LogFile logFile) { LogFile logFile) {
if (initializationContext != null) {
applySystemProperties(initializationContext.getEnvironment(), logFile);
}
LoggerContext loggerContext = getLoggerContext(); LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext); stopAndReset(loggerContext);
try { withLoggingSuppressed(() -> {
configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location)); if (initializationContext != null) {
} applySystemProperties(initializationContext.getEnvironment(), logFile);
catch (Exception ex) { }
throw new IllegalStateException("Could not initialize Logback logging from " + location, ex); try {
} configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location));
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Logback logging from " + location, ex);
}
});
reportConfigurationErrorsIfNecessary(loggerContext); reportConfigurationErrorsIfNecessary(loggerContext);
} }
@ -448,6 +453,17 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
return contribution; return contribution;
} }
private void withLoggingSuppressed(Runnable action) {
TurboFilterList turboFilters = getLoggerContext().getTurboFilterList();
turboFilters.add(FILTER);
try {
action.run();
}
finally {
turboFilters.remove(FILTER);
}
}
/** /**
* {@link LoggingSystemFactory} that returns {@link LogbackLoggingSystem} if possible. * {@link LoggingSystemFactory} that returns {@link LogbackLoggingSystem} if possible.
*/ */

@ -57,12 +57,14 @@ import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.LoggingSystemProperties; import org.springframework.boot.logging.LoggingSystemProperties;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.classpath.ClassPathOverrides; import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension; import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -89,6 +91,7 @@ import static org.mockito.Mockito.times;
* @author Scott Frederick * @author Scott Frederick
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@ClassPathExclusions({ "log4j-core-*.jar", "log4j-api-*.jar" })
class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
private final LogbackLoggingSystem loggingSystem = new LogbackLoggingSystem(getClass().getClassLoader()); private final LogbackLoggingSystem loggingSystem = new LogbackLoggingSystem(getClass().getClassLoader());
@ -123,7 +126,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
} }
@Test @Test
@ClassPathOverrides("org.jboss.logging:jboss-logging:3.5.0.Final") @ClassPathOverrides({ "org.jboss.logging:jboss-logging:3.5.0.Final", "org.apache.logging.log4j:log4j-core:2.19.0" })
void jbossLoggingRoutesThroughLog4j2ByDefault() { void jbossLoggingRoutesThroughLog4j2ByDefault() {
System.getProperties().remove("org.jboss.logging.provider"); System.getProperties().remove("org.jboss.logging.provider");
org.jboss.logging.Logger jbossLogger = org.jboss.logging.Logger.getLogger(getClass()); org.jboss.logging.Logger jbossLogger = org.jboss.logging.Logger.getLogger(getClass());
@ -706,6 +709,15 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
.satisfies((ex) -> assertThat(ex.getCause()).isNotInstanceOf(IllegalArgumentException.class)); .satisfies((ex) -> assertThat(ex.getCause()).isNotInstanceOf(IllegalArgumentException.class));
} }
@Test
void applyingSystemPropertiesDoesNotCauseUnwantedStatusWarnings(CapturedOutput output) {
this.loggingSystem.beforeInitialize();
this.environment.getPropertySources()
.addFirst(new MapPropertySource("test", Map.of("logging.pattern.console", "[CONSOLE]%m")));
this.loggingSystem.initialize(this.initializationContext, "classpath:logback-nondefault.xml", null);
assertThat(output).doesNotContain("WARN");
}
private void initialize(LoggingInitializationContext context, String configLocation, LogFile logFile) { private void initialize(LoggingInitializationContext context, String configLocation, LogFile logFile) {
this.loggingSystem.getSystemProperties((ConfigurableEnvironment) context.getEnvironment()).apply(logFile); this.loggingSystem.getSystemProperties((ConfigurableEnvironment) context.getEnvironment()).apply(logFile);
this.loggingSystem.initialize(context, configLocation, logFile); this.loggingSystem.initialize(context, configLocation, logFile);

Loading…
Cancel
Save