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

Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View in Thread

You seem to consider implicit values as hoops; I do not.

I would generally rather write warn("We assumed that x will never be
greater than y, and that assumption is incorrect") than
logger.warn("We assumed that..."), simply because the logger bit is
irrelevant to understanding that code.

Scala lets us do that without our code gaining bindings to global
variables/state, which is an improvement over other languages.  Then
you call it jumping through hoops, and start talking about "a time and
a place.".  It's now, and here.

I feel more strongly about your disdain for the feature than I do
about actually typing logger.warn(s) though.

2009/6/18 Ivan Todoroski <grnch_lists@...>:

> 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/
>>>
>>>
>>>
>>
>>
>>
>
>



--
Ricky Clarkson
Java Programmer, AD Holdings
+44 1565 770804
Skype: ricky_clarkson
Google Talk: ricky.clarkson@...

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