Can somebody explain why this code works in that way? I wanted to make my own proof of concept Loggable trait. The plan was to instantiate a logger instance in order that inherited classes do not have to do that work. But as I can see this is not what I wanted.
Here is the code:
package hu.jonas.simple
trait Loggable {
val logger = java.util.logging.Logger.getLogger(this.getClass.getName)
def whoAmI = {
logger.info(this.getClass.getName)
}
}
class Service extends Loggable {
def answer = {
whoAmI
}
}
object Main extends App {
new Service().answer
}
It produced the following log message:
Jan 25, 2013 2:02:07 PM hu.jonas.simple.Loggable$class whoAmI
INFO: hu.jonas.simple.Service
Why do the two this.getClass.getName differ? And moreover what should I need to write when I instantiate the logger in order to get this:
Jan 25, 2013 2:02:07 PM hu.jonas.simple.Service whoAmI
INFO: hu.jonas.simple.Service
In your code both occurences of getClass.getName
return the same value. But the logger, when formatting the output message, is simply using the source class (that it can know by inspecting the stack) instead of the logger's name (which in your case corresponds to getClass.getName
). So the logger when outputing the header for the log record is actually using the name of the class where the call to log
is done, while the content of the log message is the name runtime class of the instance. So this is like a static vs runtime type issue. If you're wondering where Loggable$class
comes from, it just so happens that the method implementations in a trait named T
are located in a JVM class named T$class
.
And now for an illustration. In the below code I change the log handler so as to erase the information from the source class. This forces the logger to use the logger name instead of the source class name, and you get back the behaviour that you expected.
import java.util.logging._
trait Loggable {
val logger = Logger.getLogger(this.getClass.getName)
logger.getParent.getHandlers.foreach{ handler =>
val formatter = handler.getFormatter
handler.setFormatter( new java.util.logging.Formatter {
def format( record: LogRecord ) = {
record.setSourceClassName( null )
formatter.format( record )
}
})
}
def whoAmI = {
logger.info(this.getClass.getName)
}
}
class Service extends Loggable {
def answer = {
whoAmI
}
}
object Main extends App {
new Service().answer
}
Now, to properly fix your issue, there is a property named java.util.logging.SimpleFormatter.format
that you can set to change the default log formatting. Use it to have the log use the logger name instead of the source class. See http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/SimpleFormatter.html.
Note that it requires Java 7.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With