diff --git a/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java b/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java index e795fcd71d..d18d7dd36e 100644 --- a/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java +++ b/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java @@ -62,9 +62,12 @@ public class JarCommandIT { @Test public void jarCreationWithGrabResolver() throws Exception { File jar = new File("target/test-app.jar"); - Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(), + Invocation invocation = this.cli.invoke("run", jar.getAbsolutePath(), "bad.groovy"); invocation.await(); + assertThat(invocation.getErrorOutput(), equalTo("")); + invocation = this.cli.invoke("jar", jar.getAbsolutePath(), "bad.groovy"); + invocation.await(); assertEquals(invocation.getErrorOutput(), 0, invocation.getErrorOutput().length()); assertTrue(jar.exists()); 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 5be479bfb7..1ab5ee145e 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -43,7 +43,8 @@ content into your application; rather pick only the properties that you need. # LOGGING logging.path=/var/logs logging.file=myapp.log - logging.config= + 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) # IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer]) spring.application.name= diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index cd9508c0e7..727a87054e 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -833,10 +833,6 @@ Check out {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`W [[howto-logging]] == Logging - - -[[howto-configure-logback-for-loggin]] -=== Configure Logback for logging Spring Boot has no mandatory logging dependence, except for the `commons-logging` API, of which there are many implementations to choose from. To use http://logback.qos.ch[Logback] you need to include it, and some bindings for `commons-logging` on the classpath. The @@ -854,10 +850,32 @@ For example, using Maven: ---- Spring Boot has a `LoggingSystem` abstraction that attempts to configure logging based on -the content of the classpath. If Logback is available it is the first choice. So if you -put a `logback.xml` in the root of your classpath it will be picked up from there. Spring -Boot provides a default base configuration that you can include if you just want to set -levels, e.g. +the content of the classpath. If Logback is available it is the first choice. + +If the only change you need to make to logging is to set the levels of various loggers +then you can do that in `application.properties` using the "logging.level" prefix, e.g. + +[source,properties,indent=0,subs="verbatim,quotes,attributes"] +---- +logging.level.org.springframework.web: DEBUG +logging.level.org.hibernate: ERROR +---- + +You can also set the location of a file to log to (in addition to the console) using +"logging.file". + +To configure the more fine grained settings of a logging system you need to use the native configuration +format supported by the `LoggingSystem` in question. By default Spring Boot picks up the native +configuration from its default location for the system (e.g. `classpath:/logback.xml` for Logback), but +you can set the location of the config file using the "logging.config" property. + + +[[howto-configure-logback-for-loggin]] +=== Configure Logback for logging +If you put a `logback.xml` in the root of your classpath it will be +picked up from there. Spring Boot provides a default base +configuration that you can include if you just want to set levels, +e.g. [source,xml,indent=0,subs="verbatim,quotes,attributes"] ---- diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index a4237f05c5..061ee6f4b6 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -724,6 +724,18 @@ using a `logging.file` property. As with console output, `ERROR`, `WARN` and `INFO` level messages are logged by default. +[[boot-features-custom-log-levels]] +=== Log Levels + +All the supported logging systems can have the logger levels set in the Spring `Environment` +(so for example in `application.properties`) using "logging.level.*=LEVEL" where "LEVEL" is one of +TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF. Example `application.properties`: + +[source,properties,indent=0,subs="verbatim,quotes,attributes"] +---- +logging.level.org.springframework.web: DEBUG +logging.level.org.hibernate: ERROR +---- [[boot-features-custom-log-configuration]] diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties index 87a55bc89d..49672f79a1 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties @@ -1,4 +1,5 @@ logging.file: /tmp/logs/app.log +logging.level.org.springframework.security: INFO management.address: 127.0.0.1 endpoints.shutdown.enabled: true server.tomcat.basedir: target/tomcat diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/logback.xml deleted file mode 100644 index d1900162b3..0000000000 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/spring-boot-samples/spring-boot-sample-integration/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-integration/src/main/resources/application.properties index 1fd64e4d13..92dc00252b 100644 --- a/spring-boot-samples/spring-boot-sample-integration/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-integration/src/main/resources/application.properties @@ -1,3 +1,4 @@ logging.file: /tmp/logs/app.log +logging.level.org.springframework.integration.file: DEBUG service.greeting: Hello debug: true \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-integration/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-integration/src/main/resources/logback.xml deleted file mode 100644 index 178cf3322a..0000000000 --- a/spring-boot-samples/spring-boot-sample-integration/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml deleted file mode 100644 index 178cf3322a..0000000000 --- a/spring-boot-samples/spring-boot-sample-parent-context/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/application.properties index f1e67dc5f9..14bc33fa92 100644 --- a/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/application.properties @@ -1,2 +1,3 @@ # Allow templates to be reloaded at dev time spring.groovy.template.cache: false +logging.level.org.springframework.web: INFO \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/logback.xml deleted file mode 100644 index 38ed210e2f..0000000000 --- a/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/logback.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/application.properties index cce37b52b5..c19741f86f 100644 --- a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/application.properties @@ -1 +1,2 @@ spring.thymeleaf.cache: false +logging.level.org.springframework.security: INFO \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/logback.xml deleted file mode 100644 index 92ea748a3e..0000000000 --- a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/application.properties index 521ecc4286..f6fecdb8b4 100644 --- a/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/application.properties @@ -1,5 +1,5 @@ spring.thymeleaf.cache: false -debug: true security.basic.enabled: false # demo only: -security.user.password: password \ No newline at end of file +security.user.password: password +logging.level.org.springframework.security: INFO \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/logback.xml b/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/logback.xml deleted file mode 100644 index 6173a50684..0000000000 --- a/spring-boot-samples/spring-boot-sample-web-secure/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java b/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java index 843cf2d749..1df44cbd30 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java @@ -23,6 +23,6 @@ package org.springframework.boot.logging; */ public enum LogLevel { - TRACE, DEBUG, INFO, WARN, ERROR, FATAL + TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF } diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java index 6b92646461..b2c84c9345 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java @@ -19,11 +19,13 @@ package org.springframework.boot.logging; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.ApplicationPid; import org.springframework.boot.SpringApplication; +import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationEvent; @@ -180,7 +182,6 @@ public class LoggingApplicationListener implements SmartApplicationListener { try { ResourceUtils.getURL(value).openStream().close(); system.initialize(value); - return; } catch (Exception ex) { // Swallow exception and continue @@ -188,10 +189,31 @@ public class LoggingApplicationListener implements SmartApplicationListener { this.logger.warn("Logging environment value '" + value + "' cannot be opened and will be ignored"); } + else { - system.initialize(); - if (this.springBootLogging != null) { - initializeLogLevel(system, this.springBootLogging); + system.initialize(); + if (this.springBootLogging != null) { + initializeLogLevel(system, this.springBootLogging); + } + + } + + setLogLevels(system, environment); + + } + + public void setLogLevels(LoggingSystem system, Environment environment) { + Map levels = new RelaxedPropertyResolver(environment) + .getSubProperties("logging.level."); + for (Entry entry : levels.entrySet()) { + try { + LogLevel level = LogLevel.valueOf(entry.getValue().toString()); + system.setLogLevel(entry.getKey(), level); + } + catch (RuntimeException e) { + this.logger.error("Cannot set level: " + entry.getValue() + " for '" + + entry.getKey() + "'"); + } } } 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 4186686670..d9a9b7629f 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 @@ -47,6 +47,7 @@ public class JavaLoggingSystem extends AbstractLoggingSystem { levels.put(LogLevel.WARN, Level.WARNING); levels.put(LogLevel.ERROR, Level.SEVERE); levels.put(LogLevel.FATAL, Level.SEVERE); + levels.put(LogLevel.OFF, Level.OFF); LEVELS = Collections.unmodifiableMap(levels); } 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 b054ce8651..256464279e 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 @@ -49,6 +49,7 @@ public class Log4JLoggingSystem extends AbstractLoggingSystem { levels.put(LogLevel.WARN, Level.WARN); levels.put(LogLevel.ERROR, Level.ERROR); levels.put(LogLevel.FATAL, Level.ERROR); + levels.put(LogLevel.OFF, Level.OFF); LEVELS = Collections.unmodifiableMap(levels); } 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 3808ab226e..027002aac6 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 @@ -55,6 +55,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem { levels.put(LogLevel.WARN, Level.WARN); levels.put(LogLevel.ERROR, Level.ERROR); levels.put(LogLevel.FATAL, Level.ERROR); + levels.put(LogLevel.OFF, Level.OFF); LEVELS = Collections.unmodifiableMap(levels); } diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java index 38be0ecf5c..35cff97a05 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java @@ -187,6 +187,42 @@ public class LoggingApplicationListenerTests { assertThat(this.outputCapture.toString(), containsString("testattrace")); } + @Test + public void parseLevels() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "logging.level.org.springframework.boot=TRACE"); + this.initializer.initialize(this.context.getEnvironment(), + this.context.getClassLoader()); + this.logger.debug("testatdebug"); + this.logger.trace("testattrace"); + assertThat(this.outputCapture.toString(), containsString("testatdebug")); + assertThat(this.outputCapture.toString(), containsString("testattrace")); + } + + @Test + public void parseLevelsFails() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "logging.level.org.springframework.boot=GARBAGE"); + this.initializer.initialize(this.context.getEnvironment(), + this.context.getClassLoader()); + this.logger.debug("testatdebug"); + assertThat(this.outputCapture.toString(), not(containsString("testatdebug"))); + assertThat(this.outputCapture.toString(), + containsString("Cannot set level: GARBAGE")); + } + + @Test + public void parseLevelsNone() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "logging.level.org.springframework.boot=OFF"); + this.initializer.initialize(this.context.getEnvironment(), + this.context.getClassLoader()); + this.logger.debug("testatdebug"); + this.logger.fatal("testatfatal"); + assertThat(this.outputCapture.toString(), not(containsString("testatdebug"))); + assertThat(this.outputCapture.toString(), not(containsString("testatfatal"))); + } + @Test public void parseArgsDisabled() throws Exception { this.initializer.setParseArgs(false);