From 4a3810a0f1b25a4916753655c6cb791daaa34f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 5 Sep 2019 21:36:28 -0500 Subject: [PATCH] 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 --- .../src/main/asciidoc/howto.adoc | 3 +- .../src/main/asciidoc/index.htmladoc | 2 +- .../main/asciidoc/spring-boot-features.adoc | 5 ++++ .../boot/logging/LoggingSystemProperties.java | 7 +++++ .../logback/DefaultLogbackConfiguration.java | 4 ++- .../logging/logback/LogbackLoggingSystem.java | 3 ++ ...itional-spring-configuration-metadata.json | 7 +++++ .../boot/logging/logback/file-appender.xml | 2 +- .../LoggingApplicationListenerTests.java | 7 ++++- .../logging/LoggingSystemPropertiesTests.java | 10 +++++++ .../logback/LogbackConfigurationTests.java | 30 +++++++++++++++++++ .../logback/LogbackLoggingSystemTests.java | 15 ++++++++++ ...-file-log-pattern-with-fileNamePattern.xml | 4 +++ 13 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index a1ebccc25c..d100f6ae02 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -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. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/index.htmladoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/index.htmladoc index 87266a1ff0..d7d9836fe7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/index.htmladoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/index.htmladoc @@ -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: diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 81f44749fc..a2588d2ee4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -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). diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java index 54fcc6ee5a..e8e2d818cd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java @@ -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(); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java index 0d14fbdadc..0e2180a178 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java @@ -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 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)); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java index aaa8db2e7d..658e2a0aea 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java @@ -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); } diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 52158c6dec..bd4c7a4e70 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -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", diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml index 05bae318e3..8275d3d8a1 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml @@ -14,7 +14,7 @@ initialization performed by Boot ${LOG_FILE} ${LOG_FILE_CLEAN_HISTORY_ON_START:-false} - ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz + ${ROLLING_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} ${LOG_FILE_MAX_SIZE:-10MB} ${LOG_FILE_MAX_HISTORY:-7} ${LOG_FILE_TOTAL_SIZE_CAP:-0} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java index 603c599efb..9701681107 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java @@ -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(); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java index 0297914bbe..3d8d0ef5bd 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java @@ -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))); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationTests.java index f8b3d08122..a80cc8d833 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationTests.java @@ -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 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 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"); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index 14f71ae79e..ffd49315c3 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -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; diff --git a/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml b/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml new file mode 100644 index 0000000000..2539b8de32 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/custom-file-log-pattern-with-fileNamePattern.xml @@ -0,0 +1,4 @@ + + + +