diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/LoggingApplicationContextInitializer.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/LoggingApplicationContextInitializer.java new file mode 100644 index 00000000000..bfe4f91f52d --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/LoggingApplicationContextInitializer.java @@ -0,0 +1,221 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.bootstrap.context.initializer; + +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.bootstrap.logging.JavaLoggerConfigurer; +import org.springframework.bootstrap.logging.LogbackConfigurer; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.ClassUtils; +import org.springframework.util.Log4jConfigurer; + +/** + * An {@link ApplicationContextInitializer} that configures a logging framework depending + * on what it finds on the classpath and in the {@link Environment}. If the environment + * contains a property logging.config 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 + * java.util.logging will be used.

+ * + *

+ * The default config locations are classpath:log4j.properties or + * classpath:log4j.xml for log4j; classpath:logback.xml for + * logback; and classpath:logging.properties for + * java.util.logging. 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 LoggingApplicationContextInitializer}. + *

+ * + *

+ * 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): + *

+ * + * @author Dave Syer + * @author Phillip Webb + */ +public class LoggingApplicationContextInitializer implements + ApplicationContextInitializer, Ordered { + + private static final Map ENVIRONMENT_SYSTEM_PROPERTY_MAPPING; + static { + ENVIRONMENT_SYSTEM_PROPERTY_MAPPING = new HashMap(); + ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("logging.file", "LOG_FILE"); + ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("logging.path", "LOG_PATH"); + ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("PID", "PID"); + } + + private int order = Integer.MIN_VALUE + 1; + + /** + * Initialize the logging system according to preferences expressed through the + * {@link Environment} and the classpath. + */ + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + + ConfigurableEnvironment environment = applicationContext.getEnvironment(); + + for (Map.Entry mapping : ENVIRONMENT_SYSTEM_PROPERTY_MAPPING + .entrySet()) { + if (environment.containsProperty(mapping.getKey())) { + System.setProperty(mapping.getValue(), + environment.getProperty(mapping.getKey())); + } + } + + if (System.getProperty("PID") == null) { + System.setProperty("PID", getPid()); + } + + LoggingSystem system = LoggingSystem.get(applicationContext.getClassLoader()); + system.init(applicationContext); + } + + private String getPid() { + String name = ManagementFactory.getRuntimeMXBean().getName(); + if (name != null) { + return name.split("@")[0]; + } + return "????"; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; + } + + private static enum LoggingSystem { + + /** + * Log4J + */ + LOG4J("org.apache.log4j.PropertyConfigurator", "log4j.xml", "log4j.properties") { + + @Override + protected void doInit(ApplicationContext applicationContext, + String configLocation) throws Exception { + Log4jConfigurer.initLogging(configLocation); + } + }, + + /** + * Logback + */ + LOGBACK("ch.qos.logback.core.Appender", "logback.xml") { + + @Override + protected void doInit(ApplicationContext applicationContext, + String configLocation) throws Exception { + LogbackConfigurer.initLogging(configLocation); + } + }, + + /** + * Java Util Logging + */ + JAVA(null, "logging.properties") { + + @Override + protected void doInit(ApplicationContext applicationContext, + String configLocation) throws Exception { + JavaLoggerConfigurer.initLogging(configLocation); + } + }; + + private final String className; + + private final String[] paths; + + private LoggingSystem(String className, String... paths) { + this.className = className; + this.paths = paths; + } + + public void init(ApplicationContext applicationContext) { + String configLocation = getConfigLocation(applicationContext); + try { + doInit(applicationContext, configLocation); + } catch (RuntimeException ex) { + throw ex; + } catch (Exception ex) { + throw new IllegalStateException("Cannot initialize logging from " + + configLocation, ex); + } + + } + + protected abstract void doInit(ApplicationContext applicationContext, + String configLocation) throws Exception; + + private String getConfigLocation(ApplicationContext applicationContext) { + Environment environment = applicationContext.getEnvironment(); + ClassLoader classLoader = applicationContext.getClassLoader(); + + // User specified config + if (environment.containsProperty("logging.config")) { + return environment.getProperty("logging.config"); + } + + // Common patterns + for (String path : this.paths) { + ClassPathResource resource = new ClassPathResource(path, classLoader); + if (resource.exists()) { + return "classpath:" + path; + } + } + + // Fallback to the default + String defaultPath = ClassUtils.getPackageName(JavaLoggerConfigurer.class); + defaultPath = defaultPath.replace(".", "/"); + defaultPath = defaultPath + "/" + this.paths[this.paths.length - 1]; + return "classpath:" + defaultPath; + } + + public static LoggingSystem get(ClassLoader classLoader) { + for (LoggingSystem loggingSystem : values()) { + String className = loggingSystem.className; + if (className == null || ClassUtils.isPresent(className, classLoader)) { + return loggingSystem; + } + } + return JAVA; + } + + } + +} diff --git a/spring-bootstrap/src/main/resources/META-INF/spring.factories b/spring-bootstrap/src/main/resources/META-INF/spring.factories index e03d6f831d1..7cc6c2e41f0 100644 --- a/spring-bootstrap/src/main/resources/META-INF/spring.factories +++ b/spring-bootstrap/src/main/resources/META-INF/spring.factories @@ -2,7 +2,7 @@ org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\ org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.MessageSourceAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ @@ -12,5 +12,5 @@ org.springframework.bootstrap.autoconfigure.web.EmbeddedTomcatAutoConfiguration, org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration org.springframework.context.ApplicationContextInitializer=\ org.springframework.bootstrap.context.initializer.ConfigFileApplicationContextInitializer,\ -org.springframework.bootstrap.context.initializer.LoggingInitializer,\ +org.springframework.bootstrap.context.initializer.LoggingApplicationContextInitializer,\ org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer \ No newline at end of file diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/logging/LoggingInitializerTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/logging/LoggingInitializerTests.java index a3277270682..1f9e64e4a74 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/logging/LoggingInitializerTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/logging/LoggingInitializerTests.java @@ -23,7 +23,7 @@ import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.springframework.bootstrap.context.initializer.LoggingInitializer; +import org.springframework.bootstrap.context.initializer.LoggingApplicationContextInitializer; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.PropertySource; @@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue; */ public class LoggingInitializerTests { - private LoggingInitializer initializer = new LoggingInitializer(); + private LoggingApplicationContextInitializer initializer = new LoggingApplicationContextInitializer(); private PrintStream savedOutput; private ByteArrayOutputStream output;