Commit cf24af0b authored by Phillip Webb's avatar Phillip Webb

Rework logging to prevent double initialization

Prior to this commit LoggingSystem initialization would happen multiple
times. Once to configure "quiet" logging, and again to configure correct
settings once the Application was initialized. This could cause problems
if `logging.groovy` logback files were used.

The logging system is now only initialized once (when possible) by
following these steps:

- Standard logging initialization occurs via the actual logging
  implementation used (e.g. logback will load a logback.xml file if it
  exists)
- beforeInitization() is called to prevent early log output.
  Implementations now either use a Filter or simply set the root logging
  level.
- initialize() is called with an optional log configuration file (e.g
  a custom logback.xml location) and an optional log output file (the
  default is null indicating console only output).

The initialize() method will attempt to prevent double initialization
by checking if a standard configuration file exists. Double
initialization now only occurs in the following situations:

- The user has a standard configuration file (e.g. classpath:logback.xml)
  but also specifies a logging.config property. Double initialization is
  required since the specified configuration file supersedes the default.
- The user has a standard configuration file (e.g. classpath:logback.xml)
  and specifies a logging.file property. Double initialization is
  required since the standard configuration may use a ${LOG_FILE}
  reference.

In addition this commit removes the `logging.console` option and now
assumes that logging either occurs only to console or to both the
console and a file. This restriction helps simplify the LoggingSystem
implementations. If file only logging is required a custom logback.xml
can be used.

Fixes gh-1091
See gh-1612, gh-1770
parent d17b7c81
...@@ -111,7 +111,7 @@ public class EndpointMBeanExporter extends MBeanExporter implements SmartLifecyc ...@@ -111,7 +111,7 @@ public class EndpointMBeanExporter extends MBeanExporter implements SmartLifecyc
this.beanFactory = (ListableBeanFactory) beanFactory; this.beanFactory = (ListableBeanFactory) beanFactory;
} }
else { else {
logger.info("EndpointMBeanExporter not running in a ListableBeanFactory: " logger.warn("EndpointMBeanExporter not running in a ListableBeanFactory: "
+ "autodetection of Endpoints not available."); + "autodetection of Endpoints not available.");
} }
} }
......
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<!-- logger name="org.springframework.web" level="DEBUG"/-->
<!-- logger name="org.springframework.jdbc" level="DEBUG"/-->
<!-- logger name="org.springframework.jms" level="DEBUG"/-->
</configuration>
...@@ -26,10 +26,10 @@ import org.springframework.context.annotation.Configuration; ...@@ -26,10 +26,10 @@ import org.springframework.context.annotation.Configuration;
@EnableAutoConfiguration @EnableAutoConfiguration
@EnableConfigurationProperties @EnableConfigurationProperties
@ComponentScan @ComponentScan
public class SampleActuatorApplication { public class SampleActuatorLog4JApplication {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorApplication.class, args); SpringApplication.run(SampleActuatorLog4JApplication.class, args);
} }
} }
...@@ -38,7 +38,7 @@ import static org.junit.Assert.assertEquals; ...@@ -38,7 +38,7 @@ import static org.junit.Assert.assertEquals;
* @author Dave Syer * @author Dave Syer
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleActuatorApplication.class) @SpringApplicationConfiguration(classes = SampleActuatorLog4JApplication.class)
@WebAppConfiguration @WebAppConfiguration
@IntegrationTest("server.port=0") @IntegrationTest("server.port=0")
@DirtiesContext @DirtiesContext
......
...@@ -26,10 +26,10 @@ import org.springframework.context.annotation.Configuration; ...@@ -26,10 +26,10 @@ import org.springframework.context.annotation.Configuration;
@EnableAutoConfiguration @EnableAutoConfiguration
@EnableConfigurationProperties @EnableConfigurationProperties
@ComponentScan @ComponentScan
public class SampleActuatorApplication { public class SampleActuatorLog4J2Application {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorApplication.class, args); SpringApplication.run(SampleActuatorLog4J2Application.class, args);
} }
} }
...@@ -38,7 +38,7 @@ import static org.junit.Assert.assertEquals; ...@@ -38,7 +38,7 @@ import static org.junit.Assert.assertEquals;
* @author Dave Syer * @author Dave Syer
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleActuatorApplication.class) @SpringApplicationConfiguration(classes = SampleActuatorLog4J2Application.class)
@WebAppConfiguration @WebAppConfiguration
@IntegrationTest("server.port=0") @IntegrationTest("server.port=0")
@DirtiesContext @DirtiesContext
......
...@@ -282,13 +282,12 @@ public class SpringApplication { ...@@ -282,13 +282,12 @@ public class SpringApplication {
// Create and configure the environment // Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment(); ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, args); configureEnvironment(environment, args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}
if (this.showBanner) { if (this.showBanner) {
printBanner(environment); printBanner(environment);
} }
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}
// Create, load, refresh and run the ApplicationContext // Create, load, refresh and run the ApplicationContext
context = createApplicationContext(); context = createApplicationContext();
......
...@@ -19,6 +19,7 @@ package org.springframework.boot.logging; ...@@ -19,6 +19,7 @@ package org.springframework.boot.logging;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;
/** /**
* Abstract base class for {@link LoggingSystem} implementations. * Abstract base class for {@link LoggingSystem} implementations.
...@@ -30,50 +31,70 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { ...@@ -30,50 +31,70 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
private final ClassLoader classLoader; private final ClassLoader classLoader;
private final String[] paths;
private boolean fileOutput;
private boolean consoleOutput;
public AbstractLoggingSystem(ClassLoader classLoader) { public AbstractLoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true);
}
public AbstractLoggingSystem(ClassLoader classLoader, boolean fileOutput,
boolean consoleOutput) {
this.classLoader = classLoader; this.classLoader = classLoader;
this.fileOutput = fileOutput;
this.consoleOutput = consoleOutput;
this.paths = getLogFileNames();
}
protected abstract String[] getLogFileNames();
protected final ClassLoader getClassLoader() {
return this.classLoader;
} }
@Override @Override
public void beforeInitialize() { public void beforeInitialize() {
initializeWithSensibleDefaults();
} }
@Override @Override
public void initialize() { public void initialize(String configLocation, String logFile) {
for (String path : this.paths) { if (StringUtils.hasLength(configLocation)) {
ClassPathResource resource = new ClassPathResource(path, this.classLoader); // Load a specific configuration
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
loadConfiguration(configLocation, logFile);
}
else {
String selfInitializationConfig = getSelfInitializationConfig();
if (selfInitializationConfig == null) {
// No self initialization has occurred, use defaults
loadDefaults(logFile);
}
else if (StringUtils.hasLength(logFile)) {
// Self initialization has occurred but the file has changed, reload
loadConfiguration(selfInitializationConfig, logFile);
}
}
}
/**
* Return any self initialization config that has been applied. By default this method
* checks {@link #getStandardConfigLocations()} and assumes that any file that exists
* will have been applied.
*/
protected String getSelfInitializationConfig() {
for (String location : getStandardConfigLocations()) {
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) { if (resource.exists()) {
initialize("classpath:" + path); return "classpath:" + location;
return;
} }
} }
// Fallback to the non-prefixed value taking into account file and console preferences return null;
initialize(getPackagedConfigFile(addChannels(this.paths[this.paths.length - 1])));
} }
protected void initializeWithSensibleDefaults() { /**
initialize(getPackagedConfigFile("basic-" + this.paths[this.paths.length - 1])); * Return the standard config locations for this system.
* @see #getSelfInitializationConfig()
*/
protected abstract String[] getStandardConfigLocations();
/**
* Load sensible defaults for the logging system.
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadDefaults(String logFile);
/**
* Load a specific configuration.
* @param location the location of the configuration to load (never {@code null})
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadConfiguration(String location, String logFile);
protected final ClassLoader getClassLoader() {
return this.classLoader;
} }
protected final String getPackagedConfigFile(String fileName) { protected final String getPackagedConfigFile(String fileName) {
...@@ -84,14 +105,4 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { ...@@ -84,14 +105,4 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
return defaultPath; return defaultPath;
} }
private String addChannels(String fileName) {
String extension = "." + StringUtils.getFilenameExtension(fileName);
return fileName.replace(extension, getChannel() + extension);
}
private String getChannel() {
return (fileOutput && consoleOutput) ? "-file-console" : (fileOutput ? "-file"
: (consoleOutput ? "" : "-none"));
}
} }
...@@ -33,35 +33,32 @@ public abstract class LoggingSystem { ...@@ -33,35 +33,32 @@ public abstract class LoggingSystem {
private static final Map<String, String> SYSTEMS; private static final Map<String, String> SYSTEMS;
static { static {
Map<String, String> systems = new LinkedHashMap<String, String>(); Map<String, String> systems = new LinkedHashMap<String, String>();
String pkg = LoggingSystem.class.getPackage().getName(); systems.put("ch.qos.logback.core.Appender",
systems.put("ch.qos.logback.core.Appender", pkg + ".logback.LogbackLoggingSystem"); "org.springframework.boot.logging.logback.LogbackLoggingSystem");
systems.put("org.apache.log4j.PropertyConfigurator", pkg systems.put("org.apache.log4j.PropertyConfigurator",
+ ".log4j.Log4JLoggingSystem"); "org.springframework.boot.logging.log4j.Log4JLoggingSystem");
systems.put("org.apache.logging.log4j.LogManager", pkg systems.put("org.apache.logging.log4j.LogManager",
+ ".log4j2.Log4J2LoggingSystem"); "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
systems.put("java.util.logging.LogManager", pkg + ".java.JavaLoggingSystem"); systems.put("java.util.logging.LogManager",
"org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems); SYSTEMS = Collections.unmodifiableMap(systems);
} }
/** /**
* Reset the logging system to be limit output. This method may be called before * Reset the logging system to be limit output. This method may be called before
* {@link #initialize()} to reduce logging noise until the systems has been full * {@link #initialize(String, String)} to reduce logging noise until the systems has
* Initialized. * been fully Initialized.
*/ */
public abstract void beforeInitialize(); public abstract void beforeInitialize();
/** /**
* Initialize the logging system using sensible defaults. This method should generally * Fully initialize the logging system.
* try to find system specific configuration on classpath before falling back to * @param configLocation a log configuration location or {@code null} if default
* sensible defaults. * initialization is required
* @param logFile the log output file that should be written or {@code null} for
* console only output
*/ */
public abstract void initialize(); public abstract void initialize(String configLocation, String logFile);
/**
* Initialize the logging system from a logging configuration location.
* @param configLocation a log configuration location
*/
public abstract void initialize(String configLocation);
/** /**
* Sets the logging level for a given logger. * Sets the logging level for a given logger.
...@@ -71,17 +68,18 @@ public abstract class LoggingSystem { ...@@ -71,17 +68,18 @@ public abstract class LoggingSystem {
public abstract void setLogLevel(String loggerName, LogLevel level); public abstract void setLogLevel(String loggerName, LogLevel level);
/** /**
* Detect and return the logging system in use. * Detect and return the logging system in use. Supports Logback, Log4J, Log4J2 and
* Java Logging.
* @return The logging system * @return The logging system
*/ */
public static LoggingSystem get(ClassLoader classLoader, boolean fileOutput, boolean consoleOutput) { public static LoggingSystem get(ClassLoader classLoader) {
for (Map.Entry<String, String> entry : SYSTEMS.entrySet()) { for (Map.Entry<String, String> entry : SYSTEMS.entrySet()) {
if (ClassUtils.isPresent(entry.getKey(), classLoader)) { if (ClassUtils.isPresent(entry.getKey(), classLoader)) {
try { try {
Class<?> systemClass = ClassUtils.forName(entry.getValue(), Class<?> systemClass = ClassUtils.forName(entry.getValue(),
classLoader); classLoader);
return (LoggingSystem) systemClass.getConstructor(ClassLoader.class, boolean.class, boolean.class) return (LoggingSystem) systemClass.getConstructor(ClassLoader.class)
.newInstance(classLoader, fileOutput, consoleOutput); .newInstance(classLoader);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
......
...@@ -27,16 +27,17 @@ import org.springframework.util.ClassUtils; ...@@ -27,16 +27,17 @@ import org.springframework.util.ClassUtils;
*/ */
public abstract class Slf4JLoggingSystem extends AbstractLoggingSystem { public abstract class Slf4JLoggingSystem extends AbstractLoggingSystem {
public Slf4JLoggingSystem(ClassLoader classLoader, boolean fileOutput, boolean consoleOutput) { private static final String BRIDGE_HANDLER = "org.slf4j.bridge.SLF4JBridgeHandler";
super(classLoader, fileOutput, consoleOutput);
public Slf4JLoggingSystem(ClassLoader classLoader) {
super(classLoader);
} }
@Override @Override
public void beforeInitialize() { public void beforeInitialize() {
super.beforeInitialize(); super.beforeInitialize();
try { try {
if (ClassUtils.isPresent("org.slf4j.bridge.SLF4JBridgeHandler", if (ClassUtils.isPresent(BRIDGE_HANDLER, getClassLoader())) {
getClassLoader())) {
try { try {
SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.removeHandlersForRootLogger();
} }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.logging.java; package org.springframework.boot.logging.java;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -27,8 +29,9 @@ import org.springframework.boot.logging.AbstractLoggingSystem; ...@@ -27,8 +29,9 @@ import org.springframework.boot.logging.AbstractLoggingSystem;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystem;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils; import org.springframework.util.StringUtils;
/** /**
* {@link LoggingSystem} for {@link Logger java.util.logging}. * {@link LoggingSystem} for {@link Logger java.util.logging}.
...@@ -52,30 +55,46 @@ public class JavaLoggingSystem extends AbstractLoggingSystem { ...@@ -52,30 +55,46 @@ public class JavaLoggingSystem extends AbstractLoggingSystem {
} }
public JavaLoggingSystem(ClassLoader classLoader) { public JavaLoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true); super(classLoader);
}
public JavaLoggingSystem(ClassLoader classLoader, boolean fileOutput,
boolean consoleOutput) {
super(classLoader, fileOutput, consoleOutput);
} }
@Override @Override
protected String[] getLogFileNames() { protected String[] getStandardConfigLocations() {
return new String[] { "logging.properties" }; return new String[] { "logging.properties" };
} }
@Override @Override
public void initialize(String configLocation) { public void beforeInitialize() {
Assert.notNull(configLocation, "ConfigLocation must not be null"); super.beforeInitialize();
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation); Logger.getLogger("").setLevel(Level.SEVERE);
}
@Override
protected void loadDefaults(String logFile) {
if (StringUtils.hasLength(logFile)) {
loadConfiguration(getPackagedConfigFile("logging-file.properties"), logFile);
}
else {
loadConfiguration(getPackagedConfigFile("logging.properties"), logFile);
}
}
@Override
protected void loadConfiguration(String location, String logFile) {
Assert.notNull(location, "Location must not be null");
try { try {
String configuration = FileCopyUtils.copyToString(new InputStreamReader(
ResourceUtils.getURL(location).openStream()));
if (StringUtils.hasLength(logFile)) {
configuration = configuration.replace("${LOG_FILE}",
StringUtils.cleanPath(logFile));
}
LogManager.getLogManager().readConfiguration( LogManager.getLogManager().readConfiguration(
ResourceUtils.getURL(resolvedLocation).openStream()); new ByteArrayInputStream(configuration.getBytes()));
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Could not initialize logging from " throw new IllegalStateException("Could not initialize Java logging from "
+ configLocation, ex); + location, ex);
} }
} }
......
...@@ -52,28 +52,42 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem { ...@@ -52,28 +52,42 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem {
} }
public Log4JLoggingSystem(ClassLoader classLoader) { public Log4JLoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true); super(classLoader);
}
public Log4JLoggingSystem(ClassLoader classLoader, boolean fileOutput,
boolean consoleOutput) {
super(classLoader, fileOutput, consoleOutput);
} }
@Override @Override
protected String[] getLogFileNames() { protected String[] getStandardConfigLocations() {
return new String[] { "log4j.xml", "log4j.properties" }; return new String[] { "log4j.xml", "log4j.properties" };
} }
@Override @Override
public void initialize(String configLocation) { public void beforeInitialize() {
Assert.notNull(configLocation, "ConfigLocation must not be null"); super.beforeInitialize();
LogManager.getRootLogger().setLevel(Level.FATAL);
}
@Override
protected void loadDefaults(String logFile) {
if (StringUtils.hasLength(logFile)) {
loadConfiguration(getPackagedConfigFile("log4j-file.properties"), logFile);
}
else {
loadConfiguration(getPackagedConfigFile("log4j.properties"), logFile);
}
}
@Override
protected void loadConfiguration(String location, String logFile) {
Assert.notNull(location, "Location must not be null");
if (StringUtils.hasLength(logFile)) {
System.setProperty("LOG_FILE", logFile);
}
try { try {
Log4jConfigurer.initLogging(configLocation); Log4jConfigurer.initLogging(location);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Could not initialize logging from " throw new IllegalStateException("Could not initialize Log4J logging from "
+ configLocation, ex); + location, ex);
} }
} }
......
...@@ -24,7 +24,6 @@ import java.util.Map; ...@@ -24,7 +24,6 @@ import java.util.Map;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
...@@ -32,7 +31,7 @@ import org.springframework.boot.logging.LoggingSystem; ...@@ -32,7 +31,7 @@ import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.Slf4JLoggingSystem; import org.springframework.boot.logging.Slf4JLoggingSystem;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils; import org.springframework.util.StringUtils;
/** /**
* {@link LoggingSystem} for <a href="http://logging.apache.org/log4j/2.x/">Log4j 2</a>. * {@link LoggingSystem} for <a href="http://logging.apache.org/log4j/2.x/">Log4j 2</a>.
...@@ -57,44 +56,53 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem { ...@@ -57,44 +56,53 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
} }
public Log4J2LoggingSystem(ClassLoader classLoader) { public Log4J2LoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true); super(classLoader);
} }
public Log4J2LoggingSystem(ClassLoader classLoader, boolean fileOutput, boolean consoleOutput) {
super(classLoader, fileOutput, consoleOutput);
}
@Override @Override
protected String[] getLogFileNames() { protected String[] getStandardConfigLocations() {
return new String[] { "log4j2.json", "log4j2.jsn", "log4j2.xml" }; return new String[] { "log4j2.json", "log4j2.jsn", "log4j2.xml" };
} }
@Override @Override
public void initialize(String configLocation) { public void beforeInitialize() {
Assert.notNull(configLocation, "ConfigLocation must not be null"); super.beforeInitialize();
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation); setLogLevel("", LogLevel.FATAL);
try { }
initializeAndStart(resolvedLocation);
@Override
protected void loadDefaults(String logFile) {
if (StringUtils.hasLength(logFile)) {
loadConfiguration(getPackagedConfigFile("log4j2-file.xml"), logFile);
} }
catch (Exception ex) { else {
throw new IllegalStateException("Could not initialize logging from " loadConfiguration(getPackagedConfigFile("log4j2.xml"), logFile);
+ configLocation, ex);
} }
} }
private void initializeAndStart(String resolvedLocation) throws Exception { @Override
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); protected void loadConfiguration(String location, String logFile) {
URL url = ResourceUtils.getURL(resolvedLocation); Assert.notNull(location, "Location must not be null");
ConfigurationSource configSource = new ConfigurationSource(url.openStream(), url); if (StringUtils.hasLength(logFile)) {
Configuration config = ConfigurationFactory.getInstance().getConfiguration( System.setProperty("LOG_FILE", logFile);
configSource); }
ctx.start(config); try {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
URL url = ResourceUtils.getURL(location);
ConfigurationSource source = new ConfigurationSource(url.openStream(), url);
ctx.start(ConfigurationFactory.getInstance().getConfiguration(source));
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Log4J2 logging from "
+ location, ex);
}
} }
@Override @Override
public void setLogLevel(String loggerName, LogLevel level) { public void setLogLevel(String loggerName, LogLevel level) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ctx.getConfiguration().getLoggerConfig(loggerName).setLevel(LEVELS.get(level)); ctx.getConfiguration().getLoggerConfig(loggerName == null ? "" : loggerName)
.setLevel(LEVELS.get(level));
ctx.updateLoggers(); ctx.updateLoggers();
} }
......
...@@ -23,6 +23,7 @@ import java.util.Map; ...@@ -23,6 +23,7 @@ import java.util.Map;
import org.slf4j.ILoggerFactory; import org.slf4j.ILoggerFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.impl.StaticLoggerBinder; import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystem;
...@@ -30,11 +31,12 @@ import org.springframework.boot.logging.Slf4JLoggingSystem; ...@@ -30,11 +31,12 @@ import org.springframework.boot.logging.Slf4JLoggingSystem;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.classic.util.ContextInitializer; import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.spi.FilterReply;
/** /**
* {@link LoggingSystem} for for <a href="http://logback.qos.ch">logback</a>. * {@link LoggingSystem} for for <a href="http://logback.qos.ch">logback</a>.
...@@ -58,25 +60,54 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { ...@@ -58,25 +60,54 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
LEVELS = Collections.unmodifiableMap(levels); LEVELS = Collections.unmodifiableMap(levels);
} }
private static final TurboFilter FILTER = new TurboFilter() {
@Override
public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger,
Level level, String format, Object[] params, Throwable t) {
return FilterReply.DENY;
}
};
public LogbackLoggingSystem(ClassLoader classLoader) { public LogbackLoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true); super(classLoader);
}
public LogbackLoggingSystem(ClassLoader classLoader, boolean fileOutput,
boolean consoleOutput) {
super(classLoader, fileOutput, consoleOutput);
} }
@Override @Override
protected String[] getLogFileNames() { protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", return new String[] { "logback-test.groovy", "logback-test.xml",
"logback.groovy", "logback.xml" }; "logback.groovy", "logback.xml" };
} }
@Override @Override
public void initialize(String configLocation) { public void beforeInitialize() {
Assert.notNull(configLocation, "ConfigLocation must not be null"); super.beforeInitialize();
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation); getLogger(null).getLoggerContext().getTurboFilterList().add(FILTER);
}
@Override
public void initialize(String configLocation, String logFile) {
getLogger(null).getLoggerContext().getTurboFilterList().remove(FILTER);
super.initialize(configLocation, logFile);
}
@Override
protected void loadDefaults(String logFile) {
if (StringUtils.hasLength(logFile)) {
loadConfiguration(getPackagedConfigFile("logback-file.xml"), logFile);
}
else {
loadConfiguration(getPackagedConfigFile("logback.xml"), logFile);
}
}
@Override
protected void loadConfiguration(String location, String logFile) {
Assert.notNull(location, "Location must not be null");
if (StringUtils.hasLength(logFile)) {
System.setProperty("LOG_FILE", logFile);
}
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Assert.isInstanceOf( Assert.isInstanceOf(
LoggerContext.class, LoggerContext.class,
...@@ -92,22 +123,25 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { ...@@ -92,22 +123,25 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
context.stop(); context.stop();
context.reset(); context.reset();
try { try {
URL url = ResourceUtils.getURL(resolvedLocation); URL url = ResourceUtils.getURL(location);
new ContextInitializer(context).configureByResource(url); new ContextInitializer(context).configureByResource(url);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Could not initialize logging from " throw new IllegalStateException("Could not initialize Logback logging from "
+ configLocation, ex); + location, ex);
} }
} }
@Override @Override
public void setLogLevel(String loggerName, LogLevel level) { public void setLogLevel(String loggerName, LogLevel level) {
getLogger(loggerName).setLevel(LEVELS.get(level));
}
private ch.qos.logback.classic.Logger getLogger(String name) {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Logger logger = factory return (ch.qos.logback.classic.Logger) factory.getLogger(StringUtils
.getLogger(StringUtils.isEmpty(loggerName) ? Logger.ROOT_LOGGER_NAME .isEmpty(name) ? Logger.ROOT_LOGGER_NAME : name);
: loggerName);
((ch.qos.logback.classic.Logger) logger).setLevel(LEVELS.get(level));
} }
} }
handlers = java.util.logging.ConsoleHandler
.level = INFO
java.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
java.util.logging.ConsoleHandler.level = ALL
org.hibernate.validator.internal.util.Version.level = WARNING
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
org.crsh.plugin.level = WARNING
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
org.apache.catalina.startup.DigesterFactory.level = SEVERE
org.apache.catalina.util.LifecycleBase.level = SEVERE
org.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE
handlers =java.util.logging.FileHandler,java.util.logging.ConsoleHandler
.level = INFO
# File Logging
java.util.logging.FileHandler.pattern = %t/spring.log
java.util.logging.FileHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
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
org.hibernate.validator.internal.util.Version.level = WARNING
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
org.crsh.plugin.level = WARNING
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
org.apache.catalina.startup.DigesterFactory.level = SEVERE
org.apache.catalina.util.LifecycleBase.level = SEVERE
org.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE
handlers =java.util.logging.FileHandler handlers =java.util.logging.FileHandler,java.util.logging.ConsoleHandler
.level = INFO .level = INFO
# File Logging # File Logging
java.util.logging.FileHandler.pattern = %t/spring.log java.util.logging.FileHandler.pattern = ${LOG_FILE}
java.util.logging.FileHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter java.util.logging.FileHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
java.util.logging.FileHandler.level = ALL java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.limit = 10485760 java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10 java.util.logging.FileHandler.count = 10
java.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
java.util.logging.ConsoleHandler.level = ALL
org.hibernate.validator.internal.util.Version.level = WARNING org.hibernate.validator.internal.util.Version.level = WARNING
org.apache.coyote.http11.Http11NioProtocol.level = WARNING org.apache.coyote.http11.Http11NioProtocol.level = WARNING
org.crsh.plugin.level = WARNING org.crsh.plugin.level = WARNING
......
handlers =
.level = INFO
org.hibernate.validator.internal.util.Version.level = WARNING
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
org.crsh.plugin.level = WARNING
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
org.apache.catalina.startup.DigesterFactory.level = SEVERE
org.apache.catalina.util.LifecycleBase.level = SEVERE
org.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE
log4j.rootCategory=INFO, CONSOLE
PID=????
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%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}
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR
log4j.category.org.apache.catalina.util.LifecycleBase=ERROR
log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.rootCategory=INFO, CONSOLE, FILE
PID=????
LOG_PATH=${java.io.tmpdir}
LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%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}
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=${LOG_FILE}
log4j.appender.FILE.MaxFileSize=10MB
log4j.appender.FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=${LOG_PATTERN}
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR
log4j.category.org.apache.catalina.util.LifecycleBase=ERROR
log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.rootCategory=INFO,FILE log4j.rootCategory=INFO, CONSOLE, FILE
PID=???? PID=????
LOG_PATH=${java.io.tmpdir} LOG_PATH=${java.io.tmpdir}
LOG_FILE=${LOG_PATH}/spring.log LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%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}
log4j.appender.FILE=org.apache.log4j.RollingFileAppender log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=${LOG_FILE} log4j.appender.FILE.File=${LOG_FILE}
log4j.appender.FILE.MaxFileSize=10MB log4j.appender.FILE.MaxFileSize=10MB
log4j.appender.FILE.layout = org.apache.log4j.PatternLayout log4j.appender.FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=${LOG_PATTERN} log4j.appender.FILE.layout.ConversionPattern=${LOG_PATTERN}
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR
log4j.category.org.apache.catalina.util.LifecycleBase=ERROR log4j.category.org.apache.catalina.util.LifecycleBase=ERROR
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.apache.sshd.common.util.SecurityUtils
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.crsh.ssh=WARN
log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration=WARN
log4j.category.org.springframework.boot.actuate.endpoint.jmx=WARN
log4j.category.org.thymeleaf=WARN
log4j.rootCategory=INFO
PID=????
LOG_PATH=${java.io.tmpdir}
LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR
log4j.category.org.apache.catalina.util.LifecycleBase=ERROR
log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.rootCategory=INFO, CONSOLE log4j.rootCategory=INFO, CONSOLE
PID=???? PID=????
LOG_PATH=${java.io.tmpdir}
LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n
# CONSOLE is set to be a ConsoleAppender using a PatternLayout. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
...@@ -10,11 +8,15 @@ log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender ...@@ -10,11 +8,15 @@ log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=${LOG_PATTERN} log4j.appender.CONSOLE.layout.ConversionPattern=${LOG_PATTERN}
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR log4j.category.org.apache.catalina.startup.DigesterFactory=ERROR
log4j.category.org.apache.catalina.util.LifecycleBase=ERROR log4j.category.org.apache.catalina.util.LifecycleBase=ERROR
log4j.category.org.apache.coyote.http11.Http11NioProtocol=WARN
log4j.category.org.apache.sshd.common.util.SecurityUtils
log4j.category.org.apache.tomcat.util.net.NioSelectorPool=WARN
log4j.category.org.crsh.plugin=WARN
log4j.category.org.crsh.ssh=WARN
log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR log4j.category.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.category.org.hibernate.validator.internal.util.Version=WARN
log4j.category.org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration=WARN
log4j.category.org.springframework.boot.actuate.endpoint.jmx=WARN
log4j.category.org.thymeleaf=WARN
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.crsh.plugin" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATH">/tmp</Property>
<Property name="LOG_FILE">${sys:LOG_PATH}/spring.log</Property>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
<RollingFile name="File" fileName="${sys:LOG_FILE}"
filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.crsh.plugin" level="warn" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"> <Configuration status="WARN">
<Properties> <Properties>
<Property name="PID">????</Property> <Property name="PID">????</Property>
<Property name="LOG_PATH">/tmp</Property> <Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
<Property name="LOG_FILE">${sys:LOG_PATH}/spring.log</Property> </Properties>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property> <Appenders>
</Properties> <Console name="Console" target="SYSTEM_OUT" follow="true">
<Appenders> <PatternLayout pattern="${LOG_PATTERN}" />
<RollingFile name="File" fileName="${sys:LOG_FILE}" </Console>
filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz"> <RollingFile name="File" fileName="${sys:LOG_FILE}" filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout> <PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern> <Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout> </PatternLayout>
<Policies> <Policies>
<SizeBasedTriggeringPolicy size="10 MB"/> <SizeBasedTriggeringPolicy size="10 MB" />
</Policies> </Policies>
</RollingFile> </RollingFile>
</Appenders> </Appenders>
<Loggers> <Loggers>
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" /> <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" /> <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.crsh.plugin" level="warn" /> <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" /> <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" /> <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" /> <Logger name="org.crsh.plugin" level="warn" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" /> <logger name="org.crsh.ssh" level="warn"/>
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Root level="info"> <Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<AppenderRef ref="File"/> <logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
</Root> <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
</Loggers> <logger name="org.thymeleaf" level="warn"/>
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="File" />
</Root>
</Loggers>
</Configuration> </Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="PID">????</Property>
<Property name="LOG_PATH">/tmp</Property>
<Property name="LOG_FILE">${sys:LOG_PATH}/spring.log</Property>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
</Properties>
<Loggers>
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.crsh.plugin" level="warn" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Root level="info">
</Root>
</Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"> <Configuration status="WARN">
<Properties> <Properties>
<Property name="PID">????</Property> <Property name="PID">????</Property>
<Property name="LOG_PATH">/tmp</Property> <Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
<Property name="LOG_FILE">${sys:LOG_PATH}/spring.log</Property> </Properties>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property> <Appenders>
</Properties> <Console name="Console" target="SYSTEM_OUT" follow="true">
<Appenders> <PatternLayout pattern="${LOG_PATTERN}" />
<Console name="Console" target="SYSTEM_OUT" follow="true"> </Console>
<PatternLayout pattern="${LOG_PATTERN}"/> </Appenders>
</Console> <Loggers>
</Appenders> <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Loggers> <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" /> <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" /> <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.crsh.plugin" level="warn" /> <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" /> <Logger name="org.crsh.plugin" level="warn" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" /> <logger name="org.crsh.ssh" level="warn"/>
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" /> <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" /> <Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
<Root level="info"> <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
<AppenderRef ref="Console"/> <logger name="org.thymeleaf" level="warn"/>
</Root> <Root level="info">
</Loggers> <AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration> </Configuration>
...@@ -2,16 +2,28 @@ ...@@ -2,16 +2,28 @@
<included> <included>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t{14}]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex"/> <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t{14}]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } [%t] --- %-40.40logger{39} : %m%n%wex"/>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern> <appender name="DEBUG_LEVEL_REMAPPER" class="org.springframework.boot.logging.logback.LevelRemappingAppender">
<charset>utf8</charset> <destinationLogger>org.springframework.boot</destinationLogger>
</encoder>
</appender> </appender>
<root level="INFO"> <logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
<appender-ref ref="CONSOLE" /> <logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
</root> <logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
<logger name="org.crsh.plugin" level="WARN"/>
<logger name="org.crsh.ssh" level="WARN"/>
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN"/>
<logger name="org.springframework.boot.actuate.endpoint.jmx" additivity="false">
<appender-ref ref="DEBUG_LEVEL_REMAPPER"/>
</logger>
<logger name="org.thymeleaf" additivity="false">
<appender-ref ref="DEBUG_LEVEL_REMAPPER"/>
</logger>
</included> </included>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<included>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
</included>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<included> <included>
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } [%t] --- %-40.40logger{39} : %m%n%wex"/>
<appender name="FILE" <appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender"> class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder> <encoder>
...@@ -17,7 +14,4 @@ ...@@ -17,7 +14,4 @@
<MaxFileSize>10MB</MaxFileSize> <MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy> </triggeringPolicy>
</appender> </appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</included> </included>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base-file.xml"/>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
</configuration>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<include resource="org/springframework/boot/logging/logback/base-file.xml"/> <include resource="org/springframework/boot/logging/logback/base.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml"/>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration> </configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<root level="INFO">
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/> <include resource="org/springframework/boot/logging/logback/base.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration> </configuration>
/*
* Copyright 2012-2014 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;
import java.io.File;
import org.junit.After;
import org.junit.Before;
import org.springframework.util.StringUtils;
/**
* Base for {@link LoggingSystem} tests.
*
* @author Phillip Webb
*/
public abstract class AbstractLoggingSystemTests {
@Before
public void deleteTempLog() {
new File(tmpDir() + "/spring.log").delete();
}
@After
public void clear() {
System.clearProperty("LOG_FILE");
System.clearProperty("PID");
}
protected final String tmpDir() {
String path = StringUtils.cleanPath(System.getProperty("java.io.tmpdir"));
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
return path;
}
}
...@@ -106,17 +106,6 @@ public class LoggingApplicationListenerTests { ...@@ -106,17 +106,6 @@ public class LoggingApplicationListenerTests {
assertFalse(new File(tmpDir() + "/spring.log").exists()); assertFalse(new File(tmpDir() + "/spring.log").exists());
} }
@Test
public void noConsole() {
EnvironmentTestUtils.addEnvironment(this.context, "logging.console: false");
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.info("Hello world");
String output = this.outputCapture.toString().trim();
assertFalse("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
}
@Test @Test
public void overrideConfigLocation() { public void overrideConfigLocation() {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
...@@ -127,7 +116,8 @@ public class LoggingApplicationListenerTests { ...@@ -127,7 +116,8 @@ public class LoggingApplicationListenerTests {
String output = this.outputCapture.toString().trim(); String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Wrong output:\n" + output, output.contains("???")); assertFalse("Wrong output:\n" + output, output.contains("???"));
assertTrue("Wrong output:\n" + output, output.startsWith(tmpDir() + "/tmp.log")); assertTrue("Wrong output:\n" + output, output.startsWith("LOG_FILE_IS_UNDEFINED"));
assertTrue("Wrong output:\n" + output, output.endsWith("BOOTBOOT"));
} }
@Test @Test
...@@ -178,7 +168,7 @@ public class LoggingApplicationListenerTests { ...@@ -178,7 +168,7 @@ public class LoggingApplicationListenerTests {
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class); Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
logger.info("Hello world"); logger.info("Hello world");
String output = this.outputCapture.toString().trim(); String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.startsWith("target/foo/tmp.log")); assertTrue("Wrong output:\n" + output, output.startsWith("target/foo/spring.log"));
} }
@Test @Test
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.logging.java; package org.springframework.boot.logging.java;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
...@@ -24,12 +26,15 @@ import org.junit.After; ...@@ -24,12 +26,15 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
...@@ -37,8 +42,18 @@ import static org.junit.Assert.assertTrue; ...@@ -37,8 +42,18 @@ import static org.junit.Assert.assertTrue;
* Tests for {@link JavaLoggingSystem}. * Tests for {@link JavaLoggingSystem}.
* *
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb
*/ */
public class JavaLoggerSystemTests { public class JavaLoggerSystemTests extends AbstractLoggingSystemTests {
private static final FileFilter SPRING_LOG_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().startsWith("spring.log");
}
};
private final JavaLoggingSystem loggingSystem = new JavaLoggingSystem(getClass() private final JavaLoggingSystem loggingSystem = new JavaLoggingSystem(getClass()
.getClassLoader()); .getClassLoader());
...@@ -58,17 +73,43 @@ public class JavaLoggerSystemTests { ...@@ -58,17 +73,43 @@ public class JavaLoggerSystemTests {
} }
@After @After
public void clear() { public void clearLocale() {
System.clearProperty("LOG_FILE");
System.clearProperty("LOG_PATH");
System.clearProperty("PID");
Locale.setDefault(this.defaultLocale); Locale.setDefault(this.defaultLocale);
} }
@Test
public void noFile() throws Exception {
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
}
@Test
public void withFile() throws Exception {
File temp = new File(tmpDir());
File[] logFiles = temp.listFiles(SPRING_LOG_FILTER);
for (File file : logFiles) {
file.delete();
}
this.loggingSystem.beforeInitialize();
this.logger.info("Hidden");
this.loggingSystem.initialize(null, tmpDir() + "/spring.log");
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertThat(temp.listFiles(SPRING_LOG_FILTER).length, greaterThan(0));
}
@Test @Test
public void testCustomFormatter() throws Exception { public void testCustomFormatter() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
...@@ -79,9 +120,10 @@ public class JavaLoggerSystemTests { ...@@ -79,9 +120,10 @@ public class JavaLoggerSystemTests {
public void testSystemPropertyInitializesFormat() throws Exception { public void testSystemPropertyInitializesFormat() throws Exception {
System.setProperty("PID", "1234"); System.setProperty("PID", "1234");
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:" this.loggingSystem.initialize(
+ ClassUtils.addResourcePathToPackagePath(getClass(), "classpath:"
"logging.properties")); + ClassUtils.addResourcePathToPackagePath(getClass(),
"logging.properties"), null);
this.logger.info("Hello world"); this.logger.info("Hello world");
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
...@@ -92,7 +134,7 @@ public class JavaLoggerSystemTests { ...@@ -92,7 +134,7 @@ public class JavaLoggerSystemTests {
@Test @Test
public void testNonDefaultConfigLocation() throws Exception { public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logging-nondefault.properties"); this.loggingSystem.initialize("classpath:logging-nondefault.properties", null);
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("INFO: Hello")); assertTrue("Wrong output:\n" + output, output.contains("INFO: Hello"));
...@@ -101,19 +143,13 @@ public class JavaLoggerSystemTests { ...@@ -101,19 +143,13 @@ public class JavaLoggerSystemTests {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception { public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logging-nonexistent.properties"); this.loggingSystem.initialize("classpath:logging-nonexistent.properties", null);
}
@Test(expected = IllegalArgumentException.class)
public void testNullConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null);
} }
@Test @Test
public void setLevel() throws Exception { public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
this.logger.debug("Hello"); this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello"); this.logger.debug("Hello");
......
...@@ -16,17 +16,20 @@ ...@@ -16,17 +16,20 @@
package org.springframework.boot.logging.log4j; package org.springframework.boot.logging.log4j;
import java.io.File;
import org.apache.commons.logging.impl.Log4JLogger; import org.apache.commons.logging.impl.Log4JLogger;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
...@@ -35,7 +38,7 @@ import static org.junit.Assert.assertTrue; ...@@ -35,7 +38,7 @@ import static org.junit.Assert.assertTrue;
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
public class Log4JLoggingSystemTests { public class Log4JLoggingSystemTests extends AbstractLoggingSystemTests {
@Rule @Rule
public OutputCapture output = new OutputCapture(); public OutputCapture output = new OutputCapture();
...@@ -50,39 +53,52 @@ public class Log4JLoggingSystemTests { ...@@ -50,39 +53,52 @@ public class Log4JLoggingSystemTests {
this.logger = new Log4JLogger(getClass().getName()); this.logger = new Log4JLogger(getClass().getName());
} }
@After @Test
public void clear() { public void noFile() throws Exception {
System.clearProperty("LOG_FILE"); this.loggingSystem.beforeInitialize();
System.clearProperty("LOG_PATH"); this.logger.info("Hidden");
System.clearProperty("PID"); this.loggingSystem.initialize(null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
} }
@Test @Test
public void testNonDefaultConfigLocation() throws Exception { public void withFile() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j-nondefault.properties"); this.logger.info("Hidden");
this.loggingSystem.initialize(null, tmpDir() + "/spring.log");
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertTrue("Wrong output:\n" + output, output.contains("/tmp/spring.log")); assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertTrue(new File(tmpDir() + "/spring.log").exists());
} }
@Test(expected = IllegalStateException.class) @Test
public void testNonexistentConfigLocation() throws Exception { public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j-nonexistent.xml"); this.loggingSystem.initialize("classpath:log4j-nondefault.properties", tmpDir()
+ "/spring.log");
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(tmpDir() + "/spring.log"));
assertFalse(new File(tmpDir() + "/tmp.log").exists());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalStateException.class)
public void testNullConfigLocation() throws Exception { public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null); this.loggingSystem.initialize("classpath:log4j-nonexistent.xml", null);
} }
@Test @Test
public void setLevel() throws Exception { public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
this.logger.debug("Hello"); this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello"); this.logger.debug("Hello");
...@@ -94,7 +110,7 @@ public class Log4JLoggingSystemTests { ...@@ -94,7 +110,7 @@ public class Log4JLoggingSystemTests {
@Ignore("Fails on Bamboo") @Ignore("Fails on Bamboo")
public void loggingThatUsesJulIsCaptured() { public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName()); .getLogger(getClass().getName());
julLogger.severe("Hello world"); julLogger.severe("Hello world");
......
...@@ -16,18 +16,21 @@ ...@@ -16,18 +16,21 @@
package org.springframework.boot.logging.log4j2; package org.springframework.boot.logging.log4j2;
import java.io.File;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
...@@ -35,8 +38,9 @@ import static org.junit.Assert.assertTrue; ...@@ -35,8 +38,9 @@ import static org.junit.Assert.assertTrue;
* Tests for {@link Log4J2LoggingSystem}. * Tests for {@link Log4J2LoggingSystem}.
* *
* @author Daniel Fullarton * @author Daniel Fullarton
* @author Phillip Webb
*/ */
public class Log4J2LoggingSystemTests { public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Rule @Rule
public OutputCapture output = new OutputCapture(); public OutputCapture output = new OutputCapture();
...@@ -51,39 +55,52 @@ public class Log4J2LoggingSystemTests { ...@@ -51,39 +55,52 @@ public class Log4J2LoggingSystemTests {
this.logger = LogManager.getLogger(getClass()); this.logger = LogManager.getLogger(getClass());
} }
@After @Test
public void clear() { public void noFile() throws Exception {
System.clearProperty("LOG_FILE"); this.loggingSystem.beforeInitialize();
System.clearProperty("LOG_PATH"); this.logger.info("Hidden");
System.clearProperty("PID"); this.loggingSystem.initialize(null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
} }
@Test @Test
public void testNonDefaultConfigLocation() throws Exception { public void withFile() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j2-nondefault.xml"); this.logger.info("Hidden");
this.loggingSystem.initialize(null, tmpDir() + "/spring.log");
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertTrue("Wrong output:\n" + output, output.contains("/tmp/spring.log")); assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertTrue(new File(tmpDir() + "/spring.log").exists());
} }
@Test(expected = IllegalStateException.class) @Test
public void testNonexistentConfigLocation() throws Exception { public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:log4j2-nonexistent.xml"); this.loggingSystem.initialize("classpath:log4j2-nondefault.xml", tmpDir()
+ "/tmp.log");
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(tmpDir() + "/tmp.log"));
assertFalse(new File(tmpDir() + "/tmp.log").exists());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalStateException.class)
public void testNullConfigLocation() throws Exception { public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null); this.loggingSystem.initialize("classpath:log4j2-nonexistent.xml", null);
} }
@Test @Test
public void setLevel() throws Exception { public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
this.logger.debug("Hello"); this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello"); this.logger.debug("Hello");
...@@ -95,7 +112,7 @@ public class Log4J2LoggingSystemTests { ...@@ -95,7 +112,7 @@ public class Log4J2LoggingSystemTests {
@Ignore("Fails on Bamboo") @Ignore("Fails on Bamboo")
public void loggingThatUsesJulIsCaptured() { public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName()); .getLogger(getClass().getName());
julLogger.severe("Hello world"); julLogger.severe("Hello world");
......
...@@ -20,12 +20,12 @@ import java.io.File; ...@@ -20,12 +20,12 @@ import java.io.File;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.SLF4JLogFactory; import org.apache.commons.logging.impl.SLF4JLogFactory;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.slf4j.ILoggerFactory; import org.slf4j.ILoggerFactory;
import org.slf4j.impl.StaticLoggerBinder; import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -43,8 +43,9 @@ import static org.junit.Assert.assertTrue; ...@@ -43,8 +43,9 @@ import static org.junit.Assert.assertTrue;
* Tests for {@link LogbackLoggingSystem}. * Tests for {@link LogbackLoggingSystem}.
* *
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb
*/ */
public class LogbackLoggingSystemTests { public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
@Rule @Rule
public OutputCapture output = new OutputCapture(); public OutputCapture output = new OutputCapture();
...@@ -57,22 +58,30 @@ public class LogbackLoggingSystemTests { ...@@ -57,22 +58,30 @@ public class LogbackLoggingSystemTests {
@Before @Before
public void setup() { public void setup() {
this.logger = new SLF4JLogFactory().getInstance(getClass().getName()); this.logger = new SLF4JLogFactory().getInstance(getClass().getName());
new File(tmpDir() + "/spring.log").delete();
} }
private String tmpDir() { @Test
String path = StringUtils.cleanPath(System.getProperty("java.io.tmpdir")); public void noFile() throws Exception {
if (path.endsWith("/")) { this.loggingSystem.beforeInitialize();
path = path.substring(0, path.length() - 1); this.logger.info("Hidden");
} this.loggingSystem.initialize(null, null);
return path; this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
} }
@After @Test
public void clear() { public void withFile() throws Exception {
System.clearProperty("LOG_FILE"); this.loggingSystem.beforeInitialize();
System.clearProperty("LOG_PATH"); this.logger.info("Hidden");
System.clearProperty("PID"); this.loggingSystem.initialize(null, tmpDir() + "/spring.log");
this.logger.info("Hello world");
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(new File(tmpDir() + "/spring.log").exists());
} }
@Test @Test
...@@ -87,31 +96,26 @@ public class LogbackLoggingSystemTests { ...@@ -87,31 +96,26 @@ public class LogbackLoggingSystemTests {
@Test @Test
public void testNonDefaultConfigLocation() throws Exception { public void testNonDefaultConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logback-nondefault.xml"); this.loggingSystem.initialize("classpath:logback-nondefault.xml", tmpDir()
+ "/tmp.log");
this.logger.info("Hello world"); this.logger.info("Hello world");
String output = this.output.toString().trim(); String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world")); assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertTrue("Wrong output (not " + tmpDir() + " :\n" + output, assertTrue("Wrong output:\n" + output, output.contains(tmpDir() + "/tmp.log"));
output.contains(tmpDir() + "/tmp.log")); assertTrue("Wrong output:\n" + output, output.endsWith("BOOTBOOT"));
assertFalse(new File(tmpDir() + "/tmp.log").exists()); assertFalse(new File(tmpDir() + "/tmp.log").exists());
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testNonexistentConfigLocation() throws Exception { public void testNonexistentConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize("classpath:logback-nonexistent.xml"); this.loggingSystem.initialize("classpath:logback-nonexistent.xml", null);
}
@Test(expected = IllegalArgumentException.class)
public void testNullConfigLocation() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null);
} }
@Test @Test
public void setLevel() throws Exception { public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
this.logger.debug("Hello"); this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello"); this.logger.debug("Hello");
...@@ -122,7 +126,7 @@ public class LogbackLoggingSystemTests { ...@@ -122,7 +126,7 @@ public class LogbackLoggingSystemTests {
@Test @Test
public void loggingThatUsesJulIsCaptured() { public void loggingThatUsesJulIsCaptured() {
this.loggingSystem.beforeInitialize(); this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(); this.loggingSystem.initialize(null, null);
java.util.logging.Logger julLogger = java.util.logging.Logger java.util.logging.Logger julLogger = java.util.logging.Logger
.getLogger(getClass().getName()); .getLogger(getClass().getName());
julLogger.info("Hello world"); julLogger.info("Hello world");
......
...@@ -2,8 +2,6 @@ log4j.reset=true ...@@ -2,8 +2,6 @@ log4j.reset=true
log4j.rootCategory=INFO, CONSOLE log4j.rootCategory=INFO, CONSOLE
PID=???? 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 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. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"> <Configuration status="WARN">
<Properties> <Properties>
<Property name="PID">????</Property> <Property name="PID">????</Property>
<Property name="LOG_PATH">/tmp</Property> <Property name="LOG_PATTERN">${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>
<Property name="LOG_FILE">${sys:LOG_PATH}/spring.log</Property> </Properties>
<Property name="LOG_PATTERN">${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property> <Appenders>
</Properties> <Console name="Console" target="SYSTEM_OUT" follow="true">
<Appenders> <PatternLayout pattern="${LOG_PATTERN}"/>
<Console name="Console" target="SYSTEM_OUT" follow="true"> </Console>
<PatternLayout pattern="${LOG_PATTERN}"/> </Appenders>
</Console> <Loggers>
</Appenders> <Root level="info">
<Loggers> <AppenderRef ref="Console"/>
<Root level="info"> </Root>
<AppenderRef ref="Console"/> </Loggers>
</Root> </Configuration>
</Loggers>
</Configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}tmp.log}"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
<pattern>${LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n</pattern> <pattern>${LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>
</encoder> </encoder>
</appender> </appender>
<root level="INFO"> <root level="INFO">
......
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