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
* `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.
......
[[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 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).
......
......@@ -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,12 @@ 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;
/**
......@@ -122,6 +129,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();
}
......
......@@ -140,7 +140,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));
......
......@@ -139,6 +139,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 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",
"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 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) {
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 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;
* @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 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() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
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