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软件包中的LazyLogging和StrictLogging特征分别将logger构件定义为懒惰或严格的值,而AnyLogging特征都定义了抽象logger 。
这取决于要使用的个人用例。但是,我们定义了一些可以使用这些特征的方案:
- 如果您重复使用此特征来创建许多对象,请使用
LazyLogging。 - 默认情况下,几乎使用
StrictLogging,尤其是当类是单身人士的情况下,或者您知道日志方法将始终被调用。 - 在编写一些需要访问任何记录器的特征时,请使用
AnyLogging而无需决定特定的实现。
如果有LazyLogging和StrictLogging ,那么基础SLF4J记录仪是根据这些特征混合在一起的类命名的:
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! " ))
}
} 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! " ))
}
} 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 ,而不会在执行上下文中遇到任何麻烦。
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.记录方法。如果您要记录异常并使用字符串插值(这是SLF4J API的限制),则它不起作用。(marker, message)
日志消息中的行号?
使用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帐户在线同意在线登录贡献者许可协议。
通过命令行克隆项目: