containing 'warn'. Or jump to declaration in your IDE.
> On Jun 17, 2009, at 9:57 PM, Walter Smith wrote:
>
>>
>> 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 point of slf4j's format string, i.e. "The foobar's value is {}", is to
> avoid interpolation cost if the log message will not be used.
>
> The Scala way of dealing with this is to use by-name arguments. So you end
> up with
>
> trait Logger
> {
> def warn(msg : => String) : Unit
> }
>
> trait Slf4jLogger extends Logger
> {
> private val myRealLogger = Logger.getLogger(this.getClass.getName)
>
> private val isWarnEnabled = myRealLogger.isWarnEnabled
>
> def warn(msg : => String) : Unit
> {
> if (isWarnEnabled) {
> myRealLogger.warn(msg)
> }
> }
> }
>
> Then call it
>
> logger.warn("The foobar's value is " + foobar + ".")
>
> the string concatenation here won't be done unless
> my_real_logger.isWarnEnabled is true.
>
> BTW, I'm not a fan of implicits here. I'd much rather see a call
>
> logger.warn("It blew up!")
>
> than
>
> warn("It blew up!")
>
> It's clear I'm calling a logger and don't need to wonder where warn() is
> defined.
>
> Check out Lift's logger. It does this nicely and has a slf4j layer.
>
>
http://github.com/dpp/liftweb/blob/338119b8d7a76adcb9f45e9aa8a2b946d9c81118/lift-util/src/main/scala/net/liftweb/util/Log.scala>
http://github.com/dpp/liftweb/blob/338119b8d7a76adcb9f45e9aa8a2b946d9c81118/lift-util/src/main/scala/net/liftweb/util/Slf4jLog.scala>
> Regards,
> Blair
>
> --
> Blair Zajac, Ph.D.
> CTO, OrcaWare Technologies
> <
blair@...>
> Subversion training, consulting and support
>
http://www.orcaware.com/svn/>
>
>