Skip to content

Commit

Permalink
Rework logging to prevent double initialization
Browse files Browse the repository at this point in the history
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 spring-projectsgh-1091
See spring-projectsgh-1612, spring-projectsgh-1770
  • Loading branch information
philwebb committed Oct 30, 2014
1 parent d17b7c8 commit cf24af0
Show file tree
Hide file tree
Showing 46 changed files with 652 additions and 657 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (ListableBeanFactory) beanFactory;
}
else {
logger.info("EndpointMBeanExporter not running in a ListableBeanFactory: "
logger.warn("EndpointMBeanExporter not running in a ListableBeanFactory: "
+ "autodetection of Endpoints not available.");
}
}
Expand Down
7 changes: 0 additions & 7 deletions spring-boot-cli/src/test/resources/logback.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
@EnableAutoConfiguration
@EnableConfigurationProperties
@ComponentScan
public class SampleActuatorApplication {
public class SampleActuatorLog4JApplication {

public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorApplication.class, args);
SpringApplication.run(SampleActuatorLog4JApplication.class, args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleActuatorApplication.class)
@SpringApplicationConfiguration(classes = SampleActuatorLog4JApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port=0")
@DirtiesContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
@EnableAutoConfiguration
@EnableConfigurationProperties
@ComponentScan
public class SampleActuatorApplication {
public class SampleActuatorLog4J2Application {

public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorApplication.class, args);
SpringApplication.run(SampleActuatorLog4J2Application.class, args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleActuatorApplication.class)
@SpringApplicationConfiguration(classes = SampleActuatorLog4J2Application.class)
@WebAppConfiguration
@IntegrationTest("server.port=0")
@DirtiesContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,12 @@ public ConfigurableApplicationContext run(String... args) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}

if (this.showBanner) {
printBanner(environment);
}
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}

// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;

/**
* Abstract base class for {@link LoggingSystem} implementations.
Expand All @@ -30,50 +31,70 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {

private final ClassLoader classLoader;

private final String[] paths;

private boolean fileOutput;

private boolean consoleOutput;

public AbstractLoggingSystem(ClassLoader classLoader) {
this(classLoader, false, true);
}

public AbstractLoggingSystem(ClassLoader classLoader, boolean fileOutput,
boolean consoleOutput) {
this.classLoader = classLoader;
this.fileOutput = fileOutput;
this.consoleOutput = consoleOutput;
this.paths = getLogFileNames();
}

protected abstract String[] getLogFileNames();

protected final ClassLoader getClassLoader() {
return this.classLoader;
}

@Override
public void beforeInitialize() {
initializeWithSensibleDefaults();
}

@Override
public void initialize() {
for (String path : this.paths) {
ClassPathResource resource = new ClassPathResource(path, this.classLoader);
public void initialize(String configLocation, String logFile) {
if (StringUtils.hasLength(configLocation)) {
// 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()) {
initialize("classpath:" + path);
return;
return "classpath:" + location;
}
}
// Fallback to the non-prefixed value taking into account file and console preferences
initialize(getPackagedConfigFile(addChannels(this.paths[this.paths.length - 1])));
return null;
}

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) {
Expand All @@ -84,14 +105,4 @@ protected final String getPackagedConfigFile(String fileName) {
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"));
}

}
Loading

0 comments on commit cf24af0

Please sign in to comment.