diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index 24487cee38b..23ceb1d5ae5 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -39,6 +39,11 @@
javax.servlet-api
true
+
+ log4j
+ log4j
+ true
+
org.apache.tomcat.embed
tomcat-embed-core
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
new file mode 100644
index 00000000000..843cf2d749d
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012-2013 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.logging;
+
+/**
+ * Logging levels supported by a {@link LoggingSystem}.
+ *
+ * @author Phillip Webb
+ */
+public enum LogLevel {
+
+ TRACE, DEBUG, INFO, WARN, ERROR, FATAL
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
index 4fa579758f7..425b65151ae 100644
--- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
@@ -61,6 +61,13 @@ public abstract class LoggingSystem {
*/
public abstract void initialize(String configLocation);
+ /**
+ * Sets the logging level for a given logger.
+ * @param loggerName the name of the logger to set
+ * @param level the log level
+ */
+ public abstract void setLogLevel(String loggerName, LogLevel level);
+
/**
* Detect and return the logging system in use.
* @return The logging system
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 9bfc93cdecd..16d4b9ef2c3 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
@@ -16,11 +16,17 @@
package org.springframework.boot.logging.java;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.springframework.boot.logging.AbstractLoggingSystem;
+import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
+import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils;
@@ -32,12 +38,25 @@ import org.springframework.util.SystemPropertyUtils;
*/
public class JavaLoggingSystem extends AbstractLoggingSystem {
+ private static final Map LEVELS;
+ static {
+ Map levels = new HashMap();
+ levels.put(LogLevel.TRACE, Level.FINEST);
+ levels.put(LogLevel.DEBUG, Level.FINE);
+ levels.put(LogLevel.INFO, Level.INFO);
+ levels.put(LogLevel.WARN, Level.WARNING);
+ levels.put(LogLevel.ERROR, Level.SEVERE);
+ levels.put(LogLevel.FATAL, Level.SEVERE);
+ LEVELS = Collections.unmodifiableMap(levels);
+ }
+
public JavaLoggingSystem(ClassLoader classLoader) {
super(classLoader, "logging.properties");
}
@Override
public void initialize(String configLocation) {
+ Assert.notNull(configLocation, "ConfigLocation must not be null");
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
try {
LogManager.getLogManager().readConfiguration(
@@ -49,4 +68,10 @@ public class JavaLoggingSystem extends AbstractLoggingSystem {
}
}
+ @Override
+ public void setLogLevel(String loggerName, LogLevel level) {
+ Assert.notNull(level, "Level must not be null");
+ Logger logger = Logger.getLogger(loggerName == null ? "" : loggerName);
+ logger.setLevel(LEVELS.get(level));
+ }
}
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 b78b314e455..da46a2b212b 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
@@ -16,9 +16,19 @@
package org.springframework.boot.logging.log4j;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
import org.springframework.boot.logging.AbstractLoggingSystem;
+import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
+import org.springframework.util.Assert;
import org.springframework.util.Log4jConfigurer;
+import org.springframework.util.StringUtils;
/**
* {@link LoggingSystem} for for log4j.
@@ -28,12 +38,25 @@ import org.springframework.util.Log4jConfigurer;
*/
public class Log4JLoggingSystem extends AbstractLoggingSystem {
+ private static final Map LEVELS;
+ static {
+ Map levels = new HashMap();
+ levels.put(LogLevel.TRACE, Level.TRACE);
+ levels.put(LogLevel.DEBUG, Level.DEBUG);
+ levels.put(LogLevel.INFO, Level.INFO);
+ levels.put(LogLevel.WARN, Level.WARN);
+ levels.put(LogLevel.ERROR, Level.ERROR);
+ levels.put(LogLevel.FATAL, Level.ERROR);
+ LEVELS = Collections.unmodifiableMap(levels);
+ }
+
public Log4JLoggingSystem(ClassLoader classLoader) {
super(classLoader, "log4j.xml", "log4j.properties");
}
@Override
public void initialize(String configLocation) {
+ Assert.notNull(configLocation, "ConfigLocation must not be null");
try {
Log4jConfigurer.initLogging(configLocation);
}
@@ -43,4 +66,11 @@ public class Log4JLoggingSystem extends AbstractLoggingSystem {
}
}
+ @Override
+ public void setLogLevel(String loggerName, LogLevel level) {
+ Logger logger = (StringUtils.hasLength(loggerName) ? LogManager
+ .getLogger(loggerName) : LogManager.getRootLogger());
+ logger.setLevel(LEVELS.get(level));
+ }
+
}
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 9c7e83b2eba..d45448fcc91 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
@@ -17,17 +17,24 @@
package org.springframework.boot.logging.logback;
import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.AbstractLoggingSystem;
+import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
+import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;
+import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.util.ContextInitializer;
@@ -39,6 +46,18 @@ import ch.qos.logback.classic.util.ContextInitializer;
*/
public class LogbackLoggingSystem extends AbstractLoggingSystem {
+ private static final Map LEVELS;
+ static {
+ Map levels = new HashMap();
+ levels.put(LogLevel.TRACE, Level.TRACE);
+ levels.put(LogLevel.DEBUG, Level.DEBUG);
+ levels.put(LogLevel.INFO, Level.INFO);
+ levels.put(LogLevel.WARN, Level.WARN);
+ levels.put(LogLevel.ERROR, Level.ERROR);
+ levels.put(LogLevel.FATAL, Level.ERROR);
+ LEVELS = Collections.unmodifiableMap(levels);
+ }
+
public LogbackLoggingSystem(ClassLoader classLoader) {
super(classLoader, "logback.xml");
}
@@ -54,6 +73,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem {
@Override
public void initialize(String configLocation) {
+ Assert.notNull(configLocation, "ConfigLocation must not be null");
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Assert.isInstanceOf(ILoggerFactory.class, factory);
@@ -69,4 +89,13 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem {
}
}
+ @Override
+ public void setLogLevel(String loggerName, LogLevel level) {
+ ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
+ Logger logger = factory
+ .getLogger(StringUtils.isEmpty(loggerName) ? Logger.ROOT_LOGGER_NAME
+ : loggerName);
+ ((ch.qos.logback.classic.Logger) logger).setLevel(LEVELS.get(level));
+ }
+
}
diff --git a/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging.properties b/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging.properties
index 77e2072e34e..ae8eb52a3d5 100644
--- a/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging.properties
+++ b/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging.properties
@@ -2,10 +2,11 @@ handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level = INFO
# File Logging
-java.util.logging.FileHandler.pattern = %t/service.log
+java.util.logging.FileHandler.pattern = %t/spring.log
java.util.logging.FileHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
-java.util.logging.FileHandler.level = INFO
+java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10
java.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
+java.util.logging.ConsoleHandler.level = ALL
diff --git a/spring-boot/src/main/resources/org/springframework/boot/logging/log4j/log4j.properties b/spring-boot/src/main/resources/org/springframework/boot/logging/log4j/log4j.properties
index 6442a1edf7e..7102d33f941 100644
--- a/spring-boot/src/main/resources/org/springframework/boot/logging/log4j/log4j.properties
+++ b/spring-boot/src/main/resources/org/springframework/boot/logging/log4j/log4j.properties
@@ -1,9 +1,8 @@
log4j.rootCategory=INFO, CONSOLE, FILE
PID=????
-catalina.base=/tmp
-LOG_PATH=${catalina.base}/logs
-LOG_FILE=${LOG_PATH}/service.log
+LOG_PATH=/tmp
+LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggerSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggerSystemTests.java
index d5a10edb7d1..100816a1591 100644
--- a/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggerSystemTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggerSystemTests.java
@@ -19,15 +19,17 @@ package org.springframework.boot.logging.java;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
-import java.util.logging.LogManager;
import org.apache.commons.logging.impl.Jdk14Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.boot.logging.java.JavaLoggingSystem;
+import org.springframework.boot.logging.LogLevel;
import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
@@ -48,8 +50,6 @@ public class JavaLoggerSystemTests {
@Before
public void init() throws SecurityException, IOException {
- LogManager.getLogManager().readConfiguration(
- getClass().getResourceAsStream("/logging.properties"));
this.logger = new Jdk14Logger(getClass().getName());
this.savedOutput = System.err;
this.output = new ByteArrayOutputStream();
@@ -71,6 +71,7 @@ public class JavaLoggerSystemTests {
@Test
public void testCustomFormatter() throws Exception {
+ this.loggingSystem.initialize();
this.logger.info("Hello world");
String output = getOutput().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
@@ -108,4 +109,14 @@ public class JavaLoggerSystemTests {
this.loggingSystem.initialize(null);
}
+ @Test
+ public void setLevel() throws Exception {
+ this.loggingSystem.initialize();
+ this.logger.debug("Hello");
+ this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
+ this.logger.debug("Hello");
+ assertThat(StringUtils.countOccurrencesOf(this.output.toString(), "Hello"),
+ equalTo(1));
+ }
+
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java
new file mode 100644
index 00000000000..b39771b607f
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012-2013 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.logging.log4j;
+
+import org.apache.commons.logging.impl.Log4JLogger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.springframework.boot.OutputCapture;
+import org.springframework.boot.logging.LogLevel;
+import org.springframework.util.StringUtils;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link Log4JLoggingSystem}.
+ *
+ * @author Phillip Webb
+ */
+public class Log4JLoggingSystemTests {
+
+ @Rule
+ public OutputCapture output = new OutputCapture();
+
+ private Log4JLoggingSystem loggingSystem = new Log4JLoggingSystem(getClass()
+ .getClassLoader());
+
+ private Log4JLogger logger;
+
+ @Before
+ public void setup() {
+ this.logger = new Log4JLogger(getClass().getName());
+ }
+
+ @After
+ public void clear() {
+ System.clearProperty("LOG_FILE");
+ System.clearProperty("LOG_PATH");
+ System.clearProperty("PID");
+ }
+
+ @Test
+ public void testNonDefaultConfigLocation() throws Exception {
+ this.loggingSystem.initialize("classpath:log4j-nondefault.properties");
+ this.logger.info("Hello world");
+ String output = this.output.toString().trim();
+ assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
+ assertTrue("Wrong output:\n" + output, output.contains("/tmp/spring.log"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testNonexistentConfigLocation() throws Exception {
+ this.loggingSystem.initialize("classpath:log4j-nonexistent.xml");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullConfigLocation() throws Exception {
+ this.loggingSystem.initialize(null);
+ }
+
+ @Test
+ public void setLevel() throws Exception {
+ this.loggingSystem.initialize();
+ this.logger.debug("Hello");
+ this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
+ this.logger.debug("Hello");
+ assertThat(StringUtils.countOccurrencesOf(this.output.toString(), "Hello"),
+ equalTo(1));
+ }
+
+}
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 051555aaf83..812567cf67d 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,12 +17,17 @@
package org.springframework.boot.logging.logback;
import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.SLF4JLogFactory;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.OutputCapture;
+import org.springframework.boot.logging.LogLevel;
+import org.springframework.util.StringUtils;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
@@ -33,11 +38,18 @@ import static org.junit.Assert.assertTrue;
public class LogbackLoggingSystemTests {
@Rule
- public OutputCapture outputCapture = new OutputCapture();
+ public OutputCapture output = new OutputCapture();
private LogbackLoggingSystem loggingSystem = new LogbackLoggingSystem(getClass()
.getClassLoader());
+ private Log logger;
+
+ @Before
+ public void setup() {
+ this.logger = new SLF4JLogFactory().getInstance(getClass().getName());
+ }
+
@After
public void clear() {
System.clearProperty("LOG_FILE");
@@ -46,13 +58,12 @@ public class LogbackLoggingSystemTests {
}
@Test
- public void testDefaultConfigLocation() throws Exception {
+ public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.initialize("classpath:logback-nondefault.xml");
- Log logger = LogFactory.getLog(LogbackLoggingSystemTests.class);
- logger.info("Hello world");
- String output = this.outputCapture.toString().trim();
+ this.logger.info("Hello world");
+ String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
- assertTrue("Wrong output:\n" + output, output.startsWith("/tmp/spring.log"));
+ assertTrue("Wrong output:\n" + output, output.contains("/tmp/spring.log"));
}
@Test(expected = IllegalStateException.class)
@@ -65,4 +76,14 @@ public class LogbackLoggingSystemTests {
this.loggingSystem.initialize(null);
}
+ @Test
+ public void setLevel() throws Exception {
+ this.loggingSystem.initialize();
+ this.logger.debug("Hello");
+ this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
+ this.logger.debug("Hello");
+ assertThat(StringUtils.countOccurrencesOf(this.output.toString(), "Hello"),
+ equalTo(1));
+ }
+
}
diff --git a/spring-boot/src/test/resources/log4j-nondefault.properties b/spring-boot/src/test/resources/log4j-nondefault.properties
new file mode 100644
index 00000000000..544139af915
--- /dev/null
+++ b/spring-boot/src/test/resources/log4j-nondefault.properties
@@ -0,0 +1,12 @@
+log4j.reset=true
+log4j.rootCategory=INFO, CONSOLE
+
+PID=????
+LOG_PATH=/tmp
+LOG_FILE=${LOG_PATH}/spring.log
+LOG_PATTERN=${LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n
+
+# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=${LOG_PATTERN}
diff --git a/spring-boot/src/test/resources/logging.properties b/spring-boot/src/test/resources/logging.properties
deleted file mode 100644
index 187c49109c0..00000000000
--- a/spring-boot/src/test/resources/logging.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-handlers= java.util.logging.ConsoleHandler
-.level= INFO
-java.util.logging.ConsoleHandler.level = INFO
-java.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter