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记录仪是根据这些特征混合在一起的类命名的:
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! \" )) } }
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! \" )) } }
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.<level>(message)和logger.<level>(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帐户在线同意在线登录贡献者许可协议。
