Add ROLLING_FILE_NAME_PATTERN for File Appender
This new property allows to customize `fileNamePattern` if it is set. Otherwise, a default pattern remains. Also, new property is supported `logging.pattern.rolling-file-name`. See gh-18151
This commit is contained in:
committed by
Stephane Nicoll
parent
06f46baa9d
commit
4a3810a0f1
@@ -1307,7 +1307,7 @@ The following files are provided under `org/springframework/boot/logging/logback
|
||||
|
||||
* `defaults.xml` - Provides conversion rules, pattern properties and common logger configurations.
|
||||
* `console-appender.xml` - Adds a `ConsoleAppender` using the `CONSOLE_LOG_PATTERN`.
|
||||
* `file-appender.xml` - Adds a `RollingFileAppender` using the `FILE_LOG_PATTERN` with appropriate settings.
|
||||
* `file-appender.xml` - Adds a `RollingFileAppender` using the `FILE_LOG_PATTERN` and `ROLLING_FILE_NAME_PATTERN` with appropriate settings.
|
||||
|
||||
In addition, a legacy `base.xml` file is provided for compatibility with earlier versions of Spring Boot.
|
||||
|
||||
@@ -1332,6 +1332,7 @@ Your logback configuration file can also make use of System properties that the
|
||||
* `$\{LOG_FILE}`: Whether `logging.file.name` was set in Boot's external configuration.
|
||||
* `$\{LOG_PATH}`: Whether `logging.file.path` (representing a directory for log files to live in) was set in Boot's external configuration.
|
||||
* `$\{LOG_EXCEPTION_CONVERSION_WORD}`: Whether `logging.exception-conversion-word` was set in Boot's external configuration.
|
||||
* `$\{ROLLING_FILE_NAME_PATTERN}`: Whether `logging.pattern.rolling-file-name` was set in Boot's external configuration.
|
||||
|
||||
Spring Boot also provides some nice ANSI color terminal output on a console (but not in a log file) by using a custom Logback converter.
|
||||
See the `CONSOLE_LOG_PATTERN` in the `default.xml` configuration for an example.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[spring-boot-reference-documentation]]
|
||||
= Spring Boot Reference Documentation
|
||||
Phillip Webb, Dave Syer, Josh Long, Stéphane Nicoll, Rob Winch, Andy Wilkinson, Marcel Overdijk, Christian Dupuis, Sébastien Deleuze, Michael Simons, Vedran Pavić, Jay Bryant, Madhura Bhave
|
||||
Phillip Webb, Dave Syer, Josh Long, Stéphane Nicoll, Rob Winch, Andy Wilkinson, Marcel Overdijk, Christian Dupuis, Sébastien Deleuze, Michael Simons, Vedran Pavić, Jay Bryant, Madhura Bhave, Eddú Meléndez
|
||||
:docinfo: shared
|
||||
|
||||
The reference documentation consists of the following sections:
|
||||
|
||||
@@ -1775,6 +1775,11 @@ To help with the customization, some other properties are transferred from the S
|
||||
| The format to use when rendering the log level (default `%5p`).
|
||||
(Only supported with the default Logback setup.)
|
||||
|
||||
| `logging.pattern.rolling-file-name`
|
||||
| `ROLLING_FILE_NAME_PATTERN`
|
||||
| Pattern to use when roll-over log files (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).
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
|
||||
* @author Madhura Bhave
|
||||
* @author Vedran Pavic
|
||||
* @author Robert Thornton
|
||||
* @author Eddú Meléndez
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class LoggingSystemProperties {
|
||||
@@ -95,6 +96,11 @@ 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 pattern.
|
||||
*/
|
||||
public static final String ROLLING_FILE_NAME_PATTERN = "ROLLING_FILE_NAME_PATTERN";
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
@@ -122,6 +128,7 @@ public class LoggingSystemProperties {
|
||||
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");
|
||||
if (logFile != null) {
|
||||
logFile.applyToSystemProperties();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.unit.DataSize;
|
||||
* @author Madhura Bhave
|
||||
* @author Vedran Pavic
|
||||
* @author Robert Thornton
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
class DefaultLogbackConfiguration {
|
||||
|
||||
@@ -140,7 +141,8 @@ class DefaultLogbackConfiguration {
|
||||
SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new SizeAndTimeBasedRollingPolicy<>();
|
||||
rollingPolicy.setCleanHistoryOnStart(
|
||||
this.patterns.getProperty("logging.file.clean-history-on-start", Boolean.class, false));
|
||||
rollingPolicy.setFileNamePattern(logFile + ".%d{yyyy-MM-dd}.%i.gz");
|
||||
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));
|
||||
|
||||
@@ -61,6 +61,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Ben Hale
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class LogbackLoggingSystem extends Slf4JLoggingSystem {
|
||||
@@ -139,6 +140,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
|
||||
environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
|
||||
context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders(
|
||||
"${logging.pattern.dateformat:${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}"));
|
||||
context.putProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN, environment
|
||||
.resolvePlaceholders("${logging.pattern.rolling-file-name:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}"));
|
||||
new DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);
|
||||
context.setPackagingDataEnabled(true);
|
||||
}
|
||||
|
||||
@@ -165,6 +165,13 @@
|
||||
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
|
||||
"defaultValue": "%5p"
|
||||
},
|
||||
{
|
||||
"name": "logging.pattern.rolling-file-name",
|
||||
"type": "java.lang.String",
|
||||
"description": "Pattern for roll-over log files. Supported only with the default Logback setup.",
|
||||
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
|
||||
"defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz"
|
||||
},
|
||||
{
|
||||
"name": "logging.register-shutdown-hook",
|
||||
"type": "java.lang.Boolean",
|
||||
|
||||
@@ -14,7 +14,7 @@ initialization performed by Boot
|
||||
<file>${LOG_FILE}</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<cleanHistoryOnStart>${LOG_FILE_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
|
||||
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
|
||||
<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>
|
||||
|
||||
@@ -83,6 +83,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Stephane Nicoll
|
||||
* @author Ben Hale
|
||||
* @author Fahim Farook
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@ClassPathExclusions("log4j*.jar")
|
||||
@@ -134,6 +135,7 @@ class LoggingApplicationListenerTests {
|
||||
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);
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
@@ -479,7 +481,8 @@ class LoggingApplicationListenerTests {
|
||||
void systemPropertiesAreSetForLoggingConfiguration() {
|
||||
addPropertiesToEnvironment(this.context, "logging.exception-conversion-word=conversion",
|
||||
"logging.file.name=" + this.logFile, "logging.file.path=path", "logging.pattern.console=console",
|
||||
"logging.pattern.file=file", "logging.pattern.level=level");
|
||||
"logging.pattern.file=file", "logging.pattern.level=level",
|
||||
"logging.pattern.rolling-file-name=my.log.%d{yyyyMMdd}.%i.gz");
|
||||
this.initializer.initialize(this.context.getEnvironment(), this.context.getClassLoader());
|
||||
assertThat(System.getProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN)).isEqualTo("console");
|
||||
assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).isEqualTo("file");
|
||||
@@ -487,6 +490,8 @@ 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.ROLLING_FILE_NAME_PATTERN))
|
||||
.isEqualTo("my.log.%d{yyyyMMdd}.%i.gz");
|
||||
assertThat(System.getProperty(LoggingSystemProperties.PID_KEY)).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Tests for {@link LoggingSystemProperties}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
class LoggingSystemPropertiesTests {
|
||||
|
||||
@@ -82,6 +83,15 @@ class LoggingSystemPropertiesTests {
|
||||
assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).matches("[0-9]+");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rollingFileIsSet() {
|
||||
new LoggingSystemProperties(
|
||||
new MockEnvironment().withProperty("logging.pattern.rolling-file-name", "rolling file pattern"))
|
||||
.apply(null);
|
||||
assertThat(System.getProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN))
|
||||
.isEqualTo("rolling file pattern");
|
||||
}
|
||||
|
||||
private Environment environment(String key, Object value) {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
environment.getPropertySources().addLast(new MapPropertySource("test", Collections.singletonMap(key, value)));
|
||||
|
||||
@@ -27,6 +27,9 @@ import ch.qos.logback.core.ConsoleAppender;
|
||||
import ch.qos.logback.core.FileAppender;
|
||||
import ch.qos.logback.core.encoder.Encoder;
|
||||
import ch.qos.logback.core.joran.spi.JoranException;
|
||||
import ch.qos.logback.core.rolling.RollingFileAppender;
|
||||
import ch.qos.logback.core.rolling.RollingPolicy;
|
||||
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -35,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Tests for default Logback configuration provided by {@code base.xml}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
class LogbackConfigurationTests {
|
||||
|
||||
@@ -64,4 +68,30 @@ class LogbackConfigurationTests {
|
||||
assertThat(((PatternLayoutEncoder) encoder).getPattern()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultFileNamePattern() throws JoranException {
|
||||
JoranConfigurator configurator = new JoranConfigurator();
|
||||
LoggerContext context = new LoggerContext();
|
||||
configurator.setContext(context);
|
||||
configurator.doConfigure(new File("src/test/resources/custom-file-log-pattern.xml"));
|
||||
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("FILE");
|
||||
assertThat(appender).isInstanceOf(RollingFileAppender.class);
|
||||
RollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();
|
||||
String fileNamePattern = ((SizeAndTimeBasedRollingPolicy) rollingPolicy).getFileNamePattern();
|
||||
assertThat(fileNamePattern).endsWith("spring.log.%d{yyyy-MM-dd}.%i.gz");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFileNamePattern() throws JoranException {
|
||||
JoranConfigurator configurator = new JoranConfigurator();
|
||||
LoggerContext context = new LoggerContext();
|
||||
configurator.setContext(context);
|
||||
configurator.doConfigure(new File("src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml"));
|
||||
Appender<ILoggingEvent> appender = context.getLogger("ROOT").getAppender("FILE");
|
||||
assertThat(appender).isInstanceOf(RollingFileAppender.class);
|
||||
RollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();
|
||||
String fileNamePattern = ((SizeAndTimeBasedRollingPolicy) rollingPolicy).getFileNamePattern();
|
||||
assertThat(fileNamePattern).endsWith("my.log.%d{yyyyMMdd}.%i.gz");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Madhura Bhave
|
||||
* @author Vedran Pavic
|
||||
* @author Robert Thornton
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
@@ -537,6 +538,20 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRollingFileProperty() {
|
||||
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);
|
||||
File file = new File(tmpDir(), "my.log");
|
||||
LogFile logFile = getLogFile(file.getPath(), null);
|
||||
this.loggingSystem.initialize(loggingInitializationContext, null, logFile);
|
||||
this.logger.info("Hello world");
|
||||
assertThat(getLineWithText(file, "Hello world")).contains("INFO");
|
||||
assertThat(getRollingPolicy().getFileNamePattern()).isEqualTo(rollingFile);
|
||||
}
|
||||
|
||||
private static Logger getRootLogger() {
|
||||
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
|
||||
LoggerContext context = (LoggerContext) factory;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<configuration>
|
||||
<property name="ROLLING_FILE_NAME_PATTERN" value="my.log.%d{yyyyMMdd}.%i.gz"/>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml" />
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user