Support programmatic setting of log levels
Provide a common way to programmatically set log levels regardless of the underlying log implementation. Issue: #55202588
This commit is contained in:
parent
5446a20a90
commit
5b77028f04
|
@ -39,6 +39,11 @@
|
|||
<artifactId>javax.servlet-api</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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<LogLevel, Level> LEVELS;
|
||||
static {
|
||||
Map<LogLevel, Level> levels = new HashMap<LogLevel, Level>();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <a href="http://logging.apache.org/log4j">log4j</a>.
|
||||
|
@ -28,12 +38,25 @@ import org.springframework.util.Log4jConfigurer;
|
|||
*/
|
||||
public class Log4JLoggingSystem extends AbstractLoggingSystem {
|
||||
|
||||
private static final Map<LogLevel, Level> LEVELS;
|
||||
static {
|
||||
Map<LogLevel, Level> levels = new HashMap<LogLevel, Level>();
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<LogLevel, Level> LEVELS;
|
||||
static {
|
||||
Map<LogLevel, Level> levels = new HashMap<LogLevel, Level>();
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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}
|
|
@ -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
|
Loading…
Reference in New Issue