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

Re: logging the Scala way and named varargs

by Ivan Todoroski-2 :: Rate this Message:

Reply to Author | View in Thread

The question is why should you go through extra hoops (however minor) to
recognize a logging statement?

There is a time and place for implicits, and this is not it - the use
case here seems pretty weak and contrived. There is nothing wrong with
typing logger.warn(...), it clearly documents that it's a logging
statement, and such statements are simply not frequent enough to save
much typing by omitting the "logger" part. I know that implicits are
cool, but there is no need to abuse them for every little thing.


On 18.06.2009 09:03, Ricky Clarkson wrote:

> Surely you can find where warn is defined by searching for an import
> containing 'warn'.  Or jump to declaration in your IDE.
>
> 2009/6/18 Blair Zajac <blair@...>:
>> 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/
>>
>>
>>
>
>
>

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