logging the Scala way and named varargs

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 | Next >

logging the Scala way and named varargs

by Walter Smith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Array(3, 4, 5) map (_ toByte)

2009/6/18 Walter Smith <walter.smith@...>:

>
> 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
> --
> View this message in context: http://www.nabble.com/logging-the-Scala-way-and-named-varargs-tp24086402p24086402.html
> Sent from the Scala - Debate mailing list archive at Nabble.com.
>
>



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

Re: logging the Scala way and named varargs

by Blair Zajac :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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/



Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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@...

Re: logging the Scala way and named varargs

by Ivan Todoroski-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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


Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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@...

Re: logging the Scala way and named varargs

by Ivan Todoroski-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Oh, sorry if I came across as feeling disdain for implicits as a
feature. To the contrary, implicits are one of the things I love most
about Scala. I just didn't feel it was appropriate to use implicits in
this particular case, that's all.

Maybe I'm too used to the logger.warn() pattern... it just looked to me
that a method call like warn() without any context could mean any number
of things, including popping up a message dialog in a GUI, whereas
logger.warn() is pretty self-describing without further ado.

You increase confusion ever so slightly, yet you don't really gain much.


On 18.06.2009 10:13, Ricky Clarkson wrote:

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


Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I see.  That's fair enough.

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

> Oh, sorry if I came across as feeling disdain for implicits as a feature. To
> the contrary, implicits are one of the things I love most about Scala. I
> just didn't feel it was appropriate to use implicits in this particular
> case, that's all.
>
> Maybe I'm too used to the logger.warn() pattern... it just looked to me that
> a method call like warn() without any context could mean any number of
> things, including popping up a message dialog in a GUI, whereas
> logger.warn() is pretty self-describing without further ado.
>
> You increase confusion ever so slightly, yet you don't really gain much.
>
>
> On 18.06.2009 10:13, Ricky Clarkson wrote:
>>
>> 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@...

Re: logging the Scala way and named varargs

by Robert Fischer :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

If "use an IDE" was an acceptable answer, we'd all still be coding Java via Eclipse refactoring wizards.

~~ Robert.

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/
>>
>>
>>
>
>
>
--
~~ Robert Fischer, Smokejumper IT Consulting.
Enfranchised Mind Blog http://EnfranchisedMind.com/blog

Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/redirect.html



signature.asc (201 bytes) Download Attachment

Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I gave two options.  One a text search, the other an IDE.  Unless you
print out your code to read it, I think those options cover most
cases.

2009/6/18 Robert Fischer <robert.fischer@...>:

> If "use an IDE" was an acceptable answer, we'd all still be coding Java via Eclipse refactoring wizards.
>
> ~~ Robert.
>
> 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/
>>>
>>>
>>>
>>
>>
>>
>
> --
> ~~ Robert Fischer, Smokejumper IT Consulting.
> Enfranchised Mind Blog http://EnfranchisedMind.com/blog
>
> Check out my book, "Grails Persistence with GORM and GSQL"!
> http://www.smokejumperit.com/redirect.html
>
>



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

Re: logging the Scala way and named varargs

by Daniel Sobral :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I don't see that the same way. Logging is something normally associated with a large codebase. You often have a single logging solution in a project, though there might be more than one being used -- often for legacy reasons. In such scenarios, the programmer knows what the logging solution is, and where the logger is defined. There would never be any confusion about what "warn(...)" means.
 
But I'll grant you a programmer who isn't familiar with that yet. He sees the warn(...) statement, look for the import or use the IDE to identify its origin, recognizes it is the logger, and then goes back to what he was doing. He will know, from then on, as long as he is working on that codebase, what warn(...) is supposed to be.
 
OTOH, you could have logger.warn(...) everywhere, which would add "logger" to the everywhere in the code, even though everyone working in the code knows warn(...) refers to the logger.

On Thu, Jun 18, 2009 at 4:23 AM, Ivan Todoroski <grnch_lists@...> wrote:
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/










--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

Re: logging the Scala way and named varargs

by Blair Zajac :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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.

Sure, but it that injects a whole number of methods into the class that are not
related to the class' primary job.  So from a design point of view, having all
the logging methods tied to a val in the class is much cleaner than putting
those methods onto the class itself.  Also, looking at the ScalaDoc shows me 20+
methods I don't care to see on each class that uses that trait.

Regards,
Blair


Re: logging the Scala way and named varargs

by michaelg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I disagree. I think most folks who have been programming for awhile are quite used to the fatal-error-warn-info-debug/trace paradigms. I've often seen static utilities (sometimes buggy ones) written in Java by developers so they could type warn("we're in trouble"); etc.


Ivan Todoroski-2 wrote:
Maybe I'm too used to the logger.warn() pattern... it just looked to me
that a method call like warn() without any context could mean any number
of things, including popping up a message dialog in a GUI, whereas
logger.warn() is pretty self-describing without further ado.

You increase confusion ever so slightly, yet you don't really gain much.

Re: logging the Scala way and named varargs

by Raoul Duke :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> I disagree. I think most folks who have been programming for awhile are quite
> used to the fatal-error-warn-info-debug/trace paradigms.

[i'm assuming that the f/e/w/i/d/t is an ordering, so that if you set
the logging level to "debug" you will get all of f/e/w/i and d, but
not t]

i believe the usual approach to logging in the java world to be a
clear indictment of the ability of java developers to actually think
about semantics at all. it is such a horribly anemic and wrong-headed
approach. and it continually blows my mind that the people using these
systems don't seem to ever stop and realize how poor a fit the
f/e/w/i/d/t type approach is to actually getting work done.

no i haven't taken the time to write a better replacement. i already
don't have any free time. :-P

sincerely,
the curmudgeon.

Re: logging the Scala way and named varargs

by Ricky Clarkson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I sent a few months on the death march of a mobile phone WAP browser
integration a number of years ago, everything in C, with a logging
system that I liked and was disappointed to later discover was not
standard in the industry.

Instead of logging levels, we used categories, so that, say,
log(MEMORY, "malloc returned NULL"), log(SEAN, "Sean broke arrays"),
log(MOUSE, "It's a phone, it doesn't have a damn mouse.") were
written, and one could decide what to filter on.  So instead of
switching from viewing warnings to viewing info and seeing a lot of
unrelated noise, you could watch all memory problems by watching the
category MEMORY.

I have a vague idea that log4j or something actually supports this,
but I've never seen this pattern actually used since 2001.

2009/6/18 Raoul Duke <raould@...>:

>> I disagree. I think most folks who have been programming for awhile are quite
>> used to the fatal-error-warn-info-debug/trace paradigms.
>
> [i'm assuming that the f/e/w/i/d/t is an ordering, so that if you set
> the logging level to "debug" you will get all of f/e/w/i and d, but
> not t]
>
> i believe the usual approach to logging in the java world to be a
> clear indictment of the ability of java developers to actually think
> about semantics at all. it is such a horribly anemic and wrong-headed
> approach. and it continually blows my mind that the people using these
> systems don't seem to ever stop and realize how poor a fit the
> f/e/w/i/d/t type approach is to actually getting work done.
>
> no i haven't taken the time to write a better replacement. i already
> don't have any free time. :-P
>
> sincerely,
> the curmudgeon.
>



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

Re: logging the Scala way and named varargs

by Daniel Sobral :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Actually, fatal-error-warn-ino-debug/trace is properly called "severity". That paradigm actually dates back at least back into the 80s, with Sendmail's syslog, which eventually became the BSD syslog protocol (RFC 3164).
 
Personally, I think it predates even that, from mainframe logging, which a brief googling about REXX seems to confirm it, but I can't give dates on that.
 
Having been a system administrator, the severity level was a perfect fit to getting things done. You treat first Emergencies, then Alerts, then Criticals. After that, you deal with Errors, and, time being available, Warnings. If a problem evades you, you take a look at the Notice or Informationals. Failing all that, you turn to the Debug messages.
 
If you filter for Warnings, you don't want to miss Errors or worse. And you don't want any more information than needed. This has served me very well as a sysadmin, and, judging by its longevity and widespread, served others as well.
 
So I urge you to take time to write a better replacement, as something better would certainly revolutionize the field. And, trust me, people on operations need all the help they can get.

On Thu, Jun 18, 2009 at 2:56 PM, Raoul Duke <raould@...> wrote:
> I disagree. I think most folks who have been programming for awhile are quite
> used to the fatal-error-warn-info-debug/trace paradigms.

[i'm assuming that the f/e/w/i/d/t is an ordering, so that if you set
the logging level to "debug" you will get all of f/e/w/i and d, but
not t]

i believe the usual approach to logging in the java world to be a
clear indictment of the ability of java developers to actually think
about semantics at all. it is such a horribly anemic and wrong-headed
approach. and it continually blows my mind that the people using these
systems don't seem to ever stop and realize how poor a fit the
f/e/w/i/d/t type approach is to actually getting work done.

no i haven't taken the time to write a better replacement. i already
don't have any free time. :-P

sincerely,
the curmudgeon.



--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

Re: logging the Scala way and named varargs

by Walter Smith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Blair Zajac wrote:
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.
That's actually much simpler, and I must admit that I hadn't thought of this. I used by-name arguments just for the arguments that go *into* the format, not the complete format itself. But actually I currently have a compelling use case that requires access to the raw arguments: We use an appender to report some numbers to a monitoring tool. You might also want to store them into a database as separate objects, so you can do all kind of things to them. So the compiler should allow me to put that asterisk after a by-name argument, shouldn't it?

Ivan Todoroski-2 wrote:
There is a time and place for implicits, and this is not it - the use
case here seems pretty weak and contrived.
When I first read about implicit arguments, I thought: "Oh my god! Nobody will understand that kind of code." But there are some very compelling use cases while you have to be very careful with it. But I didn't want the implicits as an end in itself; I wanted to be able to store a LogLevel into a variable! And warn(logger, "message") looks very confusing to me, so I preferred an implicit argument. It would be a contrived use case for currying, though ;-)

BTW: I find the discussion about how difficult or not it is to find out where warn() comes from not very conductive. This boils down to a simple matter of taste. You can discuss deliberately on it, but nobody will ever convince anybody about anything ;-)

I think I grew a bit too big for my boots when I wrote "the Scala way"... there are just too many to have everybody settle on one, just by good reasons. I think things like this require a Scala rock star to set the tone ;-) ... and that's what I think is much more important than which one it is!


Regards
Walter

Re: logging the Scala way and named varargs

by Walter Smith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ricky Clarkson wrote:
Instead of logging levels, we used categories
That's what you can use different loggers for... even hierarchically.

Kind Regards
Walter

Re: logging the Scala way and named varargs

by Meredith Gregory :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Loggerheads,

On a brighter side, in Dec i came up with a method of logging that was really cool for the specific application i was working on. i was building a web-enabled compiler. The input graphs, the output Haskell code. When the compiler hit an error it would calculate the smallest complete compilation unit from the evaluation path (in the compiler) that caused the error and log that. In other words it logged the minimal breaking test.

It was really useful and just so cool, imho. This won't work for all apps, but i think it can be made to work for a great deal of them.

Best wishes,

--greg

On Thu, Jun 18, 2009 at 10:56 AM, Raoul Duke <raould@...> wrote:
> I disagree. I think most folks who have been programming for awhile are quite
> used to the fatal-error-warn-info-debug/trace paradigms.

[i'm assuming that the f/e/w/i/d/t is an ordering, so that if you set
the logging level to "debug" you will get all of f/e/w/i and d, but
not t]

i believe the usual approach to logging in the java world to be a
clear indictment of the ability of java developers to actually think
about semantics at all. it is such a horribly anemic and wrong-headed
approach. and it continually blows my mind that the people using these
systems don't seem to ever stop and realize how poor a fit the
f/e/w/i/d/t type approach is to actually getting work done.

no i haven't taken the time to write a better replacement. i already
don't have any free time. :-P

sincerely,
the curmudgeon.



--
L.G. Meredith
Managing Partner
Biosimilarity LLC
1219 NW 83rd St
Seattle, WA 98117

+1 206.650.3740

http://biosimilarity.blogspot.com

Re: logging the Scala way and named varargs

by Chris Twiner :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

+1

if its really wanted:

val logger = someLoggerFactoryFunction

logger.warn

import logger._

warn

no need for implicits here, just a stable identifier.

On Thu, Jun 18, 2009 at 10:30 AM, Ivan Todoroski<grnch_lists@...> wrote:

> Oh, sorry if I came across as feeling disdain for implicits as a feature. To
> the contrary, implicits are one of the things I love most about Scala. I
> just didn't feel it was appropriate to use implicits in this particular
> case, that's all.
>
> Maybe I'm too used to the logger.warn() pattern... it just looked to me that
> a method call like warn() without any context could mean any number of
> things, including popping up a message dialog in a GUI, whereas
> logger.warn() is pretty self-describing without further ado.
>
> You increase confusion ever so slightly, yet you don't really gain much.
>
>
> On 18.06.2009 10:13, Ricky Clarkson wrote:
>>
>> 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/
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>>
>>
>
>
< Prev | 1 - 2 | Next >