Logging in Java can be messy. Especially the dreaded isDebugEnabled. Look – a class that calculates something:
import org.slf4j.LoggerFactory;
class SomeCalculator implements Calculator {
private final log = LoggerFactory.getLogger(getClass());
public Result caclulate(Input input) {
if (log.isDebugEnabled()) {
log.debug("Input is " + input);
}
Result result = input.times(64).shift(LEFT);
if (log.isDebugEnabled()) {
log.debug("Result is " + result);
}
return result;
}
}
We have a class which has one line that actually does something and loads of lines that do logging. This is kind of simple, but in more complex cases it really messes your head up.
Now, consider this, in Scala:
class SomeCalculator extends Calculator with Logging {
override def calculate(input:Input) : Result = {
debug("Input is " + input)
val result = input.times(64).shift(LEFT);
debug("Result is " + result)
result
}
}
Why is this possible? Because I’ve made myself a nice little Logging trait, which looks something like this:
package com.supplesoftware.scala.log
import org.slf4j.LoggerFactory
trait Logging {
val log = LoggerFactory.getLogger(getClass)
def debug(msg: => String) = if (log.isDebugEnabled) log.debug(msg)
....
def error(msg: => String, e:Throwable) = if (log.isErrorEnabled) log.error(msg,e)
}
So, as long as I add the logging trait to my Calculator class, I can just say debug(“something”). Note that the argument to debug() will not get evaluated unless it’s necessary – the argument is actually a function, not the actual evaluated string. So doing one isDebugEnabled in the actual Logging trait is fine and does not cause evaluation of the string.
In case that sounds weird, consider the debug method written like this:
def debug(msg: () => String) = if (log.isDebugEnabled) log.debug(msg())
I.e. the argument is not a by-name argument, but an actual function (which I guess is pretty much the same), taking no arguments and returning String. If debug is enabled, the VM will execute that function, to get the result – the log message.
Thanks for the folks at StackOverflow for the great suggestions.
Filed under: programming | 2 Comments
Tags: java, logging, programming, scala
Here’s my BIG quibble with that: the lookup function for the log itself can (probably is) a fairly expensive thing. If you have a ton of object creation, this implementation (even if you use lazy objects) could lead to a huge amount of extra effort, specially if the logging is off (since logging is itself very expensive when it’s on, it won’t matter as much).
The only option (pretty ugly) I’ve found to avoid these lookups per instantiated object is to create a private object to hold the logger on a package level. You could do that on a per-class case, but it becomes even more verbose.
All logging solutions I’ve seen until now seem to be using this, am I the only one that’s raising this question?
Oh, the LoggerFactory.getLogger() you mean?
I would imagine the logging framework (aforementioned LoggerFactory) probably does a fair amount of caching and doesn’t instantiate a new logger every time. Plus, the kind of objects you would instantiate a lot (model classes?) aren’t that fussed about logging.
I guess the only way to find out is to profile it…