[slf4j-user] Per-web-app logging with jars on the server's classpath

Mark Stralka mstralka at gmail.com
Tue Mar 13 12:15:55 CET 2007


Jacob Kjome <hoju <at> visi.com> writes:

> 
> 
> It doesn't much matter what the config file looks like, but what your 
> custom repository selector is doing.  Clearly it isn't working, 
> otherwise you'd have separate logger repositories and no cross-talk 
> between application-specific logger repositories.  So, what does your 
> implementation look like?  How it the repository selector 
> installed?.  How are you configuring each repository?  Where are your 
> config files?  Where's Log4j?
> 
> Jake
> 
> At 06:59 PM 3/12/2007, you wrote:
>  >We have a custom web framework packaged into a jar file 
> (myframework.jar) that
>  >is used by 50 web applications deployed as WAR files on Weblogic 8.1 SP4.
>  >myframework.jar uses the Spring framework internally (which uses commons
>  >logging API), so we must continue to use SLF4J's jcl104-over-slf4j-1.3.0.jar
>  >for the foreseeable future.  None of these web apps use EJBs and I want to
>  >avoid them.
>  >
>  >myframework.jar, log4j.jar, slf4j*.jar spring.jar, and dozens of other 3rd
>  >party dependencies are loaded on Weblogic's server classpath.
>  >myframework.jar is under continual development by my team and we can't
>  >redeploy every WAR file with the new version of libraries in WEB-INF/lib -
>  >so we have to load myframework and other JARs on weblogic's classpath.
>  >Each web app has very few Java classes of its own - most are Spring-injected
>  >from myframework.jar.
>  >
>  >This has proven to be an interesting puzzle because we want each web app to
>  >write to its own log file (appA.log, appB.log, etc), but be able to record
>  >log entries from classes inside myframework.jar, spring.jar, etc for
>  >debugging purposes.
>  >
>  >I bought the Log4J book, read Chapter 8, and followed the JBoss instructions
>  >here http://wiki.jboss.org/wiki/Wiki.jsp?page=Log4jRepositorySelector
>  >to create a custom RepositorySelector (which loads 
> /WEB-INF/log4j.properties),
>  >and modified myframework's StartupListener to initialize this
>  >RepositorySelector in each web app's web.xml.
>  >
>  >The problem is that when I start weblogic with several webapps (appA.war,
>  >appB.war, appC.war, etc), all log entries are written to appA.log, even
>  >though each application has its own WEB-INF/log4j.properties (albeit they
>  >are currently all the same, except for the "log4j.appender.file.File" value).
>  >
>  >Am I doing something wrong to keep JAR files at the server level but let
>  >each web app write to its own log file?  Thank you
>  >
>  >Here is appA's log4j.properties file:
>  >log4j.rootLogger=warn, file
>  >
>  >### direct messages to file <app name>.log ###
>  >log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
>  >log4j.appender.file.DatePattern='.'yyyy-MM-dd
>  >#Each app should go to its own log file but they are not
>  >log4j.appender.file.File=c:/logs/appA.log
>  >log4j.appender.file.layout=org.apache.log4j.PatternLayout
>  >log4j.appender.file.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss,SSS}
>  >%5p %C{1} - %m%n
>  >
>  >log4j.logger.org.apache.struts=error
>  >log4j.logger.org.apache.commons=error
>  >log4j.logger.org.apache.jcs=error
>  >log4j.logger.org.springframework=error
>  >log4j.logger.org.hibernate=error
>  >log4j.logger.org.acegisecurity=error
>  >
>  >#Make sure you turn logging off before deploying to staging or production.
>  >log4j.logger.com.myframework.core=debug
>  >
>  >_______________________________________________
>  >user mailing list
>  >user <at> slf4j.org
>  >http://www.slf4j.org/mailman/listinfo/user
> 


public class JbossAppRepositorySelector implements RepositorySelector {
	private static boolean initialized = false;
	private static Object guard = LogManager.getRootLogger();
	private static Map repositories = new HashMap();
	private static LoggerRepository defaultRepository;

	public static synchronized void init(ServletConfig servletConfig)
	throws ServletException {
		init(servletConfig.getServletContext());
	}

	public static synchronized void init(ServletContext servletContext)
	throws ServletException {
		if (!initialized) // set the global RepositorySelector
		{
			defaultRepository = LogManager.getLoggerRepository();
			RepositorySelector theSelector = new JbossAppRepositorySelector();
			LogManager.setRepositorySelector(theSelector, guard);
			initialized = true;
		}

		Hierarchy hierarchy = new Hierarchy(new RootCategory(Level.DEBUG));
		loadLog4JConfig(servletContext, hierarchy);
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		repositories.put(loader, hierarchy);
	}

	public static synchronized void removeFromRepository() {
		repositories.remove(Thread.currentThread().getContextClassLoader());
	}

	// load log4j.xml from WEB-INF
	private static void loadLog4JConfig(ServletContext servletContext,
		Hierarchy hierarchy) throws ServletException {
		String log4jFile = null;
		InputStream log4JConfig = null;
		Properties properties = new Properties();
		PropertyConfigurator conf = new PropertyConfigurator();
		try {
			log4jFile = "/WEB-INF/log4j_webapp.properties";
			log4JConfig = servletContext.getResourceAsStream(log4jFile);
			properties.load(log4JConfig);
			conf.doConfigure(properties, hierarchy);
		} catch (Exception e) {
			throw new ServletException(e);
		}
	}

	private JbossAppRepositorySelector() {
	}

	public LoggerRepository getLoggerRepository() {
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		LoggerRepository repository = (LoggerRepository) repositories.get(loader);
		if (repository == null) {
			return defaultRepository;
		} else {
			return repository;
		}
	}
}


com.myframework.web.StartupListener:
public void contextInitialized(ServletContextEvent event) {
	...
	JbossAppRepositorySelector.init(event.getServletContext());
	...
}




More information about the slf4j-user mailing list