登录Scala

Geo*_*rge 162 logging scala

在Scala应用程序中登录的好方法是什么?与语言哲学一致的东西,不会使代码混乱,并且维护成本低且不引人注目.这是一个基本要求清单:

  • 简单
  • 不会使代码混乱.Scala非常简洁.我不希望我的一半代码记录语句
  • 可以更改日志格式以适应我的其他企业日志和监视软件
  • 支持日志记录级别(即调试,跟踪,错误)
  • 可以记录到磁盘以及其他目的地(即套接字,控制台等)
  • 最低配置,如果有的话
  • 在容器中工作(即Web服务器)
  • (可选,但很高兴)作为语言的一部分或作为maven工件,所以我不必破解我的构建来使用它

我知道我可以使用现有的Java日志记录解决方案,但它们至少在上面的两个方面失败了,即混乱和配置.

谢谢你的回复.

Eug*_*ota 117

slf4j包装器

大多数Scala的日志库都是围绕Java日志框架(slf4j,log4j等)的一些包装器,但截至2015年3月,幸存的日志库都是slf4j.这些日志库提供某种形式的log对象,你可以打电话info(...),debug(...)等我不是SLF4J的忠实粉丝,但现在看来是主要的日志框架.这是SLF4J的描述:

对于Java或(SLF4J)简单记录门面用作简单门面或抽象的各种日志框架,例如java.util.logging中,log4j的和的logback,允许最终用户在在部署时所需的日志框架插头.

在部署时更改底层日志库的能力为整个slf4j系列记录器带来了独特的特性,您需要注意这些特性:

  1. classpath作为配置方法.slf4j知道你正在使用哪个底层日志库的方法是通过某个名称加载一个类.在定制类加载器时,我遇到过slf4j无法识别我的记录器的问题.
  2. 因为简单的外观试图成为共同点,所以它仅限于实际的日志调用.换句话说,不能通过代码完成配置.

在一个大型项目中,如果每个人都使用slf4j,那么能够控制传递依赖项的日志记录行为实际上很方便.

Scala记录

Scala Logging由Heiko Seeberger编写,作为他的slf4s的继承者.它使用宏将调用扩展到if表达式,以避免可能昂贵的日志调用.

Scala Logging是一个方便且高性能的日志记录库,包含SLF4J等日志库以及其他可能的日志库.

历史记录器

  • Logula,由Coda Hale编写的Log4J包装器.曾经喜欢这个,但现在已经放弃了.
  • configgy,一个java.util.logging包装器,曾经在Scala的早期流行.现在放弃了.

  • 根据Github上的README,Logula被废弃了. (3认同)

fra*_*cca 62

使用Scala 2.10+考虑通过Typesafe进行ScalaLogging.使用宏来提供非常干净的API

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

引用他们的wiki:

幸运的是,Scala宏可以用来让我们的生活更轻松:ScalaLogging为类Logger提供了轻量级的日志记录方法,这些方法将扩展到上面的习语.所以我们要编写的是:

logger.debug(s"Some ${expensiveExpression} message!")
Run Code Online (Sandbox Code Playgroud)

在应用宏之后,代码将被转换为上述习语.

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

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}
Run Code Online (Sandbox Code Playgroud)

  • 使用`class MyClass with Logging`. (12认同)
  • 你有一个记录器领域,你可以在闲暇时使用.有关详细信息,请参阅https://github.com/typesafehub/scalalogging/blob/master/scalalogging-slf4j/src/main/scala/com/typesafe/scalalogging/slf4j/Logging.scala (2认同)
  • 2.x需要Scala 2.11; 希望没有太大的实际差别; 对于Scala 2.10.x,有"com.typesafe"%%"scalalogging-slf4j"%"1.1.0"`. (2认同)

Bla*_*jac 14

使用slf4j和包装器很不错但是当你有两个以上的内插值时,使用它的内置插值会破坏,因为那时你需要创建一个值数组来进行插值.

更像Scala的解决方案是使用thunk或集群来延迟错误消息的连接.一个很好的例子是Lift的记录器

Log.scala Slf4jLog.scala

看起来像这样:

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

请注意,msg是一个按名称调用,除非isTraceEnabled为true,否则不会对其进行评估,因此生成一个好的消息字符串是没有成本的.这适用于slf4j的插值机制,需要解析错误消息.使用此模型,您可以在错误消息中插入任意数量的值.

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

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

代替

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

  • 是否有可能获得scala类中记录语句的准确行号????? (2认同)

Nik*_*kov 12

不要使用Logula

我实际上已经按照Eugene的推荐进行了尝试并发现它有一个笨拙的配置并且受到了错误的修复,这些错误没有得到修复(比如这个).它看起来维护得不好,也不支持Scala 2.10.

使用slf4s + slf4j-simple

主要优点:

  • 支持最新的Scala 2.10 (迄今为止它是M7)
  • 配置是通用的,但不能简单.它是通过系统属性完成的,您可以通过-Dorg.slf4j.simplelogger.defaultlog=trace在脚本中附加类似于执行命令或硬编码的内容来设置:System.setProperty("org.slf4j.simplelogger.defaultlog", "trace").无需管理无用的配置文件!
  • 适合IDE使用.例如设置日志记录级别在IDEA特定的运行配置为"追踪"刚去Run/Debug Configurations,并添加-Dorg.slf4j.simplelogger.defaultlog=traceVM 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>
Run Code Online (Sandbox Code Playgroud)


Mat*_*aun 11

这就是我让Scala Logging为我工作的方式:

把它放在你的build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
Run Code Online (Sandbox Code Playgroud)

然后,执行sbt update此操作后,会打印出友好的日志消息:

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

如果您正在使用Play,您当然可以只import play.api.Logger编写日志消息:Logger.debug("Hi").

有关详细信息,请参阅文档.


Tri*_*cek 7

我把一些工作形成Logging的特点scalax,创造一个特点是还集成了一个MessageFormat-based图书馆.

然后东西看起来像这样:

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

我们喜欢到目前为止的方法.

执行:

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))  
}
Run Code Online (Sandbox Code Playgroud)


Kri*_*zsa 6

我使用SLF4J + Logback经典并将其应用如下:

trait Logging {
  lazy val logger = LoggerFactory.getLogger(getClass)

  implicit def logging2Logger(anything: Logging): Logger = anything.logger
}
Run Code Online (Sandbox Code Playgroud)

然后你可以更好地使用它适合你的风格:

class X with Logging {
    logger.debug("foo")
    debug("bar")
}
Run Code Online (Sandbox Code Playgroud)

但是这种方法当然每个类实例使用一个记录器实例.


Ton*_*ris 5

WriterMonoid和一个Monad实现。

  • 你能解释一下你的意思吗? (5认同)

Ava*_*Ava 5

2020年登录

我真的很惊讶我在工作中使用的Scribe日志框架在这里甚至没有提到。更重要的是,在搜索“scala logging”后,它甚至没有出现在谷歌的第一页。但是在谷歌搜索时会出现这个页面!所以让我把它留在这里。

Scribe 的主要优点: