diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b19f5a8e8d..24234afe67 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -57,6 +57,8 @@ content into your application; rather pick only the properties that you need. logging.file=myapp.log logging.config= # location of config file (default classpath:logback.xml for logback) logging.level.*= # levels for loggers, e.g. "logging.level.org.springframework=DEBUG" (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF) + logging.pattern.console= # appender pattern for output to the console (only supported with the default logback setup) + logging.pattern.file= # appender pattern for output to the file (only supported with the default logback setup) # IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer]) spring.application.name= diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java index 6e587ed2f7..ca69e50a5b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java @@ -71,7 +71,7 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { loadConfiguration(initializationContext, config, logFile); return; } - loadDefaults(logFile); + loadDefaults(initializationContext, logFile); } /** @@ -129,9 +129,11 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { /** * Load sensible defaults for the logging system. + * @param initializationContext the logging initialization context * @param logFile the file to load or {@code null} if no log file is to be written */ - protected abstract void loadDefaults(LogFile logFile); + protected abstract void loadDefaults( + LoggingInitializationContext initializationContext, LogFile logFile); /** * Load a specific configuration. diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java index ff662ba5cb..fe172f0846 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -72,7 +72,8 @@ public class JavaLoggingSystem extends AbstractLoggingSystem { } @Override - protected void loadDefaults(LogFile logFile) { + protected void loadDefaults(LoggingInitializationContext initializationContext, + LogFile logFile) { if (logFile != null) { loadConfiguration(getPackagedConfigFile("logging-file.properties"), logFile); } diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java index 96af7c1a25..ab772113d6 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java @@ -70,7 +70,8 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem { } @Override - protected void loadDefaults(LogFile logFile) { + protected void loadDefaults(LoggingInitializationContext initializationContext, + LogFile logFile) { if (logFile != null) { loadConfiguration(getPackagedConfigFile("log4j-file.properties"), logFile); } diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index 57578be33a..72e1a448a9 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -136,7 +136,8 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem { } @Override - protected void loadDefaults(LogFile logFile) { + protected void loadDefaults(LoggingInitializationContext initializationContext, + LogFile logFile) { if (logFile != null) { loadConfiguration(getPackagedConfigFile("log4j2-file.xml"), logFile); } diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java b/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java index 24aeb38908..45f3d537b0 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -18,7 +18,12 @@ package org.springframework.boot.logging.logback; import java.nio.charset.Charset; +import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.logging.LogFile; +import org.springframework.boot.logging.LoggingInitializationContext; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertyResolver; +import org.springframework.core.env.PropertySourcesPropertyResolver; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; @@ -50,12 +55,23 @@ class DefaultLogbackConfiguration { private static final Charset UTF8 = Charset.forName("UTF-8"); + private final PropertyResolver patterns; + private final LogFile logFile; - public DefaultLogbackConfiguration(LogFile logFile) { + public 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); + } + return new RelaxedPropertyResolver(environment, "logging.pattern."); + } + @SuppressWarnings("unchecked") public void apply(LogbackConfigurator config) { synchronized (config.getConfigurationLock()) { @@ -99,8 +115,8 @@ class DefaultLogbackConfiguration { private Appender consoleAppender(LogbackConfigurator config) { ConsoleAppender appender = new ConsoleAppender(); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); - encoder.setPattern(OptionHelper.substVars(CONSOLE_LOG_PATTERN, - config.getContext())); + String logPattern = this.patterns.getProperty("console", CONSOLE_LOG_PATTERN); + encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); encoder.setCharset(UTF8); config.start(encoder); appender.setEncoder(encoder); @@ -112,7 +128,8 @@ class DefaultLogbackConfiguration { String logFile) { RollingFileAppender appender = new RollingFileAppender(); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); - encoder.setPattern(OptionHelper.substVars(FILE_LOG_PATTERN, config.getContext())); + String logPattern = this.patterns.getProperty("file", FILE_LOG_PATTERN); + encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); appender.setEncoder(encoder); config.start(encoder); diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java index c4ccc1e660..5fe4adf48f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java @@ -103,12 +103,14 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { } @Override - protected void loadDefaults(LogFile logFile) { + protected void loadDefaults(LoggingInitializationContext initializationContext, + LogFile logFile) { LoggerContext context = getLoggerContext(); context.stop(); context.reset(); LogbackConfigurator configurator = new LogbackConfigurator(context); - new DefaultLogbackConfiguration(logFile).apply(configurator); + new DefaultLogbackConfiguration(initializationContext, logFile) + .apply(configurator); } @Override @@ -210,4 +212,5 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { } return "unknown location"; } + } diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index 6fe9c1fe86..358aa7676d 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.logging.logback; import java.io.File; +import java.io.FileReader; import java.util.logging.Handler; import java.util.logging.LogManager; @@ -30,10 +31,12 @@ import org.slf4j.ILoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import org.slf4j.impl.StaticLoggerBinder; import org.springframework.boot.logging.AbstractLoggingSystemTests; +import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.test.OutputCapture; import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import ch.qos.logback.classic.Logger; @@ -87,6 +90,8 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { String output = this.output.toString().trim(); assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertFalse("Output not hidden:\n" + output, output.contains("Hidden")); + assertTrue("Wrong output pattern:\n" + output, + getLineWithText(output, "Hello world").contains("INFO")); assertFalse(new File(tmpDir() + "/spring.log").exists()); } @@ -98,9 +103,14 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { getLogFile(null, tmpDir())); this.logger.info("Hello world"); String output = this.output.toString().trim(); + File file = new File(tmpDir() + "/spring.log"); assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertFalse("Output not hidden:\n" + output, output.contains("Hidden")); - assertTrue(new File(tmpDir() + "/spring.log").exists()); + assertTrue("Wrong console output pattern:\n" + output, + getLineWithText(output, "Hello world").contains("INFO")); + assertTrue(file.exists()); + assertTrue("Wrong file output pattern:\n" + output, + getLineWithText(file, "Hello world").contains("INFO")); } @Test @@ -197,4 +207,49 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { return false; } + @Test + public void testConsolePatternProperty() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("logging.pattern.console", "%logger %msg"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext( + environment); + this.loggingSystem.initialize(loggingInitializationContext, null, null); + this.logger.info("Hello world"); + String output = this.output.toString().trim(); + assertFalse("Wrong output pattern:\n" + output, + getLineWithText(output, "Hello world").contains("INFO")); + } + + @Test + public void testFilePatternProperty() throws Exception { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("logging.pattern.file", "%logger %msg"); + LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext( + environment); + File file = new File(tmpDir(), "logback-test.log"); + LogFile logFile = getLogFile(file.getPath(), null); + this.loggingSystem.initialize(loggingInitializationContext, null, logFile); + this.logger.info("Hello world"); + String output = this.output.toString().trim(); + assertTrue("Wrong console output pattern:\n" + output, + getLineWithText(output, "Hello world").contains("INFO")); + assertFalse("Wrong file output pattern:\n" + output, + getLineWithText(file, "Hello world").contains("INFO")); + } + + private String getLineWithText(File file, String outputSearch) throws Exception { + return getLineWithText(FileCopyUtils.copyToString(new FileReader(file)), + outputSearch); + } + + private String getLineWithText(String output, String outputSearch) { + String[] lines = output.split("\\r?\\n"); + for (String line : lines) { + if (line.contains(outputSearch)) { + return line; + } + } + return null; + } + }