|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 | Next > |
|
|
logging the Scala way and named varargsHi!
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 varargsArray(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 varargsOn 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 varargsSurely 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 varargsThe 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 varargsYou 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 varargsOh, 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 varargsI 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 varargsIf "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 |
|
|
Re: logging the Scala way and named varargsI 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 varargsI 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? -- 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 varargsRicky 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 varargsI 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.
|
|
|
Re: logging the Scala way and named varargs> 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 varargsI 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 varargsActually, 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:
-- 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 varargsThat'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? 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 varargsThat's what you can use different loggers for... even hierarchically. Kind Regards Walter |
|
|
Re: logging the Scala way and named varargsLoggerheads,
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:
-- 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+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 > |
| Free embeddable forum powered by Nabble | Forum Help |