LogbackServletContextListener.java
package com.ziesemer.logging;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
/**
* @author Mark A. Ziesemer
* <a href="http://www.ziesemer.com"><www.ziesemer.com></a>
*/
public class LogbackServletContextListener implements ServletContextListener{
protected static final Logger LOGGER = LoggerFactory.getLogger(LogbackServletContextListener.class);
@Override
public void contextInitialized(final ServletContextEvent sce){
final ServletContext sc = sce.getServletContext();
final String appName = sc.getContextPath();
// http://jira.qos.ch/browse/LOGBACK-764
final LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
context.reset();
if(!appName.isEmpty()){
context.setName(appName);
}
boolean configured = false;
final ContextInitializer ci = new ContextInitializer(context);
try{
final JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
// These first entries effectively override the design of the "logback.xml" vs. "logback-test.xml" bit -
// but the same goal can be accomplished by including the same path on both a "main" and a "test" classpath,
// ensuring both are on the path of the same classloader (level), but with the "test" path coming before "main".
// This is the default in Maven builds, for example.
InputStream is = getClass().getResourceAsStream("/com/ziesemer/logging/contexts/" + appName + "/logback.xml");
if(is == null){
is = getClass().getResourceAsStream("/com/ziesemer/logging/logback.xml");
if(is == null){
final URL url = ci.findURLOfDefaultConfigurationFile(true);
if(url != null){
ci.configureByResource(url);
configured = true;
}else{
// Using standard parent-first classloading, this can be placed within the container to override,
// or fall-back to the copy embedded within this logging library.
is = getClass().getResourceAsStream("/com/ziesemer/logging/logback-default.xml");
}
}
}
if(is != null){
try{
configurator.doConfigure(is);
configured = true;
}finally{
is.close();
}
}
// This should never happen, as this logging library itself should be packaged with the above "logback.xml".
if(!configured){
new BasicConfigurator().configure(context);
}
// Allow the application to append additional configurations from within the package
// (likely, instead of using the default "logback.xml"):
is = getClass().getResourceAsStream("/com/ziesemer/logging/logback-append.xml");
if(is != null){
try{
configurator.doConfigure(is);
}finally{
is.close();
}
}
is = getClass().getResourceAsStream("/com/ziesemer/logging/contexts/" + appName + "/logback-append.xml");
if(is != null){
try{
configurator.doConfigure(is);
}finally{
is.close();
}
}
// Allow the container to append append additional configurations (used globally):
is = getClass().getResourceAsStream("/com/ziesemer/logging/logback-container-append.xml");
if(is != null){
try{
configurator.doConfigure(is);
}finally{
is.close();
}
}
}catch(final JoranException je){
// StatusPrinter will handle this
}catch(final IOException ioe){
LOGGER.error(ioe.toString(), ioe);
}
StatusPrinter.printInCaseOfErrorsOrWarnings(context);
LOGGER.info("Context initialized.");
}
@Override
public void contextDestroyed(final ServletContextEvent sce){
LOGGER.info("Destroying context...");
final LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
context.stop();
}
}