in trying to fix a bug where toBriefXML was creating a giant string bigger than the JVM would allow, I said to myself.... why is it that when we're running a junit test, it's calling toBriefXML anyway?
Turns out the code is:
log(LogLevel.Debug, "This is %s", toString)
Now, the def log uses a varargs, and that means the toString will be evaluated (no by-name passing of varargs in scala), and someplace else we have
override def toString = toBriefXML(...)
We really want the arguments to log to be passed by name, so if the log-level isn't reached, then the arguments aren't evaluated.
So shortest-of-short-terms, log(....) calls that have expensive arguments should be rewritten as:
log(LogLevel.Debug, "This is %s", Seq(toString))
That version of log(...) takes an explicit sequence as the last arg, and so this is passed by-name and so not evaluated unless the log level is met.
But, really, what we want is a MACRO that expands into an if-then and only takes the branch if the log level check passes. That way we avoid not only evaluating the arguments, but allocating closures, etc. We also get to have varargs syntax back.
So, scala 2.10 has some truly-horrible Macro stuff. But we can likely use it black-box.
mentions "Scala Logging" and "log4s" both of which use macros. I checked and at least log4s has a 2.10 compatible version.
(If you want to see how horrible scala 2.10 macros are, just look at the source code for the 2.10 version of log4s.... What were they thinking? Anyway, macros are better in 2.11 (somewhat), and even more-so in 2.12 I am told.)