Commit 1725594a authored by Phillip Webb's avatar Phillip Webb

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
parent 9c54a536
......@@ -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
......
/*
* 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" };
......
/*
* 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
......
/*
* 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"))
......
/*
* 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;
......
<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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment