Showing posts with label logging. Show all posts
Showing posts with label logging. Show all posts

Wednesday, June 26, 2013

Dynamically changing a log4j configuration

For most of my career, I've used log4j as my logging back end. Whether during development, testing or production, I've encountered situations where I need to change the log level of a running web app on Tomcat. Restarting the application is often not feasible: either the situation I'm trying to diagnose would be wiped out, or other users would be impacted.  Here's an easy tweak, if you're using Spring, to dynamically change a log4j configuration. With this addition to your web.xml, log4j will pick up any changes you make to your log4j.properties file within 5 seconds:
<listener> 
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
</listener>
<context-param> 
    <param-name>log4jConfigLocation</param-name> 
    <param-value>WEB-INF/classes/log4j.properties</param-value>
</context-param> 
<context-param> 
    <param-name>log4jRefreshInterval</param-name> 
    <param-value>5000</param-value> 
</context-param>
The log4jRefreshInterval parameter is the key. Without that, the log4j configuration won't reload. While this solution is documented separately elsewhere, I wanted to call attention to this tweak because it really deserves wider knowledge.
There are, of course, other possible approaches such as writing your own custom JMX MBean, a custom servlet or using JRebel. These have their own advantages and disadvantages, but I feel the Spring Log4jConfigListener approach is the easiest and most straighforward for a developer.

Friday, September 4, 2009

Logging: should I wrap?

Once upon a time, there was a de facto logging standard, log4j. Then Sun decided to confuse matters by introducing another -- and many say inferior -- logging API in JDK 1.4. Some people responded with Jakarta Commons Logging (JCL), a wrapper that abstracts away these two APIs. Some other people decided that JCL was awful, and wrote SLF4J, a wrapper that abstracts away the first two APIs and JCL. There are also other logging implementations like Logback and x4juli, but fortunately these natively implement the existing APIs so they don't multiply the confusion.

If you start work on an existing project, I suppose you'd use whatever logging API is already in use. If on the other hand you are lucky enough to start a brand new project, you have to choose from a number of logging APIs:
  • log4j
  • JDK Logging
  • JCL
  • SLF4J
The conventional wisdom is that if you are writing a component or library, you'd likely choose one of the wrapper APIs (JCL or SLF4J) since you won't have control over what logging implementation the actual app will use. On the other hand, the conventional wisdom continues, if you are working on a standalone application you might as well code directly to the native APIs since you can pick the logging engine and are unlikely to switch. Even SLF4J's docs say that you needn't bother with SLF4J for standalone applications.

I have joined projects that build J2EE applications almost from scratch, so we got to pick the logging API. My initial inclination was the direct approach: we'd code directly to log4j. After all, why add an unnecessary abstraction? In one project, we ended up using SLF4J, even though we had no intention of switching logging engines. Why? Well, it turns out that SLF4J has a useful feature that log4j does not: parameterized logging. Ordinary logging messages incur the overhead of building the log message even if the message will not be logged at the current log level:

logger.debug("Value of obj#" + i + " = " + obj.toString());

All that work will be wasted if you are logging at the INFO level. The performance penalty could be significant if obj.toString() is particularly heavy. You could wrap that line in an "if (logger.isDebugEnabled()) {...}" block, but that adds clutter. SLF4J lets you defer evaluation of any String conversions until the line is actually written:

logger.debug("Value of obj#{} = {}", i, obj);

Does this minor convenience justify throwing in yet another 3rd party library? We did not need to answer that question. In a substantial app, there is no extra overhead. Quite likely, as in our case, the third party libraries you use will require JCL (e.g., Spring) and SLF4J (e.g., Hibernate) anyway. It's up to you to choose the API for your own logging. For us, SLF4J came along for the ride, gave us the parameterized expressions and still exposed powerful features like Mapped Diagnostic Context (MDC). Where is the downside?

In another project, we coded straight to the log4j API. This project was coded almost entirely in Groovy. In Groovy, we get lazy evaluation for free, so SLF4J offered no API benefits. The Groovy logging code below lazily evaluates its parameters regardless of logging implementation, and more concisely than SLF4J:

logger.debug "Value of obj#${i} = ${obj}"