RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Set the Logging Level Over a Tomcat Cluster Dynamically : Page 2

Rather than modifying your Log4J configuration and then redeploying the correct code version with the modified logging level, you can dynamically set the Log4J logging level over each node in a Tomcat cluster with JMX.


A Log4J MBean for Each Log4J Configuration

Although this technique seems simple, if your Tomcat cluster hosts a number of Web applications—each with its own Log4J configuration that allows it to log to a separate log file—then you will run into your first problem. Given multiple Log4J configurations, only the first one loaded by the JVM will have a root logger MBean associated with it. The reason for this is Log4J hard-codes the JMX Domain that it uses when registering its MBeans as log4j, and the JMX server doesn't allow duplicate names.

The way round this is to leave a Tomcat server Log4J configuration (jars under server/lib and property files under server/classes) registered under the default Log4J name log4j:logger=root. Then register the root logger for each Web application in a startup servlet, using the Web application name to identify the domain:

public class RegisterLog4JMBeanServlet extends HttpServlet {

    private static final Log log = LogFactory.getLog(RegisterLog4JMBeanServlet.class);

    public void init(ServletConfig servletConfig) 
            throws ServletException {
        ServletContext context = servletConfig.getServletContext();
        String webappName = context.getServletContextName();
        Hashtable<String, String> nameParameters = new Hashtable<String, String>();
        nameParameters.put("logger", "root");

        Logger rootLogger = LogManager.getRootLogger();
        LoggerDynamicMBean mbean = new LoggerDynamicMBean(rootLogger);
        List list = MBeanServerFactory.findMBeanServer(null);
        MBeanServer server  = (MBeanServer)list.iterator().next();

        ObjectName objectName = null;
        try {
            objectName = new ObjectName(webappName, nameParameters);
            server.registerMBean(mbean, objectName);
        } catch (Exception e) {
            log.error("Problems registering Log4J MBean", e);

You will end up with an MBean named <web-app-name>: logger=root for each Web application. The webappName is retrieved from the <display-name> element in your application's web.xml file, and the application's root logger is retrieved by calling LogManager.getRootLogger(). Then you can use the LoggerDynamicMBean class from Log4J to create your MBean from the root logger definition.

To create a distinct ObjectName for the new MBean, you should use the Web application name as the JMX domain (this is the text before the colon) and then register the Root Logger MBean with the new ObjectName. This will guard against conflicts with other Log4J MBeans.

Now that you have registered your Root Logger under a different domain, you must modify the servlet that sets the logging level. So in SetLog4JlevelServlet, change this:

ObjectName objectName = new ObjectName("log4j:logger=root");

To this:

ServletContext context = servletConfig.getServletContext();
String webappName = context.getServletContextName();
Hashtable<String, String> nameParameters = new Hashtable<String, String>();
nameParameters.put("logger", "root");
ObjectName objectName = new ObjectName(webappName, nameParameters);

When setting up your Log4J configuration, give your Log4J appenders unique names. Otherwise, they will not get registered to the JMX server and you will get lots of the following errors in your log files at startup:

ERROR main org.apache.log4j.jmx.LoggerDynamicMBean ? - Could not add appenderMBean for [<appender_name>].
javax.management.InstanceAlreadyExistsException: log4j:appender=<appender_name>

Again, the reason for this is because the JMX domain name his hard-coded to log4j, so if you have repeated appender names then only the first of these will be registered.

At this point, configuring the MX4J HTTP adaptor in your Tomcat server might be useful. This will give you a visual representation of the MBeans you are creating and manipulating, and show you what else is exposed via MBeans within Tomcat. To do this, you must put the mx4j-tools.jar file (download it at mx4j.sourceforge.net) in your common/lib directory. Then configure your server.xml file to set up the connector as follows:

    <Connector port="8010" 

When you start your server, you will be able to access the MX4J HTTP connector through your browser at http://localhost:8013, assuming you have no other Tomcat connector running on port 8010.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date