Platinum Partner
java,log4j,jmx,java spring framework

Non-Stop Control of Logging Level

Sometimes there is a need to change the logging level in the some modules of an application server. This usually isn't managed easily: the change the logging level means a restart of the server in most cases. This is not always required, but is in most cases.

The restart of one application server in production operation is not really good idea. But if the application server or one its module doesn't operate correctly it is very useful to obtain the log file with debug logging-level. As the logging will usually be performed in INFO or ERROR level to save the unnecessary I/O operations and CPU overhead, with such logging levels it is very hard to analyse the problem. So, what have we do?

If the application server runs under JVM 1.5 or higher and uses the Spring framework there is one logical way to painlessly change the logging level: use a Java Management Extension.

Step 1: Create a bean with a logic to change the logging level.

For a simplicity, we change the level of the root logger only. The class needs two methods: get logging level for root logger and a method to set that level. The Logging framework used here is the popular log4j logger. The functionality is almost the same as other useful loggers. Every logger created exists only in a single instance, so you can call getRootLogger() method as often as you want without the problem of having many root-logger instances. To make our code compact I am using the annotations. It allows me to keep the code with a static data definitions, such as method description. The use of annotations is a tool, but not the objective. You can also achieve your aim  without annotations.

 @ManagedResource(objectName="Custom:type=Management,name="Log4j Logging", description="Log4j Managed Bean")
public class Log4jMBean
{
@ManagedAttribute(description="get the logging level to the root logger")
public String getRootLogLevel()
{
Logger root = Logger.getRootLogger();
Level level = root.getLevel();
return level;
}

@ManagedAttribute(description="set the new logging level to the root logger")
public void setRootLogLevel(String newLevel)
{
Logger root = Logger.getRootLogger();
Level level = Level.toLevel(newLevel);
root.setLevel(level);
}
}

There is no error checking, package or import statements in code. That class is simply a Java bean class with the spring-jmx annotations

Step 2: Load and register the logic.

The bean alone is not enough. Something must load that bean and allow remote access to it. Spring is the best choice here. We need a applicationContext-logcontrol.xml with some lines of code. That code informs Spring about  Log4jMBean and also says that this bean must be registered in the MBeanServer.

<config:annotation-config />
<context:mbean-export default-domain="Custom" registration="ignoreExisting" />
<bean id="log4jBean" class="my.company.jmx.Log4jMBean" />

That is all the code! Some explanation:
  • First line - says to the Spring framework that the code contains some annotations
  • Second line - calls the Spring mbean exporter and tells it to ignore our beans that are already registered in the MBeanServer
  • Third line - declares the bean to load within the Spring framework

I have missed the namespaces declaration. These have to be declared the context namespace.
Compile and package the two files to an JAR file. Place the xml file in a subdirectory, for example "conf".

Step 3: Use the package with Spring framework

Now the application server must use our library. Place your package on the classpath, for example WEB-INF/lib directory of the application. Place a line in one of Spring context xml files of the web application with the logging level you want to control.

That allows to load your Log4jMBean class and perform the registration of their instance at MBeanServer, wenn the web application starts up. The Spring framework automatically looks into the jar files in WEB-INF/lib directory and search for applicationContext-logcontrol.xml file. The access to the bean will be performed by JMX. By default, there is no activated JMX feature on a  JVM of version 1.5+, but you can activate it by means of set the command-line parameters for JVM. For example, the environment variable "JAVA_OPTS" allows to set any command-line parameters for Tomcat server.

The simpliest way to activate the access to MBeanServer is to start the JVM with such parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=XXXX
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

where, the XXXX is an unused port of the system. The JavaVM activates MBeanServer and listens the port XXXX for incoming JMX connections.

Now, you can connect with the jconsole.exe programme from the JDK 1.5+ installation directory of your server, choose the page and look for the actual loggers and their logging-levels.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}