Friday, June 1, 2007

JBoss and Log4j

JBoss and Log4j come together will make the stupid things. JBoss make all logs of user application come to its log file and prohibit the user using trace log. It is terrible. In my project, i have to define my own log file which separated with the system log. But this task take me 2 days. What a terrible. Now i find 2 solution.
First one: Remove all the trace log and define new appender and category in log4j.xml in folder conf of jboss. It will make the log of application come to new place.
Seconde one:
Using RepositorySelector with ServletListener or Listener to use your own log. As my research in internet, i found that this is the clean solution of separate logger with jboss logger.
All you need for the second solution is:

  1. Log4j.jar in WEB-INF.
  2. Your own lof4j.xml file( you can mimic the log4j.xml of jboss)
  3. 2 file followings.
  4. Configure web.xml to ensure servlet or servlet listener to run first to make log initialize or you will get error.

/***************************************
* *
* JBoss: The OpenSource J2EE WebOS *
* *
* Distributable under LGPL license. *
* See terms of license at gnu.org. *
* *
***************************************/

package org.jboss.repositoryselectorexample;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Hierarchy;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.RepositorySelector;
import org.apache.log4j.spi.RootCategory;
import org.apache.log4j.xml.DOMConfigurator;
import org.w3c.dom.Document;

/**
* This RepositorySelector is for use with web applications. It assumes that
* your log4j.xml file is in the WEB-INF directory.
*
* @author Stan Silvert
*/
public class MyRepositorySelector implements RepositorySelector
{
private static boolean initialized = false;
private static Object guard = LogManager.getRootLogger();

private static Map repositories = new HashMap();
private static LoggerRepository defaultRepository;

/**
* Register your web-app with this repository selector.
*/
public static synchronized void init(ServletConfig config)
throws ServletException {
if( !initialized ) // set the global RepositorySelector
{
defaultRepository = LogManager.getLoggerRepository();
RepositorySelector theSelector = new MyRepositorySelector();
LogManager.setRepositorySelector(theSelector, guard);
initialized = true;
}

Hierarchy hierarchy = new Hierarchy(new RootCategory(Level.DEBUG));
loadLog4JConfig(config, 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(ServletConfig config,
Hierarchy hierarchy)
throws ServletException {
try {
String log4jFile = "/WEB-INF/log4j.xml";
InputStream log4JConfig =
config.getServletContext().getResourceAsStream(log4jFile);
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(log4JConfig);
DOMConfigurator conf = new DOMConfigurator();
conf.doConfigure(doc.getDocumentElement(), hierarchy);
} catch (Exception e) {
throw new ServletException(e);
}
}

private MyRepositorySelector() {
}

public LoggerRepository getLoggerRepository() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
LoggerRepository repository = (LoggerRepository)repositories.get(loader);

if (repository == null) {
return defaultRepository;
} else {
return repository;
}
}
}

/***************************************
* *
* JBoss: The OpenSource J2EE WebOS *
* *
* Distributable under LGPL license. *
* See terms of license at gnu.org. *
* *
***************************************/

package org.jboss.repositoryselectorexample;

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
* This servlet demonstrates initialization of a RepositorySelector so that
* logging can be done on a per-app basis.
*
* @author Stan Silvert
*/
public class Log4JServlet extends HttpServlet {

private static Logger LOG;

private String servletName;
private MyObject myObj; // can't initialize until init() method called

/** Initializes the servlet.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.servletName = config.getServletName();


MyRepositorySelector.init(config);

// note that we can't call Logger.getLogger() until
// MyRepositorySelector.init() is called. For all other classes in the
// webapp, you can call Logger.getLogger() at any time.
this.LOG = Logger.getLogger(Log4JServlet.class);

// the same goes for the Logger.getLogger() method in MyObject
this.myObj = new MyObject(this.servletName);
}

/** Destroys the servlet.
*/
public void destroy() {
MyRepositorySelector.removeFromRepository();
}

/**
* Processes requests for both HTTP GET and POST
* methods.
* @param request servlet request
* @param response servlet response
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/*");
PrintWriter out = response.getWriter();

LOG.error("TEST FROM THE SERVLET: " + this.servletName);
myObj.foo();
out.println("");
out.close();
}

/** Handles the HTTP GET method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/** Handles the HTTP POST method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Log4JServlet";
}

}


/***************************************
* *
* JBoss: The OpenSource J2EE WebOS *
* *
* Distributable under LGPL license. *
* See terms of license at gnu.org. *
* *
***************************************/

package org.jboss.repositoryselectorexample;

import org.apache.log4j.Logger;

/**
* This just shows another object besides the servlet within the same
* web app.
*
* @author Stan Silvert
*/
public class MyObject {

// note that this can not be static because MyObject is referenced in
// the servlet before the RepositorySelector is initialized. For other
// classes, it would be OK to make this static.
private final Logger LOG = Logger.getLogger(MyObject.class);

private String servletName;

public MyObject(String servletName) {
this.servletName = servletName;
}
public void foo() {
LOG.info("Message from MyObject: " + this.servletName);
}
}

2 comments:

A. Rizzato said...

I tried the solution you presented in your article (the 2nd one) but it still show the same problem showed at http://wiki.jboss.org/wiki/Wiki.jsp?page=Log4jConflictsInJBoss : which release of JBoss did you refer?

CABA LAM said...

I've tried JBoss 4.04 GA.

Google