Commit f06c2503 authored by Stephane Nicoll's avatar Stephane Nicoll

Merge pull request #18151 from eddumelendez

* pr/18151:
  Polish "Add ROLLING_FILE_NAME_PATTERN for File Appender"
  Add ROLLING_FILE_NAME_PATTERN for File Appender

Closes gh-18151
parents 06f46baa a0d7d521
...@@ -1307,7 +1307,7 @@ The following files are provided under `org/springframework/boot/logging/logback ...@@ -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. * `defaults.xml` - Provides conversion rules, pattern properties and common logger configurations.
* `console-appender.xml` - Adds a `ConsoleAppender` using the `CONSOLE_LOG_PATTERN`. * `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. 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 ...@@ -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_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_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. * `$\{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. 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. See the `CONSOLE_LOG_PATTERN` in the `default.xml` configuration for an example.
......
[[spring-boot-reference-documentation]] [[spring-boot-reference-documentation]]
= 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 :docinfo: shared
The reference documentation consists of the following sections: 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 ...@@ -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`). | The format to use when rendering the log level (default `%5p`).
(Only supported with the default Logback setup.) (Only supported with the default Logback setup.)
| `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`
| `PID` | `PID`
| The current process ID (discovered if possible and when not already defined as an OS environment variable). | 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; ...@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
* @author Madhura Bhave * @author Madhura Bhave
* @author Vedran Pavic * @author Vedran Pavic
* @author Robert Thornton * @author Robert Thornton
* @author Eddú Meléndez
* @since 2.0.0 * @since 2.0.0
*/ */
public class LoggingSystemProperties { public class LoggingSystemProperties {
...@@ -95,6 +96,12 @@ public class LoggingSystemProperties { ...@@ -95,6 +96,12 @@ public class LoggingSystemProperties {
*/ */
public static final String LOG_DATEFORMAT_PATTERN = "LOG_DATEFORMAT_PATTERN"; 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; private final Environment environment;
/** /**
...@@ -122,6 +129,7 @@ public class LoggingSystemProperties { ...@@ -122,6 +129,7 @@ public class LoggingSystemProperties {
setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "file.total-size-cap"); setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "file.total-size-cap");
setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level"); setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level");
setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "pattern.dateformat"); setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "pattern.dateformat");
setSystemProperty(resolver, ROLLING_FILE_NAME_PATTERN, "pattern.rolling-file-name");
if (logFile != null) { if (logFile != null) {
logFile.applyToSystemProperties(); logFile.applyToSystemProperties();
} }
......
...@@ -140,7 +140,8 @@ class DefaultLogbackConfiguration { ...@@ -140,7 +140,8 @@ class DefaultLogbackConfiguration {
SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new SizeAndTimeBasedRollingPolicy<>(); SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new SizeAndTimeBasedRollingPolicy<>();
rollingPolicy.setCleanHistoryOnStart( rollingPolicy.setCleanHistoryOnStart(
this.patterns.getProperty("logging.file.clean-history-on-start", Boolean.class, false)); 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)); setMaxFileSize(rollingPolicy, getDataSize("logging.file.max-size", MAX_FILE_SIZE));
rollingPolicy rollingPolicy
.setMaxHistory(this.patterns.getProperty("logging.file.max-history", Integer.class, MAX_FILE_HISTORY)); .setMaxHistory(this.patterns.getProperty("logging.file.max-history", Integer.class, MAX_FILE_HISTORY));
......
...@@ -139,6 +139,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { ...@@ -139,6 +139,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}")); environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders( context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders(
"${logging.pattern.dateformat:${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}")); "${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); new DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);
context.setPackagingDataEnabled(true); context.setPackagingDataEnabled(true);
} }
......
...@@ -165,6 +165,13 @@ ...@@ -165,6 +165,13 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "%5p" "defaultValue": "%5p"
}, },
{
"name": "logging.pattern.rolling-file-name",
"type": "java.lang.String",
"description": "Pattern for rolled-over log file names. Supported only with the default Logback setup.",
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz"
},
{ {
"name": "logging.register-shutdown-hook", "name": "logging.register-shutdown-hook",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
......
...@@ -14,7 +14,7 @@ initialization performed by Boot ...@@ -14,7 +14,7 @@ initialization performed by Boot
<file>${LOG_FILE}</file> <file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<cleanHistoryOnStart>${LOG_FILE_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart> <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> <maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-7}</maxHistory> <maxHistory>${LOG_FILE_MAX_HISTORY:-7}</maxHistory>
<totalSizeCap>${LOG_FILE_TOTAL_SIZE_CAP:-0}</totalSizeCap> <totalSizeCap>${LOG_FILE_TOTAL_SIZE_CAP:-0}</totalSizeCap>
......
...@@ -83,6 +83,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; ...@@ -83,6 +83,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Ben Hale * @author Ben Hale
* @author Fahim Farook * @author Fahim Farook
* @author Eddú Meléndez
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@ClassPathExclusions("log4j*.jar") @ClassPathExclusions("log4j*.jar")
...@@ -134,6 +135,7 @@ class LoggingApplicationListenerTests { ...@@ -134,6 +135,7 @@ class LoggingApplicationListenerTests {
System.clearProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN); System.clearProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN);
System.clearProperty(LoggingSystemProperties.FILE_LOG_PATTERN); System.clearProperty(LoggingSystemProperties.FILE_LOG_PATTERN);
System.clearProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN); System.clearProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN);
System.clearProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN);
System.clearProperty(LoggingSystem.SYSTEM_PROPERTY); System.clearProperty(LoggingSystem.SYSTEM_PROPERTY);
if (this.context != null) { if (this.context != null) {
this.context.close(); this.context.close();
...@@ -479,7 +481,8 @@ class LoggingApplicationListenerTests { ...@@ -479,7 +481,8 @@ class LoggingApplicationListenerTests {
void systemPropertiesAreSetForLoggingConfiguration() { void systemPropertiesAreSetForLoggingConfiguration() {
addPropertiesToEnvironment(this.context, "logging.exception-conversion-word=conversion", addPropertiesToEnvironment(this.context, "logging.exception-conversion-word=conversion",
"logging.file.name=" + this.logFile, "logging.file.path=path", "logging.pattern.console=console", "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()); this.initializer.initialize(this.context.getEnvironment(), this.context.getClassLoader());
assertThat(System.getProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN)).isEqualTo("console"); assertThat(System.getProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN)).isEqualTo("console");
assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).isEqualTo("file"); assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).isEqualTo("file");
...@@ -487,6 +490,8 @@ class LoggingApplicationListenerTests { ...@@ -487,6 +490,8 @@ class LoggingApplicationListenerTests {
assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE)).isEqualTo(this.logFile.getAbsolutePath()); assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE)).isEqualTo(this.logFile.getAbsolutePath());
assertThat(System.getProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN)).isEqualTo("level"); assertThat(System.getProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN)).isEqualTo("level");
assertThat(System.getProperty(LoggingSystemProperties.LOG_PATH)).isEqualTo("path"); 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(); assertThat(System.getProperty(LoggingSystemProperties.PID_KEY)).isNotNull();
} }
......
...@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link LoggingSystemProperties}. * Tests for {@link LoggingSystemProperties}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Eddú Meléndez
*/ */
class LoggingSystemPropertiesTests { class LoggingSystemPropertiesTests {
...@@ -82,6 +83,15 @@ class LoggingSystemPropertiesTests { ...@@ -82,6 +83,15 @@ class LoggingSystemPropertiesTests {
assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).matches("[0-9]+"); assertThat(System.getProperty(LoggingSystemProperties.FILE_LOG_PATTERN)).matches("[0-9]+");
} }
@Test
void rollingFileNameIsSet() {
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) { private Environment environment(String key, Object value) {
StandardEnvironment environment = new StandardEnvironment(); StandardEnvironment environment = new StandardEnvironment();
environment.getPropertySources().addLast(new MapPropertySource("test", Collections.singletonMap(key, value))); environment.getPropertySources().addLast(new MapPropertySource("test", Collections.singletonMap(key, value)));
......
...@@ -27,6 +27,9 @@ import ch.qos.logback.core.ConsoleAppender; ...@@ -27,6 +27,9 @@ import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.encoder.Encoder; import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.joran.spi.JoranException; 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 org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -35,6 +38,7 @@ 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}. * Tests for default Logback configuration provided by {@code base.xml}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Eddú Meléndez
*/ */
class LogbackConfigurationTests { class LogbackConfigurationTests {
...@@ -64,4 +68,30 @@ class LogbackConfigurationTests { ...@@ -64,4 +68,30 @@ class LogbackConfigurationTests {
assertThat(((PatternLayoutEncoder) encoder).getPattern()).isEqualTo("bar"); assertThat(((PatternLayoutEncoder) encoder).getPattern()).isEqualTo("bar");
} }
@Test
void defaultRollingFileNamePattern() 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 customRollingFileNamePattern() 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; ...@@ -68,6 +68,7 @@ import static org.mockito.Mockito.verify;
* @author Madhura Bhave * @author Madhura Bhave
* @author Vedran Pavic * @author Vedran Pavic
* @author Robert Thornton * @author Robert Thornton
* @author Eddú Meléndez
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
...@@ -537,6 +538,20 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { ...@@ -537,6 +538,20 @@ 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);
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() { private static Logger getRootLogger() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
LoggerContext context = (LoggerContext) factory; LoggerContext context = (LoggerContext) factory;
......
<configuration>
<property name="ROLLING_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