Don’t clutter your code with isDebugEnabled
Tuesday, June 09th, 2009 | Author: FoX
The main function of a good logging implementation is to provide a clear overview of the functioning of a system. Basically, the logging must describe the inner workings of a system and provide the necessary details to the readers of the log. In fact, good logging can drastically reduce maintenance costs of your applications, especially for clustered systems.
Logging is a crucial part of every system and provides all the information about the state of a system. The key is to provide this information without cluttering the code too much with these logging statements.
Most programmers tend to use a decent logging mechanism in their applications, but few of them use it elegantly. How can we make sure that we don’t clutter our code with unnecessary statements that reduce readability?
The worst type of logging is, of course, the usage of System.out.println’s in your code. You will have no fine grained control over your log statements and all statements will be directly written to the standard output. Stop this madness and use a proper logging mechanism! No excuse will be good enough! Really, I’m not kidding here..
Log4j to the rescue?
Most developers noticed this issue and started to use a decent logging mechanism, like Log4j, taking control over their log statements. The main problem is that developers could decrease performance of the system by not using the log API correctly (e.g. concatenating all strings in the log statement, even when the log statement is disabled). It would be better to not use any expensive operations in your log statements, of course, but that’s not really a real option.

Be aware that the log level could be inactive in some cases (e.g. debug logging should not be enabled in a production environment) and that you make proper use of the log categories.
What you could do is checking the log level before putting in some expensive operations. The point of isDebugEnabled() is to save loops and temporary object creation for debug purposes, when you have no need for the debug log. But you will eventually create more clutter in your code when you’ll use this statement all over the place.
Don’t clutter your code with isDebugEnabled statements when you’ve other options to use! You can avoid this cluttering by simply making use of the standard Java JDK 5.0 String formatting feature or by using a more advanced approach with the slf4j logging abstraction.
The solution
We can enhance our code base with proper log statement and minimal overhead by using slf4j. The slf4j framework can be used as a simple abstraction on many logging systems and therefore provide some nice mechanisms to improve your code base.

Slf4j can be used by specifying the slf4j logger in your code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
Logger logger = LoggerFactory.getLogger(ClassToBeLogged.class);
Log4J with the isDebugEnabled check
if (logger.isDebugEnabled()) {
logger.debug("The size is '" + list.size() +
"', for '" + user.getUsername() + "'.");
}
SLF4J logging
logger.debug("The size is '{}', for '{}'.", list.size(), user.getName());
JDK 5.0 logging
logger.log(Level.FINE, "The size is '{0}', for '{1}'.", new Object[]{list.size(), user.getName()});
Which statement do you prefer?
Note that this is even the most simple example that I could come up with.
I’m aware that the Java JIT compiler is intelligent enough to optimize some of your code in certain cases so that operations will be optimized before the real execution of the application. E.g. the following two statements will produce the exact same byte code:
log.debug("Start of debug logging.");
and
log.debug("Start " + "of " + "debug " + "logging " + ".");
But it is nevertheless better to watch out and don’t do anything stupid!


Tuesday, 9. June 2009
JDK logging does not support printf-style format strings, but java.text.MessageFormat style formatting. I am afraid the JDK 1.5 version would look more like:
logger.log(Level.INFO, “The size is {0}, for {1}”, new Object[]{list.size(), user.getName()});
Tuesday, 9. June 2009
the problem is that log4j is standard and its hard to change any standard. i think not many people know about slf4j. I think the name does help it making it not popular.
Tuesday, 9. June 2009
Regarding the case :
logger.debug(String.format(“The size is ‘%s’, for ‘%s’.”, list.size(), user.getName()));
Doesn’t this suffer from the same problem that normal log4j logging suffers from? The String.format method will be always be executed regardless of what the debug level is.
Tuesday, 9. June 2009
@Ceki, @Bhima: You are correct, I’ve changed the examples to be more trustworthy.
Tuesday, 9. June 2009
On a performance critical path it is still better to write:
if(logger.isDebugEnabled()) {
logger.debug(“The size is ‘{}’, for ‘{}’.”, list.size(), user.getName());
}
because call to the log method is going to be more expensive.
Tuesday, 9. June 2009
But list.size() and user.getName() will still be called: trivial in this case, but if they were expensive you’d *still* have to wrap it in an isDebugEnabled().
Tuesday, 9. June 2009
@Eugene: The performance aspect of the log method is ignorable in this case, but the size() method would still be called. I guess making the examples more realistic would be better. Let’s say we would like to add some logging for auditing reasons, like the following statement:
logger.debug("User '{}' altered entity '{}' on {}.", user, entity, date);The
toString()of the objects won’t be called in this case and the code will be more readable than using theisDebugEnabled()construction.Tuesday, 9. June 2009
FoX, like I said, in some cases it won’t be ignorable. I am quite certain that isDebugEnabled() call can be inlined by the hotspot compiler, while debug() call will be too large to inline, hence cause the overhead.
Tuesday, 9. June 2009
Or, you can just set the Log4J config to not log at the debug level, but rather at a higher level. IIRC, you can define your own levels – but I haven’t tried that.
Wednesday, 10. June 2009
The question to me is, do we really have a performance problem if the skip the if statement? The JVM optimization features and the faster processors let me tend to skip it for a better readability of the code.
Wednesday, 10. June 2009
Without isDebungEnabled() code may look prettier but you have to pay the performance price. isDebugEnabled() takes far less time then a String construction for logging.
Wednesday, 10. June 2009
That’s really the point in using the slf4j api, you don’t have to concatenate
Strings unnecessarily.I’ve performed some tests on the different approaches and it is clear that the overhead of using the slf4j API is minimal. Slf4j is only 16% slower than the
isDebugEnabledapproach when debug logging is turned off (Plain Log4J is about +15000% slower), so we are talking about a performance penalty of only 0,11ms on 1000 log statements. When debug logging is turned on, the slf4j approach is only 6.50% slower than usingisDebugEnabled.I’d choose for cleaner code and better readability than this minor performance impact. There are other points to worry about concerning performance, like database, business logic, sorting, pagination, etc.