From 1725594a0edae57a50614210f094e59b6edca305 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 21 Oct 2020 16:05:14 -0700 Subject: [PATCH] Rationalize Logback logging properties Deprecate and provide alternatives for logging properties that are specific to Logback. The following Spring Boot properties have been changed: * logging.pattern.rolling-file-name -> logging.logback.rollingpolicy.file-name-pattern * logging.file.clean-history-on-start -> logging.logback.rollingpolicy.clean-history-on-start * logging.file.max-size -> logging.logback.rollingpolicy.max-file-size * logging.file.total-size-cap -> logging.logback.rollingpolicy.total-size-cap * logging.file.max-history -> logging.logback.rollingpolicy.max-history As have the system environment properties that they map to: * ROLLING_FILE_NAME_PATTERN -> LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN * LOG_FILE_CLEAN_HISTORY_ON_START -> LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START * LOG_FILE_MAX_SIZE -> LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE * LOG_FILE_TOTAL_SIZE_CAP -> LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP * LOG_FILE_MAX_HISTORY -> LOGBACK_ROLLINGPOLICY_MAX_HISTORY This commit also cleans up and simplifies `DefaultLogbackConfiguration`. Closes gh-23609 --- .../docs/asciidoc/spring-boot-features.adoc | 89 ++++++---- .../logging/LoggingApplicationListener.java | 7 +- .../boot/logging/LoggingSystem.java | 11 ++ .../boot/logging/LoggingSystemProperties.java | 82 +++++---- .../logback/DefaultLogbackConfiguration.java | 108 ++++-------- .../logging/logback/LogbackLoggingSystem.java | 7 + .../LogbackLoggingSystemProperties.java | 113 +++++++++++++ ...itional-spring-configuration-metadata.json | 125 ++++++++++---- .../boot/logging/logback/defaults.xml | 1 + .../boot/logging/logback/file-appender.xml | 10 +- .../LoggingApplicationListenerTests.java | 21 ++- .../logging/LoggingSystemPropertiesTests.java | 3 +- .../LogbackLoggingSystemPropertiesTests.java | 97 +++++++++++ .../logback/LogbackLoggingSystemTests.java | 160 +++++++++--------- ...-file-log-pattern-with-fileNamePattern.xml | 2 +- 15 files changed, 565 insertions(+), 271 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystemProperties.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemPropertiesTests.java diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 9bd73c7142..29dba35b35 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -2040,17 +2040,40 @@ The following table shows how the `logging.*` properties can be used together: |=== Log files rotate when they reach 10 MB and, as with console output, `ERROR`-level, `WARN`-level, and `INFO`-level messages are logged by default. -Size limits can be changed using the configprop:logging.file.max-size[] property. -Rotated log files of the last 7 days are kept by default unless the configprop:logging.file.max-history[] property has been set. -The total size of log archives can be capped using configprop:logging.file.total-size-cap[]. -When the total size of log archives exceeds that threshold, backups will be deleted. -To force log archive cleanup on application startup, use the configprop:logging.file.clean-history-on-start[] property. TIP: Logging properties are independent of the actual logging infrastructure. As a result, specific configuration keys (such as `logback.configurationFile` for Logback) are not managed by spring Boot. +[[boot-features-logging-file-rotation]] +=== File Rotation +If you are using the Logback, it's possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file. +For all other logging system, you'll need to configure rotation settings directly yourself (for example, if you use Log4J2 then you could add a `log4j.xml` file). + +The following rotation policy properties are supported: + +|=== +| Name | Description + +| configprop:logging.logback.rollingpolicy.file-name-pattern[] +| The filename pattern used to create log archives. + +| configprop:logging.logback.rollingpolicy.clean-history-on-start[] +| If log archive cleanup should occur when the application starts. + +| configprop:logging.logback.rollingpolicy.max-file-size[] +| The maximum size of log file before it's archived. + +| configprop:logging.logback.rollingpolicy.total-size-cap[] +| The maximum amount of size log archives can take before being deleted. + +| configprop:logging.logback.rollingpolicy.max-history[] +| The number of days to keep log archives (defaults to 7) +|=== + + + [[boot-features-custom-log-levels]] === Log Levels All the supported logging systems can have the logger levels set in the Spring `Environment` (for example, in `application.properties`) by using `+logging.level.=+` where `level` is one of TRACE, DEBUG, INFO, WARN, ERROR, FATAL, or OFF. @@ -2165,64 +2188,62 @@ To help with the customization, some other properties are transferred from the S | `LOG_EXCEPTION_CONVERSION_WORD` | The conversion word used when logging exceptions. -| configprop:logging.file.clean-history-on-start[] -| `LOG_FILE_CLEAN_HISTORY_ON_START` -| Whether to clean the archive log files on startup (if LOG_FILE enabled). - (Only supported with the default Logback setup.) - | configprop:logging.file.name[] | `LOG_FILE` | If defined, it is used in the default log configuration. -| configprop:logging.file.max-size[] -| `LOG_FILE_MAX_SIZE` -| Maximum log file size (if LOG_FILE enabled). - (Only supported with the default Logback setup.) - -| configprop:logging.file.max-history[] -| `LOG_FILE_MAX_HISTORY` -| Maximum number of archive log files to keep (if LOG_FILE enabled). - (Only supported with the default Logback setup.) - | configprop:logging.file.path[] | `LOG_PATH` | If defined, it is used in the default log configuration. -| configprop:logging.file.total-size-cap[] -| `LOG_FILE_TOTAL_SIZE_CAP` -| Total size of log backups to be kept (if LOG_FILE enabled). - (Only supported with the default Logback setup.) - | configprop:logging.pattern.console[] | `CONSOLE_LOG_PATTERN` | The log pattern to use on the console (stdout). - (Only supported with the default Logback setup.) | configprop:logging.pattern.dateformat[] | `LOG_DATEFORMAT_PATTERN` | Appender pattern for log date format. - (Only supported with the default Logback setup.) | configprop:logging.pattern.file[] | `FILE_LOG_PATTERN` | The log pattern to use in a file (if `LOG_FILE` is enabled). - (Only supported with the default Logback setup.) | configprop:logging.pattern.level[] | `LOG_LEVEL_PATTERN` | The format to use when rendering the log level (default `%5p`). - (Only supported with the default Logback setup.) - -| configprop:logging.pattern.rolling-file-name[] -| `ROLLING_FILE_NAME_PATTERN` -| Pattern for rolled-over log file names (default `$\{LOG_FILE}.%d\{yyyy-MM-dd}.%i.gz`). - (Only supported with the default Logback setup.) | `PID` | `PID` | The current process ID (discovered if possible and when not already defined as an OS environment variable). |=== +If you're using Logback, the following properties are also transfered: + +|=== +| Spring Environment | System Property | Comments + +| configprop:logging.logback.rollingpolicy.file-name-pattern[] +| `LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN` +| Pattern for rolled-over log file names (default `$\{LOG_FILE}.%d\{yyyy-MM-dd}.%i.gz`). + +| configprop:logging.logback.rollingpolicy.clean-history-on-start[] +| `LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START` +| Whether to clean the archive log files on startup. + +| configprop:logging.logback.rollingpolicy.max-file-size[] +| `LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE` +| Maximum log file size. + +| configprop:logging.logback.rollingpolicy.total-size-cap[] +| `LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP` +| Total size of log backups to be kept. + +| configprop:logging.logback.rollingpolicy.max-history[] +| `LOGBACK_ROLLINGPOLICY_MAX_HISTORY` +| Maximum number of archive log files to keep. +|=== + + All the supported logging systems can consult System properties when parsing their configuration files. See the default configurations in `spring-boot.jar` for examples: diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java index 5b6ceffc2a..1d901be8e4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java @@ -271,7 +271,7 @@ public class LoggingApplicationListener implements GenericApplicationListener { * @param classLoader the classloader */ protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) { - new LoggingSystemProperties(environment).apply(); + getLoggingSystemProperties(environment).apply(); this.logFile = LogFile.get(environment); if (this.logFile != null) { this.logFile.applyToSystemProperties(); @@ -283,6 +283,11 @@ public class LoggingApplicationListener implements GenericApplicationListener { registerShutdownHookIfNecessary(environment, this.loggingSystem); } + private LoggingSystemProperties getLoggingSystemProperties(ConfigurableEnvironment environment) { + return (this.loggingSystem != null) ? this.loggingSystem.getSystemProperties(environment) + : new LoggingSystemProperties(environment); + } + private void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) { if (this.parseArgs && this.springBootLogging == null) { if (isSet(environment, "debug")) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java index 0955603039..abada91ab7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java @@ -22,6 +22,7 @@ import java.util.EnumSet; import java.util.List; import java.util.Set; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -57,6 +58,16 @@ public abstract class LoggingSystem { private static final LoggingSystemFactory SYSTEM_FACTORY = LoggingSystemFactory.fromSpringFactories(); + /** + * Return the {@link LoggingSystemProperties} that should be applied. + * @param environment the {@link ConfigurableEnvironment} used to obtain value + * @return the {@link LoggingSystemProperties} to apply + * @since 2.4.0 + */ + public LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) { + return new LoggingSystemProperties(environment); + } + /** * Reset the logging system to be limit output. This method may be called before * {@link #initialize(LoggingInitializationContext, String, LogFile)} to reduce diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java index 160be0af97..39d8a00c54 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -61,31 +61,52 @@ public class LoggingSystemProperties { */ public static final String CONSOLE_LOG_PATTERN = "CONSOLE_LOG_PATTERN"; - /** - * The name of the System property that contains the clean history on start flag. - */ - public static final String FILE_CLEAN_HISTORY_ON_START = "LOG_FILE_CLEAN_HISTORY_ON_START"; - /** * The name of the System property that contains the file log pattern. */ public static final String FILE_LOG_PATTERN = "FILE_LOG_PATTERN"; /** - * The name of the System property that contains the file log max history. + * The name of the System property that contains the rolled-over log file name + * pattern. + * @deprecated since 2.4.0 in favor of + * {@link org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#ROLLINGPOLICY_FILE_NAME_PATTERN} */ - public static final String FILE_MAX_HISTORY = "LOG_FILE_MAX_HISTORY"; + @Deprecated + public static final String ROLLING_FILE_NAME_PATTERN = "ROLLING_FILE_NAME_PATTERN"; + + /** + * The name of the System property that contains the clean history on start flag. + * @deprecated since 2.4.0 in favor of + * {@link org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#ROLLINGPOLICY_CLEAN_HISTORY_ON_START} + */ + @Deprecated + public static final String FILE_CLEAN_HISTORY_ON_START = "LOG_FILE_CLEAN_HISTORY_ON_START"; /** * The name of the System property that contains the file log max size. + * @deprecated since 2.4.0 in favor of + * {@link org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#ROLLINGPOLICY_MAX_FILE_SIZE} */ + @Deprecated public static final String FILE_MAX_SIZE = "LOG_FILE_MAX_SIZE"; /** * The name of the System property that contains the file total size cap. + * @deprecated since 2.4.0 in favor of + * {@link org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#ROLLINGPOLICY_TOTAL_SIZE_CAP} */ + @Deprecated public static final String FILE_TOTAL_SIZE_CAP = "LOG_FILE_TOTAL_SIZE_CAP"; + /** + * The name of the System property that contains the file log max history. + * @deprecated since 2.4.0 in favor of + * {@link org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#ROLLINGPOLICY_MAX_HISTORY} + */ + @Deprecated + public static final String FILE_MAX_HISTORY = "LOG_FILE_MAX_HISTORY"; + /** * The name of the System property that contains the log level pattern. */ @@ -96,12 +117,6 @@ public class LoggingSystemProperties { */ public static final String LOG_DATEFORMAT_PATTERN = "LOG_DATEFORMAT_PATTERN"; - /** - * The name of the System property that contains the rolled-over log file name - * pattern. - */ - public static final String ROLLING_FILE_NAME_PATTERN = "ROLLING_FILE_NAME_PATTERN"; - private final Environment environment; /** @@ -113,43 +128,52 @@ public class LoggingSystemProperties { this.environment = environment; } - public void apply() { + public final void apply() { apply(null); } - public void apply(LogFile logFile) { + public final void apply(LogFile logFile) { PropertyResolver resolver = getPropertyResolver(); - setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD, "exception-conversion-word"); + apply(logFile, resolver); + } + + protected void apply(LogFile logFile, PropertyResolver resolver) { + setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD, "logging.exception-conversion-word"); setSystemProperty(PID_KEY, new ApplicationPid().toString()); - setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "pattern.console"); - setSystemProperty(resolver, FILE_LOG_PATTERN, "pattern.file"); - setSystemProperty(resolver, FILE_CLEAN_HISTORY_ON_START, "file.clean-history-on-start"); - setSystemProperty(resolver, FILE_MAX_HISTORY, "file.max-history"); - setSystemProperty(resolver, FILE_MAX_SIZE, "file.max-size"); - setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "file.total-size-cap"); - setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level"); - setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "pattern.dateformat"); - setSystemProperty(resolver, ROLLING_FILE_NAME_PATTERN, "pattern.rolling-file-name"); + setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "logging.pattern.console"); + setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "logging.pattern.dateformat"); + setSystemProperty(resolver, FILE_LOG_PATTERN, "logging.pattern.file"); + setSystemProperty(resolver, LOG_LEVEL_PATTERN, "logging.pattern.level"); + applyDeprecated(resolver); if (logFile != null) { logFile.applyToSystemProperties(); } } + private void applyDeprecated(PropertyResolver resolver) { + setSystemProperty(resolver, FILE_CLEAN_HISTORY_ON_START, "logging.file.clean-history-on-start"); + setSystemProperty(resolver, FILE_MAX_HISTORY, "logging.file.max-history"); + setSystemProperty(resolver, FILE_MAX_SIZE, "logging.file.max-size"); + setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "logging.file.total-size-cap"); + setSystemProperty(resolver, ROLLING_FILE_NAME_PATTERN, "logging.pattern.rolling-file-name"); + } + private PropertyResolver getPropertyResolver() { if (this.environment instanceof ConfigurableEnvironment) { PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver( ((ConfigurableEnvironment) this.environment).getPropertySources()); + resolver.setConversionService(((ConfigurableEnvironment) this.environment).getConversionService()); resolver.setIgnoreUnresolvableNestedPlaceholders(true); return resolver; } return this.environment; } - private void setSystemProperty(PropertyResolver resolver, String systemPropertyName, String propertyName) { - setSystemProperty(systemPropertyName, resolver.getProperty("logging." + propertyName)); + protected final void setSystemProperty(PropertyResolver resolver, String systemPropertyName, String propertyName) { + setSystemProperty(systemPropertyName, resolver.getProperty(propertyName)); } - private void setSystemProperty(String name, String value) { + protected final void setSystemProperty(String name, String value) { if (System.getProperty(name) == null && value != null) { System.setProperty(name, value); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java index 3d2ec34a21..49aa058f7e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java @@ -16,14 +16,11 @@ package org.springframework.boot.logging.logback; -import java.lang.reflect.Method; - import ch.qos.logback.classic.Level; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.ConsoleAppender; -import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy; import ch.qos.logback.core.util.FileSize; @@ -31,17 +28,12 @@ import ch.qos.logback.core.util.OptionHelper; import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LoggingInitializationContext; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertyResolver; -import org.springframework.core.env.PropertySourcesPropertyResolver; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.unit.DataSize; /** * Default logback configuration used by Spring Boot. Uses {@link LogbackConfigurator} to - * improve startup time. See also the {@code defaults.xml}, {@code console-appender.xml} - * and {@code file-appender.xml} files provided for classic {@code logback.xml} use. + * improve startup time. See also the {@code base.xml}, {@code defaults.xml}, + * {@code console-appender.xml} and {@code file-appender.xml} files provided for classic + * {@code logback.xml} use. * * @author Phillip Webb * @author Madhura Bhave @@ -50,43 +42,15 @@ import org.springframework.util.unit.DataSize; */ class DefaultLogbackConfiguration { - private static final String CONSOLE_LOG_PATTERN = "%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} " - + "%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} " - + "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} " - + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"; - - private static final String FILE_LOG_PATTERN = "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} " - + "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"; - - private static final DataSize MAX_FILE_SIZE = DataSize.ofMegabytes(10); - - private static final Integer MAX_FILE_HISTORY = 7; - - private final PropertyResolver patterns; - private final LogFile logFile; DefaultLogbackConfiguration(LoggingInitializationContext initializationContext, LogFile logFile) { - this.patterns = getPatternsResolver(initializationContext.getEnvironment()); this.logFile = logFile; } - private PropertyResolver getPatternsResolver(Environment environment) { - if (environment == null) { - return new PropertySourcesPropertyResolver(null); - } - if (environment instanceof ConfigurableEnvironment) { - PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver( - ((ConfigurableEnvironment) environment).getPropertySources()); - resolver.setIgnoreUnresolvableNestedPlaceholders(true); - return resolver; - } - return environment; - } - void apply(LogbackConfigurator config) { synchronized (config.getConfigurationLock()) { - base(config); + defaults(config); Appender consoleAppender = consoleAppender(config); if (this.logFile != null) { Appender fileAppender = fileAppender(config, this.logFile.toString()); @@ -98,10 +62,17 @@ class DefaultLogbackConfiguration { } } - private void base(LogbackConfigurator config) { + private void defaults(LogbackConfigurator config) { config.conversionRule("clr", ColorConverter.class); config.conversionRule("wex", WhitespaceThrowableProxyConverter.class); config.conversionRule("wEx", ExtendedWhitespaceThrowableProxyConverter.class); + config.getContext().putProperty("CONSOLE_LOG_PATTERN", resolve(config, "${CONSOLE_LOG_PATTERN:-" + + "%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) " + + "%clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} " + + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}")); + config.getContext().putProperty("FILE_LOG_PATTERN", resolve(config, "${FILE_LOG_PATTERN:-" + + "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] " + + "%-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}")); config.logger("org.apache.catalina.startup.DigesterFactory", Level.ERROR); config.logger("org.apache.catalina.util.LifecycleBase", Level.ERROR); config.logger("org.apache.coyote.http11.Http11NioProtocol", Level.WARN); @@ -115,8 +86,7 @@ class DefaultLogbackConfiguration { private Appender consoleAppender(LogbackConfigurator config) { ConsoleAppender appender = new ConsoleAppender<>(); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); - String logPattern = this.patterns.getProperty("logging.pattern.console", CONSOLE_LOG_PATTERN); - encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); + encoder.setPattern(resolve(config, "${CONSOLE_LOG_PATTERN}")); config.start(encoder); appender.setEncoder(encoder); config.appender("CONSOLE", appender); @@ -126,8 +96,7 @@ class DefaultLogbackConfiguration { private Appender fileAppender(LogbackConfigurator config, String logFile) { RollingFileAppender appender = new RollingFileAppender<>(); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); - String logPattern = this.patterns.getProperty("logging.pattern.file", FILE_LOG_PATTERN); - encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); + encoder.setPattern(resolve(config, "${FILE_LOG_PATTERN}")); appender.setEncoder(encoder); config.start(encoder); appender.setFile(logFile); @@ -140,45 +109,32 @@ class DefaultLogbackConfiguration { String logFile) { SizeAndTimeBasedRollingPolicy rollingPolicy = new SizeAndTimeBasedRollingPolicy<>(); rollingPolicy.setContext(config.getContext()); - rollingPolicy.setCleanHistoryOnStart( - this.patterns.getProperty("logging.file.clean-history-on-start", Boolean.class, false)); rollingPolicy.setFileNamePattern( - this.patterns.getProperty("logging.pattern.rolling-file-name", logFile + ".%d{yyyy-MM-dd}.%i.gz")); - setMaxFileSize(rollingPolicy, getDataSize("logging.file.max-size", MAX_FILE_SIZE)); - rollingPolicy - .setMaxHistory(this.patterns.getProperty("logging.file.max-history", Integer.class, MAX_FILE_HISTORY)); - DataSize totalSizeCap = getDataSize("logging.file.total-size-cap", - DataSize.ofBytes(CoreConstants.UNBOUNDED_TOTAL_SIZE_CAP)); - rollingPolicy.setTotalSizeCap(new FileSize(totalSizeCap.toBytes())); + resolve(config, "${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}")); + rollingPolicy.setCleanHistoryOnStart( + resolveBoolean(config, "${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}")); + rollingPolicy.setMaxFileSize(resolveFileSize(config, "${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}")); + rollingPolicy.setTotalSizeCap(resolveFileSize(config, "${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}")); + rollingPolicy.setMaxHistory(resolveInt(config, "${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}")); appender.setRollingPolicy(rollingPolicy); rollingPolicy.setParent(appender); config.start(rollingPolicy); } - private void setMaxFileSize(SizeAndTimeBasedRollingPolicy rollingPolicy, DataSize maxFileSize) { - try { - rollingPolicy.setMaxFileSize(new FileSize(maxFileSize.toBytes())); - } - catch (NoSuchMethodError ex) { - // Logback < 1.1.8 used String configuration - Method method = ReflectionUtils.findMethod(SizeAndTimeBasedRollingPolicy.class, "setMaxFileSize", - String.class); - ReflectionUtils.invokeMethod(method, rollingPolicy, String.valueOf(maxFileSize.toBytes())); - } + private boolean resolveBoolean(LogbackConfigurator config, String val) { + return Boolean.parseBoolean(resolve(config, val)); } - private DataSize getDataSize(String property, DataSize defaultSize) { - String value = this.patterns.getProperty(property); - if (value == null) { - return defaultSize; - } - try { - return DataSize.parse(value); - } - catch (IllegalArgumentException ex) { - FileSize fileSize = FileSize.valueOf(value); - return DataSize.ofBytes(fileSize.getSize()); - } + private int resolveInt(LogbackConfigurator config, String val) { + return Integer.parseInt(resolve(config, val)); + } + + private FileSize resolveFileSize(LogbackConfigurator config, String val) { + return FileSize.valueOf(resolve(config, val)); + } + + private String resolve(LogbackConfigurator config, String val) { + return OptionHelper.substVars(val, config.getContext()); } } 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 16b6e93347..c0f0a03e52 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 @@ -48,10 +48,12 @@ import org.springframework.boot.logging.LoggerConfiguration; import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystemFactory; +import org.springframework.boot.logging.LoggingSystemProperties; import org.springframework.boot.logging.Slf4JLoggingSystem; import org.springframework.core.Ordered; import org.springframework.core.SpringProperties; import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ResourceUtils; @@ -100,6 +102,11 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { super(classLoader); } + @Override + public LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) { + return new LogbackLoggingSystemProperties(environment); + } + @Override protected String[] getStandardConfigLocations() { return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" }; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystemProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystemProperties.java new file mode 100644 index 0000000000..09ff574d8b --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystemProperties.java @@ -0,0 +1,113 @@ +/* + * Copyright 2012-2020 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.core.util.FileSize; + +import org.springframework.boot.logging.LogFile; +import org.springframework.boot.logging.LoggingSystemProperties; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertyResolver; +import org.springframework.util.unit.DataSize; + +/** + * {@link LoggingSystemProperties} for Logback. + * + * @author Phillip Webb + * @since 2.4.0 + */ +public class LogbackLoggingSystemProperties extends LoggingSystemProperties { + + /** + * The name of the System property that contains the rolled-over log file name + * pattern. + */ + public static final String ROLLINGPOLICY_FILE_NAME_PATTERN = "LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN"; + + /** + * The name of the System property that contains the clean history on start flag. + */ + public static final String ROLLINGPOLICY_CLEAN_HISTORY_ON_START = "LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START"; + + /** + * The name of the System property that contains the file log max size. + */ + public static final String ROLLINGPOLICY_MAX_FILE_SIZE = "LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE"; + + /** + * The name of the System property that contains the file total size cap. + */ + public static final String ROLLINGPOLICY_TOTAL_SIZE_CAP = "LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP"; + + /** + * The name of the System property that contains the file log max history. + */ + public static final String ROLLINGPOLICY_MAX_HISTORY = "LOGBACK_ROLLINGPOLICY_MAX_HISTORY"; + + public LogbackLoggingSystemProperties(Environment environment) { + super(environment); + } + + @Override + protected void apply(LogFile logFile, PropertyResolver resolver) { + super.apply(logFile, resolver); + applyRollingPolicy(resolver, ROLLINGPOLICY_FILE_NAME_PATTERN, "logging.logback.rollingpolicy.file-name-pattern", + "logging.pattern.rolling-file-name"); + applyRollingPolicy(resolver, ROLLINGPOLICY_CLEAN_HISTORY_ON_START, + "logging.logback.rollingpolicy.clean-history-on-start", "logging.file.clean-history-on-start"); + applyRollingPolicy(resolver, ROLLINGPOLICY_MAX_FILE_SIZE, "logging.logback.rollingpolicy.max-file-size", + "logging.file.max-size", DataSize.class); + applyRollingPolicy(resolver, ROLLINGPOLICY_TOTAL_SIZE_CAP, "logging.logback.rollingpolicy.total-size-cap", + "logging.file.total-size-cap", DataSize.class); + applyRollingPolicy(resolver, ROLLINGPOLICY_MAX_HISTORY, "logging.logback.rollingpolicy.max-history", + "logging.file.max-history"); + } + + private void applyRollingPolicy(PropertyResolver resolver, String systemPropertyName, String propertyName, + String deprecatedPropertyName) { + applyRollingPolicy(resolver, systemPropertyName, propertyName, deprecatedPropertyName, String.class); + } + + private void applyRollingPolicy(PropertyResolver resolver, String systemPropertyName, String propertyName, + String deprecatedPropertyName, Class type) { + T value = getProperty(resolver, propertyName, type); + if (value == null) { + value = getProperty(resolver, deprecatedPropertyName, type); + } + if (value != null) { + String stringValue = String.valueOf((value instanceof DataSize) ? ((DataSize) value).toBytes() : value); + setSystemProperty(systemPropertyName, stringValue); + } + } + + @SuppressWarnings("unchecked") + private T getProperty(PropertyResolver resolver, String key, Class type) { + try { + return resolver.getProperty(key, type); + } + catch (ConversionFailedException | ConverterNotFoundException ex) { + if (type != DataSize.class) { + throw ex; + } + String value = resolver.getProperty(key); + return (T) DataSize.ofBytes(FileSize.valueOf(value).getSize()); + } + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 93eacab600..254fe80e61 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -35,27 +35,6 @@ "level": "error" } }, - { - "name": "logging.file.clean-history-on-start", - "type": "java.lang.Boolean", - "description": "Whether to clean the archive log files on startup. Only supported with the default logback setup.", - "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", - "defaultValue": false - }, - { - "name": "logging.file.max-history", - "type": "java.lang.Integer", - "description": "Maximum number of days archive log files are kept. Only supported with the default logback setup.", - "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", - "defaultValue": 7 - }, - { - "name": "logging.file.max-size", - "type": "org.springframework.util.unit.DataSize", - "description": "Maximum log file size. Only supported with the default logback setup.", - "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", - "defaultValue": "10MB" - }, { "name": "logging.file.name", "type": "java.lang.String", @@ -68,13 +47,6 @@ "description": "Location of the log file. For instance, `/var/log`.", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" }, - { - "name": "logging.file.total-size-cap", - "type": "org.springframework.util.unit.DataSize", - "description": "Total size of log backups to be kept. Only supported with the default logback setup.", - "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", - "defaultValue": "0B" - }, { "name": "logging.group", "type": "java.util.Map>", @@ -124,13 +96,6 @@ "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", "defaultValue": "%5p" }, - { - "name": "logging.pattern.rolling-file-name", - "type": "java.lang.String", - "description": "Pattern for rolled-over log file names. Supported only with the default Logback setup.", - "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", - "defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz" - }, { "name": "logging.register-shutdown-hook", "type": "java.lang.Boolean", @@ -138,6 +103,96 @@ "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", "defaultValue": false }, + { + "name": "logging.pattern.rolling-file-name", + "type": "java.lang.String", + "description": "Pattern for rolled-over log file names. Supported only with the default Logback setup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz", + "deprecation": { + "replacement": "logging.logback.rollingpolicy.file-name-pattern", + "level": "error" + } + }, + { + "name": "logging.file.clean-history-on-start", + "type": "java.lang.Boolean", + "description": "Whether to clean the archive log files on startup. Only supported with the default logback setup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": false, + "deprecation": { + "replacement": "logging.logback.rollingpolicy.clean-history-on-start", + "level": "error" + } + }, + { + "name": "logging.file.max-size", + "type": "org.springframework.util.unit.DataSize", + "description": "Maximum log file size. Only supported with the default logback setup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "10MB", + "deprecation": { + "replacement": "logging.logback.rollingpolicy.max-file-size", + "level": "error" + } + }, + { + "name": "logging.file.total-size-cap", + "type": "org.springframework.util.unit.DataSize", + "description": "Total size of log backups to be kept. Only supported with the default logback setup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "0B", + "deprecation": { + "replacement": "logging.logback.rollingpolicy.total-size-cap", + "level": "error" + } + }, + { + "name": "logging.file.max-history", + "type": "java.lang.Integer", + "description": "Maximum number of days archive log files are kept. Only supported with the default logback setup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": 7, + "deprecation": { + "replacement": "logging.logback.rollingpolicy.max-history", + "level": "error" + } + }, + { + "name": "logging.logback.rollingpolicy.file-name-pattern", + "type": "java.lang.String", + "description": "Pattern for rolled-over log file names.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz" + }, + { + "name": "logging.logback.rollingpolicy.clean-history-on-start", + "type": "java.lang.Boolean", + "description": "Whether to clean the archive log files on startup.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": false + }, + { + "name": "logging.logback.rollingpolicy.max-file-size", + "type": "org.springframework.util.unit.DataSize", + "description": "Maximum log file size.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "10MB" + }, + { + "name": "logging.logback.rollingpolicy.total-size-cap", + "type": "org.springframework.util.unit.DataSize", + "description": "Total size of log backups to be kept.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": "0B" + }, + { + "name": "logging.logback.rollingpolicy.max-history", + "type": "java.lang.Integer", + "description": "Maximum number of days archive log files are kept.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": 7 + }, { "name": "spring.application.index", "type": "java.lang.Integer", diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml index e4d99314c9..b2b1bfdf4a 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml @@ -8,6 +8,7 @@ Default logback configuration provided for import + diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml index 8275d3d8a1..fadd1e4ca0 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml @@ -13,11 +13,11 @@ initialization performed by Boot ${LOG_FILE} - ${LOG_FILE_CLEAN_HISTORY_ON_START:-false} - ${ROLLING_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} - ${LOG_FILE_MAX_SIZE:-10MB} - ${LOG_FILE_MAX_HISTORY:-7} - ${LOG_FILE_TOTAL_SIZE_CAP:-0} + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java index f72c008d3e..88a9d5f2f2 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java @@ -21,8 +21,10 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Handler; @@ -109,10 +111,13 @@ class LoggingApplicationListenerTests { private File logFile; + private Set systemPropertyNames; + private CapturedOutput output; @BeforeEach void init(CapturedOutput output) throws SecurityException, IOException { + this.systemPropertyNames = new HashSet<>(System.getProperties().keySet()); this.output = output; this.logFile = new File(this.tempDir.toFile(), "foo.log"); LogManager.getLogManager().readConfiguration(JavaLoggingSystem.class.getResourceAsStream("logging.properties")); @@ -131,15 +136,8 @@ class LoggingApplicationListenerTests { loggingSystem.getShutdownHandler().run(); } System.clearProperty(LoggingSystem.class.getName()); - System.clearProperty(LoggingSystemProperties.LOG_FILE); - System.clearProperty(LoggingSystemProperties.LOG_PATH); - System.clearProperty(LoggingSystemProperties.PID_KEY); - System.clearProperty(LoggingSystemProperties.EXCEPTION_CONVERSION_WORD); - System.clearProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN); - System.clearProperty(LoggingSystemProperties.FILE_LOG_PATTERN); - System.clearProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN); - System.clearProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN); System.clearProperty(LoggingSystem.SYSTEM_PROPERTY); + System.getProperties().keySet().retainAll(this.systemPropertyNames); if (this.context != null) { this.context.close(); } @@ -467,9 +465,14 @@ class LoggingApplicationListenerTests { assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE)).isEqualTo(this.logFile.getAbsolutePath()); assertThat(System.getProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN)).isEqualTo("level"); assertThat(System.getProperty(LoggingSystemProperties.LOG_PATH)).isEqualTo("path"); + assertThat(System.getProperty(LoggingSystemProperties.PID_KEY)).isNotNull(); + assertDeprecated(); + } + + @SuppressWarnings("deprecation") + private void assertDeprecated() { assertThat(System.getProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN)) .isEqualTo("my.log.%d{yyyyMMdd}.%i.gz"); - assertThat(System.getProperty(LoggingSystemProperties.PID_KEY)).isNotNull(); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java index dee39064d0..e82165ae8d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -84,6 +84,7 @@ class LoggingSystemPropertiesTests { } @Test + @SuppressWarnings("deprecation") void rollingFileNameIsSet() { new LoggingSystemProperties( new MockEnvironment().withProperty("logging.pattern.rolling-file-name", "rolling file pattern")) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemPropertiesTests.java new file mode 100644 index 0000000000..7e8ddda1d0 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemPropertiesTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2020 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 java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.convert.ApplicationConversionService; +import org.springframework.boot.logging.LoggingSystemProperties; +import org.springframework.core.convert.support.ConfigurableConversionService; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LogbackLoggingSystemProperties}. + * + * @author Phillip Webb + */ +class LogbackLoggingSystemPropertiesTests { + + private Set systemPropertyNames; + + private MockEnvironment environment; + + @BeforeEach + void captureSystemPropertyNames() { + this.systemPropertyNames = new HashSet<>(System.getProperties().keySet()); + this.environment = new MockEnvironment(); + this.environment + .setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance()); + + } + + @AfterEach + void restoreSystemProperties() { + System.getProperties().keySet().retainAll(this.systemPropertyNames); + } + + @Test + void applySetsStandardSystemProperties() { + this.environment.setProperty("logging.pattern.console", "boot"); + new LogbackLoggingSystemProperties(this.environment).apply(); + assertThat(System.getProperties()).containsEntry(LoggingSystemProperties.CONSOLE_LOG_PATTERN, "boot"); + } + + @Test + void applySetsLogbackSystemProperties() { + this.environment.setProperty("logging.logback.rollingpolicy.file-name-pattern", "fnp"); + this.environment.setProperty("logging.logback.rollingpolicy.clean-history-on-start", "chos"); + this.environment.setProperty("logging.logback.rollingpolicy.max-file-size", "1KB"); + this.environment.setProperty("logging.logback.rollingpolicy.total-size-cap", "2KB"); + this.environment.setProperty("logging.logback.rollingpolicy.max-history", "mh"); + new LogbackLoggingSystemProperties(this.environment).apply(); + assertThat(System.getProperties()) + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_FILE_NAME_PATTERN, "fnp") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_CLEAN_HISTORY_ON_START, "chos") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_MAX_FILE_SIZE, "1024") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_TOTAL_SIZE_CAP, "2048") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_MAX_HISTORY, "mh"); + } + + @Test + void applySetsLogbackSystemPropertiesFromDeprecated() { + this.environment.setProperty("logging.pattern.rolling-file-name", "fnp"); + this.environment.setProperty("logging.file.clean-history-on-start", "chos"); + this.environment.setProperty("logging.file.max-size", "1KB"); + this.environment.setProperty("logging.file.total-size-cap", "2KB"); + this.environment.setProperty("logging.file.max-history", "mh"); + new LogbackLoggingSystemProperties(this.environment).apply(); + assertThat(System.getProperties()) + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_FILE_NAME_PATTERN, "fnp") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_CLEAN_HISTORY_ON_START, "chos") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_MAX_FILE_SIZE, "1024") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_TOTAL_SIZE_CAP, "2048") + .containsEntry(LogbackLoggingSystemProperties.ROLLINGPOLICY_MAX_HISTORY, "mh"); + } + +} 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 fa91f0200d..64e8170081 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 @@ -40,6 +40,7 @@ import org.slf4j.ILoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import org.slf4j.impl.StaticLoggerBinder; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.logging.AbstractLoggingSystemTests; import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LogLevel; @@ -49,6 +50,9 @@ import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystemProperties; import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.OutputCaptureExtension; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.ConfigurableConversionService; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.mock.env.MockEnvironment; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.StringUtils; @@ -79,6 +83,8 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { private Logger logger; + private MockEnvironment environment; + private LoggingInitializationContext initializationContext; private Set systemPropertyNames; @@ -88,8 +94,10 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { this.systemPropertyNames = new HashSet<>(System.getProperties().keySet()); this.loggingSystem.cleanUp(); this.logger = ((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory()).getLogger(getClass()); - MockEnvironment environment = new MockEnvironment(); - this.initializationContext = new LoggingInitializationContext(environment); + this.environment = new MockEnvironment(); + ConversionService conversionService = ApplicationConversionService.getSharedInstance(); + this.environment.setConversionService((ConfigurableConversionService) conversionService); + this.initializationContext = new LoggingInitializationContext(this.environment); } @AfterEach @@ -103,7 +111,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { void noFile(CapturedOutput output) { this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.logger.info("Hello world"); assertThat(output).contains("Hello world").doesNotContain("Hidden"); assertThat(getLineWithText(output, "Hello world")).contains("INFO"); @@ -114,7 +122,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { void withFile(CapturedOutput output) { this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); - this.loggingSystem.initialize(this.initializationContext, null, getLogFile(null, tmpDir())); + initialize(this.initializationContext, null, getLogFile(null, tmpDir())); this.logger.info("Hello world"); File file = new File(tmpDir() + "/spring.log"); assertThat(output).doesNotContain("LOGBACK:"); @@ -129,14 +137,14 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void defaultConfigConfiguresAConsoleAppender() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); assertThat(getConsoleAppender()).isNotNull(); } @Test void testNonDefaultConfigLocation(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, "classpath:logback-nondefault.xml", + initialize(this.initializationContext, "classpath:logback-nondefault.xml", getLogFile(tmpDir() + "/tmp.log", null)); this.logger.info("Hello world"); assertThat(output).doesNotContain("DEBUG").contains("Hello world").contains(tmpDir() + "/tmp.log") @@ -149,7 +157,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { System.setProperty("logback.configurationFile", "/foo/my-file.xml"); try { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); assertThat(output).contains( "Ignoring 'logback.configurationFile' system property. Please use 'logging.config' instead."); } @@ -161,8 +169,8 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testNonexistentConfigLocation() { this.loggingSystem.beforeInitialize(); - assertThatIllegalStateException().isThrownBy(() -> this.loggingSystem.initialize(this.initializationContext, - "classpath:logback-nonexistent.xml", null)); + assertThatIllegalStateException() + .isThrownBy(() -> initialize(this.initializationContext, "classpath:logback-nonexistent.xml", null)); } @Test @@ -174,7 +182,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void setLevel(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.logger.debug("Hello"); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.logger.debug("Hello"); @@ -184,7 +192,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void setLevelToNull(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.logger.debug("Hello"); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.logger.debug("Hello"); @@ -196,7 +204,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggingConfigurations() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); List configurations = this.loggingSystem.getLoggerConfigurations(); assertThat(configurations).isNotEmpty(); @@ -206,7 +214,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggingConfiguration() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName()); assertThat(configuration) @@ -216,7 +224,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggingConfigurationForLoggerThatDoesNotExistShouldReturnNull() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration("doesnotexist"); assertThat(configuration).isNull(); } @@ -224,7 +232,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggingConfigurationForALL() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); Logger logger = (Logger) StaticLoggerBinder.getSingleton().getLoggerFactory().getLogger(getClass().getName()); logger.setLevel(Level.ALL); LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName()); @@ -235,7 +243,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void systemLevelTraceShouldReturnNativeLevelTraceNotAll() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.TRACE); Logger logger = (Logger) StaticLoggerBinder.getSingleton().getLoggerFactory().getLogger(getClass().getName()); assertThat(logger.getLevel()).isEqualTo(Level.TRACE); @@ -244,7 +252,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void loggingThatUsesJulIsCaptured(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(getClass().getName()); julLogger.info("Hello world"); assertThat(output).contains("Hello world"); @@ -253,7 +261,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void loggingLevelIsPropagatedToJul(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(getClass().getName()); julLogger.fine("Hello debug world"); @@ -296,33 +304,30 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testConsolePatternProperty(CapturedOutput output) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.pattern.console", "%logger %msg"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); - this.loggingSystem.initialize(loggingInitializationContext, null, null); + this.environment.setProperty("logging.pattern.console", "%logger %msg"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); + initialize(loggingInitializationContext, null, null); this.logger.info("Hello world"); assertThat(getLineWithText(output, "Hello world")).doesNotContain("INFO"); } @Test void testLevelPatternProperty(CapturedOutput output) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.pattern.level", "X%clr(%p)X"); - new LoggingSystemProperties(environment).apply(); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); - this.loggingSystem.initialize(loggingInitializationContext, null, null); + this.environment.setProperty("logging.pattern.level", "X%clr(%p)X"); + new LoggingSystemProperties(this.environment).apply(); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); + initialize(loggingInitializationContext, null, null); this.logger.info("Hello world"); assertThat(getLineWithText(output, "Hello world")).contains("XINFOX"); } @Test void testFilePatternProperty(CapturedOutput output) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.pattern.file", "%logger %msg"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.pattern.file", "%logger %msg"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(output, "Hello world")).contains("INFO"); assertThat(getLineWithText(file, "Hello world")).doesNotContain("INFO"); @@ -330,12 +335,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testCleanHistoryOnStartProperty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.clean-history-on-start", "true"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.clean-history-on-start", "true"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(getRollingPolicy().isCleanHistoryOnStart()).isTrue(); @@ -343,12 +347,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testCleanHistoryOnStartPropertyWithXmlConfiguration() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.clean-history-on-start", "true"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.clean-history-on-start", "true"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); + initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(getRollingPolicy().isCleanHistoryOnStart()).isTrue(); @@ -370,12 +373,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { } private void testMaxFileSizeProperty(String sizeValue, String expectedFileSize) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.max-size", sizeValue); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.max-size", sizeValue); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "maxFileSize").toString()) @@ -384,12 +386,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testMaxFileSizePropertyWithXmlConfiguration() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.max-size", "100MB"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.max-size", "100MB"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); + initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "maxFileSize").toString()).isEqualTo("100 MB"); @@ -397,12 +398,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testMaxHistoryProperty() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.max-history", "30"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.max-history", "30"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(getRollingPolicy().getMaxHistory()).isEqualTo(30); @@ -410,12 +410,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testMaxHistoryPropertyWithXmlConfiguration() { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.max-history", "30"); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.max-history", "30"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); + initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(getRollingPolicy().getMaxHistory()).isEqualTo(30); @@ -437,12 +436,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { } private void testTotalSizeCapProperty(String sizeValue, String expectedFileSize) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.total-size-cap", sizeValue); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.total-size-cap", sizeValue); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "totalSizeCap").toString()) @@ -452,12 +450,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testTotalSizeCapPropertyWithXmlConfiguration() { String expectedSize = "101 MB"; - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.file.total-size-cap", expectedSize); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.file.total-size-cap", expectedSize); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); + initialize(loggingInitializationContext, "classpath:logback-include-base.xml", logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(ReflectionTestUtils.getField(getRollingPolicy(), "totalSizeCap").toString()).isEqualTo(expectedSize); @@ -466,7 +463,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void exceptionsIncludeClassPackaging(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, getLogFile(null, tmpDir())); + initialize(this.initializationContext, null, getLogFile(null, tmpDir())); this.logger.warn("Expected exception", new RuntimeException("Expected")); String fileContents = contentOf(new File(tmpDir() + "/spring.log")); assertThat(fileContents).contains("[junit-"); @@ -479,7 +476,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { try { this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); - this.loggingSystem.initialize(this.initializationContext, null, getLogFile(null, tmpDir())); + initialize(this.initializationContext, null, getLogFile(null, tmpDir())); this.logger.warn("Expected exception", new RuntimeException("Expected", new RuntimeException("Cause"))); String fileContents = contentOf(new File(tmpDir() + "/spring.log")); assertThat(fileContents).contains("java.lang.RuntimeException: Expected").doesNotContain("Wrapped by:"); @@ -496,7 +493,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); LogFile logFile = getLogFile(tmpDir() + "/example.log", null, false); - this.loggingSystem.initialize(this.initializationContext, "classpath:logback-nondefault.xml", logFile); + initialize(this.initializationContext, "classpath:logback-nondefault.xml", logFile); assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE)).endsWith("example.log"); } @@ -506,24 +503,23 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { LoggerContextListener listener = mock(LoggerContextListener.class); loggerContext.addListener(listener); this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); verify(listener, times(1)).onReset(loggerContext); this.loggingSystem.cleanUp(); loggerContext.addListener(listener); this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(this.initializationContext, null, null); + initialize(this.initializationContext, null, null); verify(listener, times(2)).onReset(loggerContext); } @Test void testDateformatPatternProperty(CapturedOutput output) { - MockEnvironment environment = new MockEnvironment(); - environment.setProperty("logging.pattern.dateformat", "yyyy-MM-dd'T'hh:mm:ss.SSSZ"); - new LoggingSystemProperties(environment).apply(); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); - this.loggingSystem.initialize(loggingInitializationContext, null, null); + this.environment.setProperty("logging.pattern.dateformat", "yyyy-MM-dd'T'hh:mm:ss.SSSZ"); + new LoggingSystemProperties(this.environment).apply(); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); + initialize(loggingInitializationContext, null, null); this.logger.info("Hello world"); assertThat(getLineWithText(output, "Hello world")) .containsPattern("\\d{4}-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}"); @@ -535,7 +531,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { this.loggingSystem.beforeInitialize(); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(this.initializationContext, null, logFile); + initialize(this.initializationContext, null, logFile); assertThat(output).doesNotContain("LevelChangePropagator").doesNotContain("SizeAndTimeBasedFNATP"); } @@ -546,7 +542,7 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { this.loggingSystem.beforeInitialize(); File file = new File(tmpDir(), "logback-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(this.initializationContext, null, logFile); + initialize(this.initializationContext, null, logFile); assertThat(output).contains("LevelChangePropagator").contains("SizeAndTimeBasedFNATP") .contains("DebugLogbackConfigurator"); } @@ -557,18 +553,22 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testRollingFileNameProperty() { - MockEnvironment environment = new MockEnvironment(); String rollingFile = "my.log.%d{yyyyMMdd}.%i.gz"; - environment.setProperty("logging.pattern.rolling-file-name", rollingFile); - LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(environment); + this.environment.setProperty("logging.pattern.rolling-file-name", rollingFile); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment); File file = new File(tmpDir(), "my.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + initialize(loggingInitializationContext, null, logFile); this.logger.info("Hello world"); assertThat(getLineWithText(file, "Hello world")).contains("INFO"); assertThat(getRollingPolicy().getFileNamePattern()).isEqualTo(rollingFile); } + private void initialize(LoggingInitializationContext context, String configLocation, LogFile logFile) { + this.loggingSystem.getSystemProperties((ConfigurableEnvironment) context.getEnvironment()).apply(logFile); + this.loggingSystem.initialize(context, configLocation, logFile); + } + private static Logger getRootLogger() { ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); LoggerContext context = (LoggerContext) factory; diff --git a/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml b/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml index 2539b8de32..1ae820bc92 100644 --- a/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml +++ b/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml @@ -1,4 +1,4 @@ - +