From d5d96dff969392a851d7e20e7d8dd197fc18bb1b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 14 Jun 2019 15:12:05 +0100 Subject: [PATCH] Honor logback.debug property and write Logback statuses to console Closes gh-16876 --- .../logback/DebugLogbackConfigurator.java | 72 +++++++++++++++++++ .../logging/logback/LogbackConfigurator.java | 3 +- .../logging/logback/LogbackLoggingSystem.java | 9 ++- .../logback/LogbackLoggingSystemTests.java | 29 ++++++++ 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DebugLogbackConfigurator.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DebugLogbackConfigurator.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DebugLogbackConfigurator.java new file mode 100644 index 0000000000..4d70578dc5 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DebugLogbackConfigurator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.boot.logging.logback; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.pattern.Converter; +import ch.qos.logback.core.spi.LifeCycle; +import ch.qos.logback.core.status.InfoStatus; +import ch.qos.logback.core.status.Status; + +/** + * Custom {@link LogbackConfigurator} used to add {@link Status Statuses} when Logback + * debugging is enabled. + * + * @author Andy Wilkinson + */ +class DebugLogbackConfigurator extends LogbackConfigurator { + + DebugLogbackConfigurator(LoggerContext context) { + super(context); + } + + @Override + @SuppressWarnings("rawtypes") + public void conversionRule(String conversionWord, Class converterClass) { + info("Adding conversion rule of type '" + converterClass.getName() + "' for word '" + conversionWord); + super.conversionRule(conversionWord, converterClass); + } + + @Override + public void appender(String name, Appender appender) { + info("Adding appender '" + appender + "' named '" + name + "'"); + super.appender(name, appender); + } + + @Override + public void logger(String name, Level level, boolean additive, Appender appender) { + info("Configuring logger '" + name + "' with level '" + level + "'. Additive: " + additive); + if (appender != null) { + info("Adding appender '" + appender + "' to logger '" + name + "'"); + } + super.logger(name, level, additive, appender); + } + + @Override + public void start(LifeCycle lifeCycle) { + info("Starting '" + lifeCycle + "'"); + super.start(lifeCycle); + } + + private void info(String message) { + getContext().getStatusManager().add(new InfoStatus(message, this)); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackConfigurator.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackConfigurator.java index b8564b8a9a..5d9383f55d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackConfigurator.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackConfigurator.java @@ -28,7 +28,6 @@ import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.pattern.Converter; import ch.qos.logback.core.spi.ContextAware; import ch.qos.logback.core.spi.LifeCycle; -import ch.qos.logback.core.spi.PropertyContainer; import org.springframework.util.Assert; @@ -47,7 +46,7 @@ class LogbackConfigurator { this.context = context; } - public PropertyContainer getContext() { + public LoggerContext getContext() { return this.context; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java index 0325b03e21..f4ce815955 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java @@ -33,7 +33,9 @@ import ch.qos.logback.classic.turbo.TurboFilter; import ch.qos.logback.classic.util.ContextInitializer; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.spi.FilterReply; +import ch.qos.logback.core.status.OnConsoleStatusListener; import ch.qos.logback.core.status.Status; +import ch.qos.logback.core.util.StatusListenerConfigHelper; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import org.slf4j.Marker; @@ -125,7 +127,12 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { LoggerContext context = getLoggerContext(); stopAndReset(context); - LogbackConfigurator configurator = new LogbackConfigurator(context); + boolean debug = Boolean.getBoolean("logback.debug"); + if (debug) { + StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); + } + LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(context) + : new LogbackConfigurator(context); Environment environment = initializationContext.getEnvironment(); context.putProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN, environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}")); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index cc178795da..01a0201ed6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -460,6 +460,35 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { .containsPattern("\\d{4}-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}"); } + @Test + public void noDebugOutputIsProducedByDefault() { + System.clearProperty("logback.debug"); + this.loggingSystem.beforeInitialize(); + File file = new File(tmpDir(), "logback-test.log"); + LogFile logFile = getLogFile(file.getPath(), null); + this.loggingSystem.initialize(this.initializationContext, null, logFile); + String output = this.output.toString().trim(); + System.out.println(output); + assertThat(output).doesNotContain("LevelChangePropagator").doesNotContain("SizeAndTimeBasedFNATP"); + } + + @Test + public void logbackDebugPropertyIsHonored() { + System.setProperty("logback.debug", "true"); + try { + this.loggingSystem.beforeInitialize(); + File file = new File(tmpDir(), "logback-test.log"); + LogFile logFile = getLogFile(file.getPath(), null); + this.loggingSystem.initialize(this.initializationContext, null, logFile); + String output = this.output.toString().trim(); + assertThat(output).contains("LevelChangePropagator").contains("SizeAndTimeBasedFNATP") + .contains("DebugLogbackConfigurator"); + } + finally { + System.clearProperty("logback.debug"); + } + } + private static Logger getRootLogger() { ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); LoggerContext context = (LoggerContext) factory;