Tired of messy logging logic cluttering your code with a bunch of if/else statements? Don’t let logging cramp your style! The approach Seam takes to logging makes your code pretty again (and other things). What does this mean for you? No more “code guards“!
A nice byproduct of the genius of Seam’s design is that many common problems can be solved by using EL as veritable swiss-army knife. We’ll look at this through a logging example specifically, though it’s just one of many different innovative ways of solving problems using Java5 features and EL as a general approach.
WTF is a code guard?
What goes without saying in most of the discussions regarding logging is that excessive logging can be the largest and most common performance bottleneck in code that meets its functional requirements. Thus, logging APIs introduce the idea of log levels, to ease the burden of excessive logging. Generally, log levels are a configuration setting on a per-environment basis. Development environments will typically log most dependent code at the info level, and cut that up to the debug level for custom code or when things go awry with a piece of dependent code. Testing environments typically log at info while production will often just log at the warn level.
While this is all well and good, we find that for a lot of the logging we do, we typically run across an ugly little flaw in this approach that’s produced an equally ugly hack as a work-around. Enter the code guard. From the log4j docs:
Code guards are typically used to guard code that only needs to execute in support of logging, that otherwise introduces undesirable runtime overhead in the general case (logging disabled). Examples are multiple parameters, or expressions (e.g. string + ” more”) for parameters. Use the guard methods of the form log.is<Priority>() to verify that logging should be performed, before incurring the overhead of the logging method call. Yes, the logging methods will perform the same check, but only after resolving parameters.
What’s all this business about resolving parameters? Let’s look at an example:
// unguarded code
log.debug("FOO: " + foo + ", BAR: " + foo.getBar());
// guarded code
if (log.isDebugEnabled()) {
log.debug("FOO: " + foo + ", BAR: " + foo.getBar());
}
So, we need this cluttered if/else around only to ensure that our expressions (concats, usually) won’t get resolved unless we actually want them to. Why is there no other recourse? The answer isn’t surprising – it comes down to the way the API was designed. All log4j logging methods take a single argument — which made a lot of sense, I suppose when the powers that be first designed logging APIs. They soon realized that in order to use their API, one has to use an expression to resolve all parameters into a single argument prior to calling the method! This is why a code guard is needed.
Java5 introduces a feature that allows for varargs, and taking advantage of this can help us with our ugly little logging problem, e.g.
log.debug("FOO: #0, BAR: #1", foo, foo.getBar());
With this approach, our expressions won’t get resolved until after we’re in debug(), and we can let it do the dirty work inside the method. The first thing that our logging method does is check to see if its level is valid, otherwise it’ll fall out immediately. Because the concatenation happens inside the log method, we don’t need a code guard to protect us.
This is the approach that Seam takes to logging. Seam’s Log interface provides not only a solution that removes the need for code guards, it also allows you to use EL in your log messages (if you’re trying to dive into a Seam component…) – e.g.
log.debug("FOO: #{foo}, BAR: #{foo.bar}");
Much better. By and large, this is the way you do logging in Seam. Because binding occurs late, you never really run into the problem where you need to even think about using something like a “code guard.” Code what you’re supposed to; not noise! This is just one of many novel ways to use EL in Seam, and why it really deserves a look as a way to write better code, faster and as a far more productive platform for Java programmers (fed up with JavaSE/EE 1.4) than Rails/Grails.
See the Web Beans Manifesto for much more on this approach.