Change log4j logging level at runtime using JMX/Spring
Monitoring application servers is a daunting task. Without the right instrumentation of your code it is even impossible. I try to use log4j as much as possible and in general I’m very generous regarding logging levels. But occasionally the console just gets flooded with logging output. Typically then I would modify the logging configuration files and restart the server which may be very time consuming and unnecessary.
In the past I had used JMX to switch logging levels at runtime for various projects. The first time now I have tried this with the Spring framework and it worked like a charm (did you expect anything else). I’m making the solution public in case I need this for future projects and to document the steps required!
First, a bean is required that uses the logging API (here log4j) to manage the logging level.
/*
* Copyright 2002-2008 Martin Ahrer.
*
* $Id$
*/
package at.martinahrer.blueprint.log4j;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;
/**
* @author Martin Ahrer
*
*/
@ManagedResource(objectName = "at.martinahrer.blueprint.log4j:name=Logging", description = "Logging", log = true, logFile = "jmx.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200, persistLocation = "logging", persistName = "logging")
public class Logging {
@ManagedOperation(description = "Set the logging level for a category")
@ManagedOperationParameters( { @ManagedOperationParameter(name = "category", description = "Logger category"),
@ManagedOperationParameter(name = "level", description = "Logging level") })
public void setLoggerLevel(String category, String level) {
LogManager.getLogger(category).setLevel(Level.toLevel(level));
}
@ManagedOperation(description = "Get the logging level for a category")
@ManagedOperationParameters( { @ManagedOperationParameter(name = "category", description = "Logger category") })
public String getLoggerLevel(String category) {
return LogManager.getLogger(category).getLevel().toString();
}
}
It’s been annotated with Spring JMX annotations to provide JMX meta data. Next, we need to export the bean as a JMX Bean. This is supported very well by the Springframework’s MBeanExporter.
Finally to connect to the MBeanServer using jconsole the JVM (running the MBean) must be started with the system property -Dcom.sun.management.jmxremote set.

2 Comments
hualro - 2012/03/01
Hi,
First off thanks for the post very informative, although I was able to build a test web app following your example I could not see the exposed mbean under the MBeans tab on jconsole I am new to JMX so probably I’m missing something. I expected to see the Logging object on the MBeans tab.
My Env:
Spring 2.5.6.SEC02
Tomcat 6.0.18 (started with jmx vm args)
Thanks!
hualro - 2012/03/01
Please disregard the comment above, I was starting tomcat with more args which were problematic. It works like a charm now Thanks!