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
pull/23886/head
Phillip Webb 4 years ago
parent 9c54a5369d
commit 1725594a0e

@ -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.<logger-name>=<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:

@ -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")) {

@ -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

@ -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.
@ -62,30 +62,51 @@ 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.
* The name of the System property that contains the file log pattern.
*/
public static final String FILE_CLEAN_HISTORY_ON_START = "LOG_FILE_CLEAN_HISTORY_ON_START";
public static final String FILE_LOG_PATTERN = "FILE_LOG_PATTERN";
/**
* The name of the System property that contains the file log pattern.
* 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_LOG_PATTERN = "FILE_LOG_PATTERN";
@Deprecated
public static final String ROLLING_FILE_NAME_PATTERN = "ROLLING_FILE_NAME_PATTERN";
/**
* The name of the System property that contains the file log max history.
* 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}
*/
public static final String FILE_MAX_HISTORY = "LOG_FILE_MAX_HISTORY";
@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);
}

@ -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<ILoggingEvent> consoleAppender = consoleAppender(config);
if (this.logFile != null) {
Appender<ILoggingEvent> 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<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
ConsoleAppender<ILoggingEvent> 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<ILoggingEvent> fileAppender(LogbackConfigurator config, String logFile) {
RollingFileAppender<ILoggingEvent> 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<ILoggingEvent> 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<ILoggingEvent> 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());
}
}

@ -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" };

@ -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 <T> void applyRollingPolicy(PropertyResolver resolver, String systemPropertyName, String propertyName,
String deprecatedPropertyName, Class<T> 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> T getProperty(PropertyResolver resolver, String key, Class<T> 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());
}
}
}

@ -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<java.lang.String,java.util.List<java.lang.String>>",
@ -124,20 +96,103 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "%5p"
},
{
"name": "logging.register-shutdown-hook",
"type": "java.lang.Boolean",
"description": "Register a shutdown hook for the logging system when it is initialized.",
"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.register-shutdown-hook",
"name": "logging.logback.rollingpolicy.clean-history-on-start",
"type": "java.lang.Boolean",
"description": "Register a shutdown hook for the logging system when it is initialized.",
"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",

@ -8,6 +8,7 @@ Default logback configuration provided for import
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<property name="CONSOLE_LOG_PATTERN" value="${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}}"/>
<property name="FILE_LOG_PATTERN" value="${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}}"/>

@ -13,11 +13,11 @@ initialization performed by Boot
</encoder>
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<cleanHistoryOnStart>${LOG_FILE_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<fileNamePattern>${ROLLING_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-7}</maxHistory>
<totalSizeCap>${LOG_FILE_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}</maxHistory>
</rollingPolicy>
</appender>
</included>

@ -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<Object> 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

@ -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"))

@ -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<Object> 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");
}
}

@ -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<Object> 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<LoggerConfiguration> 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;

@ -1,4 +1,4 @@
<configuration>
<property name="ROLLING_FILE_NAME_PATTERN" value="my.log.%d{yyyyMMdd}.%i.gz"/>
<property name="LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN" value="my.log.%d{yyyyMMdd}.%i.gz"/>
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>

Loading…
Cancel
Save