« Return to Thread: logging the Scala way and named varargs

logging the Scala way and named varargs

by Walter Smith :: Rate this Message:

Reply to Author | View in Thread

Hi!

I think logging should be a part of the core libraries of a language... it is such an unbeloved matter that at least the logging api to use should not be something to discuss about in every project.

There is one logging framework built into Java, but it is not very well received. Especially in the Java enterprise world, log4j is used much more often for some good reasons, but you can't deploy multiple configurations for the same classes used in different enterprise applications within one JVM, if it's part of the parent class loader, i.e. it's used by the container itself. And there is a third comprehensive logging framework competing: logback. So it's a good idea for frameworks to be able to use a generic logging api, so that a customer can use *one* framework for all the frameworks in use. And generally Scala is right now in the role of such a framework, isn't it?

I still see Apache commons logging being used a lot. I think this is not much better than using prinln directly! It not only lacks important features like formatting messages only when needed, or MDCs; I understand that it still causes perm gen memory leaks when hot deploying.

There is a much better solution, though: SLF4J... IMHO every Java or Scala programmer should know it.

But SLF4J is a Java api, so I tried to wrap it in "the Scala way":
1. Logging is a trait that defines the logger using the name of the class you mix it into; a common and regularly used pattern now easily provided by a library... that's what I love Scala for.
2. There is a sealed trait LogLevel with objects for error, info, etc. that you can pass around, e.g. into a library or to configure instances of a class. To actually log at a LogLevel, you simply apply your parameters to it; the logger can be passed in as a implicit argument.
3. The arguments that are used for your format are passed in by name, so only get evaluated when the log level is enabled, i.e. it's ok to call debug("client dns name {}", java.net.InetAddress.getByAddress(client)); the lookup will only be made, if the debug log level is enabled... Scala rules!

BTW: Is there a simpler way to get an Array[Byte] literal than Array(192.byteValue,168.byteValue,178.byteValue,1.byteValue)?

The implementation is not very elegant, though, yet: I have to define one method for each number of arguments by name to be passed in; the compiler doesn't like def apply(format: String, args: => Any *)(implicit logger: Logger). Is there a differen way to do this or is that a feature that could go into a future version of Scala, maybe even 2.8?

Even if I'd simply def apply(format: String, args: Any *)(implicit logger: Logger), I can't figure out, how to pass the args to the correct overloaded slf4j method. There is one trace(String format, Object arg) and one trace(String format, Object[] argArray) (note that this is Java ;) If I just pass it along, the first one is picked and an Array instance passed in, but I need the second one! And I can't cast my args to an Object-Array... I think that's because Any can be a primitive type as well which can't be simply cast to an Object. Any suggestions?!?

I'd appreciate any comments!

Kind regards
Walter

 « Return to Thread: logging the Scala way and named varargs