loginScala

什么是在Scala应用程序中logging日志的好方法? 一些与语言哲学一致的东西,不会混淆代码,而且维护性低,不显眼。 这是一个基本的需求清单:

  • 简单
  • 不会混淆代码。 斯卡拉是简洁的伟大。 我不想让一半的代码成为日志语句
  • 日志格式可以改变,以适应我的企业日志和监控软件的其余部分
  • 支持日志级别(即debugging,跟踪,错误)
  • 可以login到磁盘以及其他目的地(即套接字,控制台等)
  • 最小configuration,如果有的话
  • 在容器(即networking服务器)
  • (可选,但很好有)来作为语言的一部分或作为一个maven工件,所以我不必破解我的构build使用它

我知道我可以使用现有的Java日志logging解决scheme,但是至less有两个失败,即混乱和configuration。

感谢您的回复。

slf4j包装

Scala的日志库大部分都是围绕Java日志框架(slf4j,log4j等)的一些包装,但是到2015年3月为止,幸存的日志库都是slf4j。 这些日志库提供了一些你可以调用info(...)debug(...)等等的log对象。我不是slf4j的忠实粉丝,但现在它似乎是主要的日志框架。 这里是SLF4J的描述:

对于Java或(SLF4J)的简单日志门面,可以作为各种日志框架(如java.util.logging,log4j和logback)的简单外观或抽象,允许最终用户在部署时插入所需的日志框架。

在部署时更改底层日志库的能力为整个slf4j系列日志logging器带来了独特的特性,您需要注意以下几点:

  1. classpath作为configuration方法。 slf4j知道你正在使用的底层日志库是通过某个名字加载一个类。 我有问题,其中slf4j无法识别我的logging器时,classloader被定制。
  2. 因为简单的外观试图成为共同的分母,它仅限于实际的日志调用。 换句话说,configuration不能通过代码完成。

在一个大型项目中,如果每个人都使用slf4j,那么能够控制传递依赖关系的日志logging行为确实很方便。

Scalalogging

Scala Logging由Heiko Seeberger作为他的slf4s的继任者。 它使用macros将呼叫扩展到ifexpression式,以避免可能昂贵的日志调用。

Scala Logging是一个方便和高性能的日志库包装日志库像SLF4J和其他潜在的。

历史logging器

  • Logula ,一个由Coda Hale编写的Log4J包装器。 曾经喜欢这个,但现在它被放弃了。
  • configgy ,一个java.util.logging包装器,在Scala早期的版本中很stream行。 现在放弃了。

Scala 2.10+考虑types安全的ScalaLogging。 使用macros提供一个非常干净的API

https://github.com/typesafehub/scala-logging

从他们的维基引用:

幸运的是,Scalamacros可以用来使我们的生活更轻松:ScalaLogging为类Logger提供了轻量级日志logging方法,这些方法将会扩展到上面的语言。 所以我们要写的是:

 logger.debug(s"Some ${expensiveExpression} message!") 

macros被应用后,代码将被转换成上述的习惯用法。

此外,ScalaLogging提供了特性Logging ,它可以方便地提供一个Logger实例,该实例初始化为混合类的名称:

 import com.typesafe.scalalogging.slf4j.LazyLogging class MyClass extends LazyLogging { logger.debug("This is very convenient ;-)") } 

使用slf4j和一个包装器是不错的,但是当你有两个以上的值进行插值的时候,它的内插使用会被破坏,因为你需要创build一个数组来插入。

更类似Scala的解决scheme是使用thunk或cluster来延迟错误消息的连接。 Lift的logging器就是一个很好的例子

Log.scala Slf4jLog.scala

看起来像这样:

 class Log4JLogger(val logger: Logger) extends LiftLogger { override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg) } 

请注意,msg是一个名称调用,除非isTraceEnabled为true,否则不会被评估,因此生成一个不错的消息string没有任何代价。 这围绕着slf4j的插值机制,需要parsing错误信息。 使用此模型,可以将任意数量的值插入到错误消息中。

如果你有一个单独的特性,将这个Log4JLogger混合到你的类中,那么你可以做

 trace("The foobar from " + a + " doesn't match the foobar from " + b + " and you should reset the baz from " + c") 

代替

 info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c}, Array(a, b, c)) 

不要使用Logula

我实际上已经按照尤金的build议进行了尝试,发现它有一个笨拙的configuration,并且受到了一些错误,而这些错误并没有被固定(比如这个 )。 它看起来没有得到很好的维护,它不支持Scala 2.10

使用slf4s + slf4j-simple

主要优点:

  • 支持最新的Scala 2.10 (迄今为止是M7)
  • configuration是多function的,但不能简单。 这是通过系统属性来完成的,您可以通过在脚本中追加类似-Dorg.slf4j.simplelogger.defaultlog=trace命令来设置执行命令或硬编码: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace") 。 无需pipe理垃圾configuration文件!
  • 与IDE很好地匹配。 例如,要在IDEA的特定运行configuration中将日志logging级别设置为“跟踪”,只需进入Run/Debug Configurations并将-Dorg.slf4j.simplelogger.defaultlog=trace添加到VM options
  • 简单的设置:从这个答案的底部放下依赖关系

以下是您需要使用Maven运行它的方法:

 <dependency> <groupId>com.weiglewilczek.slf4s</groupId> <artifactId>slf4s_2.9.1</artifactId> <version>1.0.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.6.6</version> </dependency> 

这就是我如何得到Scala Logging为我工作:

把它放在你的build.sbt

 libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2", libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3" 

然后,在进行sbt update ,打印出友好的日志消息:

 import com.typesafe.scalalogging._ object MyApp extends App with LazyLogging { logger.info("Hello there") } 

如果您使用的是Play,那么您当然可以简单地import play.api.Logger用于编写日志消息的Logger.debug("Hi")Logger.debug("Hi")

有关更多信息,请参阅文档 。

我从scalaxLogging特性中scalax了一些工作,并创build了一个也集成了一个MessageFormat-based库的特性。

那么东西看起来像这样:

 class Foo extends Loggable { info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 ) } 

我们喜欢这个方法。

执行:

 trait Loggable { val logger:Logger = Logging.getLogger(this) def checkFormat(msg:String, refs:Seq[Any]):String = if (refs.size > 0) msgfmtSeq(msg, refs) else msg def trace(msg:String, refs:Any*) = logger trace checkFormat(msg, refs) def trace(t:Throwable, msg:String, refs:Any*) = logger trace (checkFormat(msg, refs), t) def info(msg:String, refs:Any*) = logger info checkFormat(msg, refs) def info(t:Throwable, msg:String, refs:Any*) = logger info (checkFormat(msg, refs), t) def warn(msg:String, refs:Any*) = logger warn checkFormat(msg, refs) def warn(t:Throwable, msg:String, refs:Any*) = logger warn (checkFormat(msg, refs), t) def critical(msg:String, refs:Any*) = logger error checkFormat(msg, refs) def critical(t:Throwable, msg:String, refs:Any*) = logger error (checkFormat(msg, refs), t) } /** * Note: implementation taken from scalax.logging API */ object Logging { def loggerNameForClass(className: String) = { if (className endsWith "$") className.substring(0, className.length - 1) else className } def getLogger(logging: AnyRef) = LoggerFactory.getLogger(loggerNameForClass(logging.getClass.getName)) } 

我使用SLF4J + Logback classic,并像这样应用它:

 trait Logging { lazy val logger = LoggerFactory.getLogger(getClass) implicit def logging2Logger(anything: Logging): Logger = anything.logger } 

那么你可以使用它更适合你的风格:

 class X with Logging { logger.debug("foo") debug("bar") } 

但是这种方法当然使用每个类实例的logging器实例。

您应该看看scalax库: http ://scalax.scalaforge.org/在这个库中,有一个Logging特征,使用sl4j作为后端。 通过使用这个特性,你可以很容易地进行login(只需使用inheritance特性的类中的logging器字段)。

WriterMonoidMonad实现。

还没有尝试过,但configuration和日志configuration看起来很有希望:

http://github.com/robey/configgy/tree/master

在使用slf4s和logula一段时间后,我写了loglady ,一个简单的日志logging特征,包装slf4j。

它提供了一个类似于Python日志库的API,这使得常见的情况(基本string,简单格式化)变得微不足道,并且避免了对样板文件进行格式化。

http://github.com/dln/loglady/

我发现使用某种javalogging器,例如sl4j,使用简单的scala包装器非常方便,它带给我这样的语法

 val #! = new Logger(..) // somewhere deep in dsl.logging. object User with dsl.logging { #! ! "info message" #! dbg "debug message" #! trace "var a=true" } 

在我看来,非常有用的mixin的Javavalidation日志框架和斯卡拉的花式语法。

快速和简单的forms。

Scala 2.10及以上版本:

 import com.typesafe.scalalogging.slf4j.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....") 

和build.sbt:

 libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0" 

斯卡拉2.11+和更新:

 import import com.typesafe.scalalogging.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....") 

和build.sbt:

 libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"