在 Scala 中登录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/978252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:27:25  来源:igfitidea点击:

Logging in Scala

loggingscala

提问by George

What is a good way to do logging in a Scala application? Something that is consistent with the language philosophy, does not clutter the code, and is low-maintenance and unobtrusive. Here's a basic requirement list:

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

  • simple
  • does not clutter the code. Scala is great for its brevity. I don't want half of my code to be logging statements
  • log format can be changed to fit the rest of my enterprise logs and monitoring software
  • supports levels of logging (ie debug, trace, error)
  • can log to disk as well as other destinations (i.e. socket, console, etc.)
  • minimum configuration, if any
  • works in containers (ie, web server)
  • (optional, but nice to have) comes either as part of the language or as a maven artifact, so I don't have to hack my builds to use it
  • 简单的
  • 不会使代码混乱。Scala 的优点在于它的简洁性。我不希望我的一半代码记录语句
  • 可以更改日志格式以适合我的其余企业日志和监控软件
  • 支持日志级别(即调试、跟踪、错误)
  • 可以登录到磁盘以及其他目的地(即套接字、控制台等)
  • 最低配置,如果有的话
  • 在容器中工作(即网络服务器)
  • (可选,但很高兴)作为语言的一部分或作为 Maven 工件,所以我不必破解我的构建来使用它

I know I can use the existing Java logging solutions, but they fail on at least two of the above, namely clutter and configuration.

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

Thanks for your replies.

感谢您的回复。

采纳答案by Eugene Yokota

slf4j wrappers

slf4j 包装器

Most of Scala's logging libraries have been some wrappers around a Java logging framework (slf4j, log4j etc), but as of March 2015, the surviving log libraries are all slf4j. These log libraries provide some sort of logobject to which you can call info(...), debug(...), etc. I'm not a big fan of slf4j, but it now seems to be the predominant logging framework. Here's the description of SLF4J:

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

The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time.

Simple Logging Facade for Java 或 (SLF4J) 充当各种日志框架的简单外观或抽象,例如 java.util.logging、log4j 和 logback,允许最终用户在部署时插入所需的日志框架。

The ability to change underlying log library at deployment time brings in unique characteristic to the entire slf4j family of loggers, which you need to be aware of:

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

  1. classpath as configurationapproach. The way slf4j knows which underlying logging library you are using is by loading a class by some name. I've had issues in which slf4j not recognizing my logger when classloader was customized.
  2. Because the simple facadetries to be the common denominator, it's limited only to actual log calls. In other words, the configuration cannot be done via the code.
  1. 类路径作为配置方法。slf4j 知道您正在使用哪个底层日志库的方法是通过某个名称加载一个类。我遇到了在自定义类加载器时 slf4j 无法识别我的记录器的问题。
  2. 因为简单的外观试图成为公分母,所以它仅限于实际的日志调用。换句话说,配置不能通过代码来完成。

In a large project, it could actually be convenient to be able to control the logging behavior of transitive dependencies if everyone used slf4j.

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

Scala Logging

Scala 日志

Scala Loggingis written by Heiko Seeberger as a successor to his slf4s. It uses macro to expand calls into if expression to avoid potentially expensive log call.

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

Scala Logging is a convenient and performant logging library wrapping logging libraries like SLF4J and potentially others.

Scala Logging 是一个方便且高性能的日志库,它封装了像 SLF4J 和其他潜在的日志库。

Historical loggers

历史记录员

  • Logula, a Log4J wrapper written by Coda Hale. Used to like this one, but now it's abandoned.
  • configgy, a java.util.logging wrapper that used to be popular in the earlier days of Scala. Now abandoned.
  • Logula,由 Coda Hale 编写的 Log4J 包装器。以前很喜欢这个,现在放弃了。
  • configgy,一个 java.util.logging 包装器,曾经在 Scala 的早期很流行。现在放弃了。

回答by fracca

With Scala 2.10+ Consider ScalaLogging by Typesafe. Uses macros to deliver a very clean API

使用 Scala 2.10+ 考虑类型安全的 ScalaLogging。使用宏来提供非常干净的 API

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

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

Quoting from their wiki:

引用他们的维基:

Fortunately Scala macros can be used to make our lives easier: ScalaLogging offers the class Loggerwith lightweight logging methods that will be expanded to the above idiom. So all we have to write is:

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

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

After the macro has been applied, the code will have been transformed into the above described idiom.

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

In addition ScalaLogging offers the trait Loggingwhich conveniently provides a Loggerinstance initialized with the name of the class mixed into:

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

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}

回答by Blair Zajac

Using slf4j and a wrapper is nice but the use of it's built in interpolation breaks down when you have more than two values to interpolate, since then you need to create an Array of values to interpolate.

使用 slf4j 和包装器很好,但是当您有两个以上的值要插值时,使用它内置的插值会崩溃,因为那时您需要创建一个值数组来插值。

A more Scala like solution is to use a thunk or cluster to delay the concatenation of the error message. A good example of this is Lift's logger

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

Log.scalaSlf4jLog.scala

Log.scala Slf4jLog.scala

Which looks like this:

看起来像这样:

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

Note that msg is a call-by-name and won't be evaluated unless isTraceEnabled is true so there's no cost in generating a nice message string. This works around the slf4j's interpolation mechanism which requires parsing the error message. With this model, you can interpolate any number of values into the error message.

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

If you have a separate trait that mixes this Log4JLogger into your class, then you can do

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

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

instead of

代替

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

回答by Nikita Volkov

Don't use Logula

不要使用 Logula

I've actually followed the recommendation of Eugene and tried it and found out that it has a clumsy configuration and is subjected to bugs, which don't get fixed (such as this one). It doesn't look to be well maintained and it doesn't support Scala 2.10.

我实际上遵循了 Eugene 的建议并尝试了它,发现它的配置很笨拙,并且存在无法修复的错误(例如这个)。它看起来维护得不好,也不支持 Scala 2.10

Use slf4s + slf4j-simple

使用 slf4s + slf4j-simple

Key benefits:

主要优势:

  • Supports latest Scala 2.10(to date it's M7)
  • Configuration is versatile but couldn't be simpler. It's done with system properties, which you can set either by appending something like -Dorg.slf4j.simplelogger.defaultlog=traceto execution command or hardcode in your script: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). No need to manage trashy config files!
  • Fits nicely with IDEs. For instance to set the logging level to "trace" in a specific run configuration in IDEA just go to Run/Debug Configurationsand add -Dorg.slf4j.simplelogger.defaultlog=traceto VM options.
  • Easy setup: just drop in the dependencies from the bottom of this answer
  • 支持最新的 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.
  • 轻松设置:只需从这个答案的底部删除依赖项

Here's what you need to be running it with Maven:

以下是使用 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>

回答by Matthias Braun

This is how I got Scala Loggingworking for me:

这就是我让Scala Logging对我来说有效的方式:

Put this in your build.sbt:

把它放在你的build.sbt

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

Then, after doing an sbt update, this prints out a friendly log message:

然后,在执行sbt update完之后,这会打印出一条友好的日志消息:

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

If you are using Play, you can of course simply import play.api.Loggerfor writing log messages: Logger.debug("Hi").

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

See the docsfor more info.

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

回答by Tristan Juricek

I pulled a bit of work form the Loggingtrait of scalax, and created a trait that also integrated a MessageFormat-basedlibrary.

我从 的Loggingtrait 中提取了一些工作scalax,并创建了一个也集成了一个MessageFormat-based库的 trait 。

Then stuff kind of looks like this:

然后东西看起来像这样:

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

We like the approach so far.

到目前为止,我们喜欢这种方法。

Implementation:

执行:

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))  
}

回答by Kristof Jozsa

I use SLF4J + Logback classic and apply it like this:

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

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

  implicit def logging2Logger(anything: Logging): Logger = anything.logger
}

Then you can use it whichever fits your style better:

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

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

but this approach of course uses a logger instance per class instance.

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

回答by Tony Morris

Writer, Monoidand a Monadimplementation.

WriterMonoid和一个Monad实现。

回答by Tony Morris

You should have a look at the scalax library : http://scalax.scalaforge.org/In this library, there is a Logging trait, using sl4j as backend. By using this trait, you can log quite easily (just use the logger field in the class inheriting the trait).

你应该看看 scalax 库:http://scalax.scalaforge.org/ 在这个库中,有一个 Logging trait,使用 sl4j 作为后端。通过使用这个特性,你可以很容易地记录日志(只需使用继承该特性的类中的 logger 字段)。

回答by dberesford

Haven't tried it yet, but Configgy looks promising for both configuration and logging:

还没有尝试过,但 Configgy 在配置和日志记录方面看起来很有希望:

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

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