@ -16,7 +16,6 @@
package org.springframework.boot.logging ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
import java.util.Map.Entry ;
@ -41,49 +40,27 @@ import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils ;
/ * *
* An { @link ApplicationListener } that configures a logging framework depending on what it
* finds on the classpath and in the { @link Environment } . If the environment contains a
* property < code > logging . config < / code > then that will be used to initialize the logging
* system , otherwise a default location is used . The classpath is probed for log4j and
* logback and if those are present they will be reconfigured , otherwise vanilla
* < code > java . util . logging < / code > will be used . < / p >
* An { @link ApplicationListener } that configures the { @link LoggingSystem } . If the
* environment contains a { @code logging . config } property a then that will be used to
* initialize the logging system , otherwise a default configuration is used .
* < p >
* The default config locations are < code > classpath : log4j . properties < / code > or
* < code > classpath : log4j . xml < / code > for log4j ; < code > classpath : logback . xml < / code > for
* logback ; and < code > classpath : logging . properties < / code > for
* < code > java . util . logging < / code > . If the correct one of those files is not found then
* some sensible defaults are adopted from files of the same name but in the package
* containing { @link LoggingApplicationListener } .
* By default , log output is only written to the console . If a log file is required the
* { @code logging . path } and { @code logging . file } properties can be used .
* < p >
* Some system properties may be set as side effects , and these can be useful if the
* logging configuration supports placeholders ( i . e . log4j or logback ) :
* < ul >
* < li > < code > LOG_FILE < / code > is set to the value of < code > logging . file < / code > if found in
* the environment < / li >
* < li > < code > LOG_PATH < / code > is set to the value of < code > logging . path < / code > if found in
* the environment < / li >
* < li > < code > PID < / code > is set to the value of the current process ID if it can be
* determined < / li >
* < li > { @code LOG_FILE } is set to the value of path of the log file that should be written
* ( if any ) . < / li >
* < li > { @code PID } is set to the value of the current process ID if it can be determined . < / li >
* < / ul >
*
* @author Dave Syer
* @author Phillip Webb
* @see LoggingSystem # get ( ClassLoader )
* /
public class LoggingApplicationListener implements SmartApplicationListener {
private static final Map < String , String > ENVIRONMENT_SYSTEM_PROPERTY_MAPPING ;
public static final String PID_KEY = "PID" ;
public static final String LOG_FILE = "LOG_FILE" ;
static {
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING = new HashMap < String , String > ( ) ;
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING . put ( "logging.file" , "LOG_FILE" ) ;
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING . put ( "logging.path" , "LOG_PATH" ) ;
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING . put ( PID_KEY , PID_KEY ) ;
}
private static MultiValueMap < LogLevel , String > LOG_LEVEL_LOGGERS ;
static {
LOG_LEVEL_LOGGERS = new LinkedMultiValueMap < LogLevel , String > ( ) ;
@ -96,9 +73,6 @@ public class LoggingApplicationListener implements SmartApplicationListener {
LOG_LEVEL_LOGGERS . add ( LogLevel . DEBUG , "org.hibernate.SQL" ) ;
}
private static Class < ? > [ ] EVENT_TYPES = { ApplicationStartedEvent . class ,
ApplicationEnvironmentPreparedEvent . class } ;
private final Log logger = LogFactory . getLog ( getClass ( ) ) ;
private int order = Ordered . HIGHEST_PRECEDENCE + 11 ;
@ -109,12 +83,8 @@ public class LoggingApplicationListener implements SmartApplicationListener {
@Override
public boolean supportsEventType ( Class < ? extends ApplicationEvent > eventType ) {
for ( Class < ? > type : EVENT_TYPES ) {
if ( type . isAssignableFrom ( eventType ) ) {
return true ;
}
}
return false ;
return ApplicationStartedEvent . class . isAssignableFrom ( eventType )
| | ApplicationEnvironmentPreparedEvent . class . isAssignableFrom ( eventType ) ;
}
@Override
@ -124,18 +94,20 @@ public class LoggingApplicationListener implements SmartApplicationListener {
@Override
public void onApplicationEvent ( ApplicationEvent event ) {
if ( event instanceof ApplicationEnvironmentPreparedEvent ) {
ApplicationEnvironmentPreparedEvent available = ( ApplicationEnvironmentPreparedEvent ) event ;
initialize ( available . getEnvironment ( ) , available . getSpringApplication ( )
. getClassLoader ( ) ) ;
if ( event instanceof ApplicationStartedEvent ) {
onApplicationStartedEvent ( ( ApplicationStartedEvent ) event ) ;
}
else if ( event instanceof ApplicationEnvironmentPreparedEvent ) {
onApplicationPreparedEvent ( ( ApplicationEnvironmentPreparedEvent ) event ) ;
}
else {
if ( System . getProperty ( PID_KEY ) = = null ) {
System . setProperty ( PID_KEY , new ApplicationPid ( ) . toString ( ) ) ;
}
LoggingSystem loggingSystem = LoggingSystem . get ( ClassUtils . getDefaultClassLoader ( ) , false , false ) ;
loggingSystem . beforeInitialize ( ) ;
private void onApplicationStartedEvent ( ApplicationStartedEvent event ) {
LoggingSystem . get ( ClassUtils . getDefaultClassLoader ( ) ) . beforeInitialize ( ) ;
}
private void onApplicationPreparedEvent ( ApplicationEnvironmentPreparedEvent event ) {
initialize ( event . getEnvironment ( ) , event . getSpringApplication ( ) . getClassLoader ( ) ) ;
}
/ * *
@ -143,20 +115,11 @@ public class LoggingApplicationListener implements SmartApplicationListener {
* { @link Environment } and the classpath .
* /
protected void initialize ( ConfigurableEnvironment environment , ClassLoader classLoader ) {
initializeEarlyLoggingLevel ( environment ) ;
cleanLogTempProperty ( ) ;
boolean fileOutput = ! StringUtils . isEmpty ( environment . getProperty ( "logging.file" ) ) ;
boolean consoleOutput = true ;
if ( ! StringUtils . isEmpty ( environment . getProperty ( "logging.console" ) )
& & environment . getProperty ( "logging.console" ) . equalsIgnoreCase ( "false" ) ) {
consoleOutput = false ;
}
LoggingSystem system = LoggingSystem . get ( classLoader , fileOutput , consoleOutput ) ;
boolean systemEnvironmentChanged = mapSystemPropertiesFromSpring ( environment ) ;
if ( systemEnvironmentChanged ) {
// Re-initialize the defaults in case the system Environment changed
system . beforeInitialize ( ) ;
if ( System . getProperty ( "PID" ) = = null ) {
System . setProperty ( "PID" , new ApplicationPid ( ) . toString ( ) ) ;
}
initializeEarlyLoggingLevel ( environment ) ;
LoggingSystem system = LoggingSystem . get ( classLoader ) ;
initializeSystem ( environment , system ) ;
initializeFinalLoggingLevels ( environment , system ) ;
}
@ -172,52 +135,45 @@ public class LoggingApplicationListener implements SmartApplicationListener {
}
}
private void cleanLogTempProperty ( ) {
// Logback won't read backslashes so add a clean path for it to use
if ( ! StringUtils . hasLength ( System . getProperty ( "LOG_TEMP" ) ) ) {
String path = System . getProperty ( "java.io.tmpdir" ) ;
path = StringUtils . cleanPath ( path ) ;
if ( path . endsWith ( "/" ) ) {
path = path . substring ( 0 , path . length ( ) - 1 ) ;
}
System . setProperty ( "LOG_TEMP" , path ) ;
}
}
private boolean mapSystemPropertiesFromSpring ( Environment environment ) {
boolean changed = false ;
for ( Map . Entry < String , String > mapping : ENVIRONMENT_SYSTEM_PROPERTY_MAPPING
. entrySet ( ) ) {
String springName = mapping . getKey ( ) ;
String systemName = mapping . getValue ( ) ;
if ( environment . containsProperty ( springName ) ) {
System . setProperty ( systemName , environment . getProperty ( springName ) ) ;
changed = true ;
}
}
return changed ;
}
private void initializeSystem ( ConfigurableEnvironment environment ,
LoggingSystem system ) {
if ( environment . containsProperty ( "logging.config" ) ) {
String value = environment . getProperty ( "logging.config" ) ;
String logFile = getLogFile ( environment ) ;
String logConfig = environment . getProperty ( "logging.config" ) ;
if ( StringUtils . hasLength ( logConfig ) ) {
try {
ResourceUtils . getURL ( value ) . openStream ( ) . close ( ) ;
system . initialize ( valu e) ;
ResourceUtils . getURL ( logConfig ) . openStream ( ) . close ( ) ;
system . initialize ( logConfig , logFile ) ;
}
catch ( Exception ex ) {
this . logger . warn ( "Logging environment value '" + value
this . logger . warn ( "Logging environment value '" + logConfig
+ "' cannot be opened and will be ignored "
+ "(using default location instead)" ) ;
system . initialize ( ) ;
system . initialize ( null , logFile ) ;
}
}
else {
system . initialize ( ) ;
system . initialize ( null , logFile ) ;
}
}
private String getLogFile ( ConfigurableEnvironment environment ) {
String file = environment . getProperty ( "logging.file" ) ;
String path = environment . getProperty ( "logging.path" ) ;
if ( StringUtils . hasLength ( path ) | | StringUtils . hasLength ( file ) ) {
if ( ! StringUtils . hasLength ( file ) ) {
file = "spring.log" ;
}
if ( ! StringUtils . hasLength ( path ) & & ! file . contains ( "/" ) ) {
path = StringUtils . cleanPath ( System . getProperty ( "java.io.tmpdir" ) ) ;
}
if ( StringUtils . hasLength ( path ) ) {
return StringUtils . applyRelativePath ( path , file ) ;
}
return file ;
}
return null ;
}
private void initializeFinalLoggingLevels ( ConfigurableEnvironment environment ,
LoggingSystem system ) {
if ( this . springBootLogging ! = null ) {
@ -226,7 +182,16 @@ public class LoggingApplicationListener implements SmartApplicationListener {
setLogLevels ( system , environment ) ;
}
public void setLogLevels ( LoggingSystem system , Environment environment ) {
protected void initializeLogLevel ( LoggingSystem system , LogLevel level ) {
List < String > loggers = LOG_LEVEL_LOGGERS . get ( level ) ;
if ( loggers ! = null ) {
for ( String logger : loggers ) {
system . setLogLevel ( logger , level ) ;
}
}
}
protected void setLogLevels ( LoggingSystem system , Environment environment ) {
Map < String , Object > levels = new RelaxedPropertyResolver ( environment )
. getSubProperties ( "logging.level." ) ;
for ( Entry < String , Object > entry : levels . entrySet ( ) ) {
@ -248,15 +213,6 @@ public class LoggingApplicationListener implements SmartApplicationListener {
}
}
protected void initializeLogLevel ( LoggingSystem system , LogLevel level ) {
List < String > loggers = LOG_LEVEL_LOGGERS . get ( level ) ;
if ( loggers ! = null ) {
for ( String logger : loggers ) {
system . setLogLevel ( logger , level ) ;
}
}
}
public void setOrder ( int order ) {
this . order = order ;
}