scala logging

JAVA源码 2025-08-18

scala logging是一个方便快速的日志记录库包装SLF4J。

这很方便,因为您可以简单地调用日志方法,而无需检查是否启用了相应的日志级别:

logger.debug( s " Some $expensive message! " )

这很快,因为感谢Scala宏应用校验启用-IDIOM并生成以下代码:

 if (logger.isDebugEnabled) logger.debug( s " Some $expensive message! " )

先决条件

  • Java 8或更高
  • Scala 2.11、2.12、2.13或3.0
  • 记录与SLF4J兼容的后端

兼容的记录后端是记录,将其添加到您的SBT构建定义:

libraryDependencies += " ch.qos.logback " % " logback-classic " % " 1.2.10 "

如果您正在寻找与Scala 2.10兼容的版本,请查看scala logging 2.x。

获取scala logging

scala logging已发布到Sonatype OSS和Maven Central:

  • 组ID /组织: com.typesafe.scala-logging
  • 伪影ID /名称: Scala-Logging

SBT用户可以将其添加到他们的build.sbt

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

使用scala logging

来自com.typesafe.scalalogging软件包的Logger类包装了下面的SLF4J记录器。为了创建Logger ,您可以将名称传递给Logger Companion对象中定义的apply Factory方法:

 val logger = Logger ( " name " )

或者,您通过SLF4J Logger实例:

 val logger = Logger ( LoggerFactory .getLogger( " name " ))

或者,您以定义的班级的名义传递:

 val logger = Logger (getClass.getName)

或者,您通过一堂课:

 val logger = Logger ( classOf [ MyClass ])

或者,使用隐式类标记参数包裹的运行时类:

 val logger = Logger [ MyClass ]

com.typesafe.scalalogging软件包中的LazyLoggingStrictLogging特征分别将logger构件定义为懒惰或严格的值,而AnyLogging特征都定义了抽象logger

这取决于要使用的个人用例。但是,我们定义了一些可以使用这些特征的方案:

  • 如果您重复使用此特征来创建许多对象,请使用LazyLogging
  • 默认情况下,几乎使用StrictLogging ,尤其是当类是单身人士的情况下,或者您知道日志方法将始终被调用。
  • 在编写一些需要访问任何记录器的特征时,请使用AnyLogging而无需决定特定的实现。

如果有LazyLoggingStrictLogging ,那么基础SLF4J记录仪是根据这些特征混合在一起的类命名的:

println("scala logging is great!")) } }">
 class LazyLoggingExample extends LazyLogging {
  logger.debug( " This is Lazy Logging ;-) " )

  logger.whenDebugEnabled {
    println( " This would only execute when the debug level is enabled. " )
    ( 1 to 10 ).foreach(x => println( " scala logging is great! " ))
  }
}
println("scala logging is great!")) } }">
 class StrictLoggingExample extends StrictLogging {
  logger.debug( " This is Strict Logging ;-) " )

  logger.whenDebugEnabled {
    println( " This would only execute when the debug level is enabled. " )
    ( 1 to 10 ).foreach(x => println( " scala logging is great! " ))
  }
}
println("scala logging is great!")) } }">
 class AnyLoggingExample extends AnyLogging {
  override protected val logger : Logger = Logger ( " name " )

  logger.info( " This is Any Logging ;-) " )

  logger.whenInfoEnabled {
    println( " This would only execute when the info level is enabled. " )
    ( 1 to 10 ).foreach(x => println( " scala logging is great! " ))
  }
}

LoggerTakingImplicit提供了与Logger类相同的方法,但具有其他隐式参数A 。在创建LoggerTakingImplicit证据丢弃的过程中,需要CanLog[A] 。当上下文参数(例如相关ID )被传递时,您希望将其包含在日志消息中时,它可能很有用:

 case class CorrelationId ( value : String )
implicit case object CanLogCorrelationId extends CanLog [ CorrelationId ] {
  override def logMessage ( originalMsg : String , a : CorrelationId ) : String = s " ${a.value} $originalMsg "
}

implicit val correlationId = CorrelationId ( " ID " )

val logger = Logger .takingImplicit[ CorrelationId ]( " test " )
logger.info( " Test " ) // takes implicit correlationId and logs "ID Test"

如果要在此处提取与logger IE相关的correlationId对象,请使用getContext

 val context = logger.canLogEv.getContext()

也可以通过CanLog使用MDC ,而不会在执行上下文中遇到任何麻烦。

logger.trace(s"Received value $value from db") // takes implicit correlationId toResult(value) } }">
 case class CorrelationId ( value : String )
implicit case object CanLogCorrelationId extends CanLog [ CorrelationId ] {
  override def logMessage ( originalMsg : String , a : CorrelationId ) : String = {
    MDC .put( " correlationId " , a.value)
    originalMsg
  }

  override def afterLog ( a : CorrelationId ) : Unit = {
    MDC .remove( " correlationId " )
  }
}

implicit val correlationId = CorrelationId ( " ID " )

val logger = Logger .takingImplicit[ CorrelationId ]( " test " )

def serviceMethod ( implicit correlationId : CorrelationId ) : Future [ Result ] = {
  dbCall.map { value =>
    logger.trace( s " Received value $value from db " ) // takes implicit correlationId
    toResult(value)
  }
}

字符串插值

使用Scala的字符串Interpolation logger.error(s"log $value")而不是SLF4J字符串Interpolation logger.error("log {}", value)是惯用的。但是,有一些使用日志消息格式作为分组密钥的工具(例如Sentry)。因此,它们与Scala的字符串插值不太合作。

scala logging用SLF4J的对应物代替了简单的字符串插值:

logger.error( s " my log message: $arg1 $arg2 $arg3 " )
logger.error( " my log message: {} {} {} " , arg1, arg2, arg3)

这对行为没有影响,并且表现应是可比的(取决于基础记录库)。

限制

  • 仅当字符串插值直接在记录语句中使用时起作用。那就是日志消息是静态的(可在编译时可用)。
  • 仅适用于logger.(message)logger.(marker, message)记录方法。如果您要记录异常并使用字符串插值(这是SLF4J API的限制),则它不起作用。

日志消息中的行号?

使用Sourcecode库,可以添加行号信息(对于调试特别有用):

 def foo ( arg : String )( implicit line : sourcecode. Line , file : sourcecode. File ) = {
  ... do something with arg ...
  ... do something with file.value ...
}

foo( " hello " ) // the implicit sourcecode.File is filled in automatically 

维护状态

这个图书馆是社区维护的。在LightBend订阅中不支持它。

贡献政策

很乐意通过其原始作者接受GitHub拉的请求的贡献。在我们接受拉的请求之前,您需要使用您的GitHub帐户在线同意在线登录贡献者许可协议。

下载源码

通过命令行克隆项目:

git clone https://github.com/lightbend-labs/scala-logging.git