loginScala
什么是在Scala应用程序中logging日志的好方法? 一些与语言哲学一致的东西,不会混淆代码,而且维护性低,不显眼。 这是一个基本的需求清单:
- 简单
- 不会混淆代码。 斯卡拉是简洁的伟大。 我不想让一半的代码成为日志语句
- 日志格式可以改变,以适应我的企业日志和监控软件的其余部分
- 支持日志级别(即debugging,跟踪,错误)
- 可以login到磁盘以及其他目的地(即套接字,控制台等)
- 最小configuration,如果有的话
- 在容器(即networking服务器)
- (可选,但很好有)来作为语言的一部分或作为一个maven工件,所以我不必破解我的构build使用它
我知道我可以使用现有的Java日志logging解决scheme,但是至less有两个失败,即混乱和configuration。
感谢您的回复。
slf4j包装
Scala的日志库大部分都是围绕Java日志框架(slf4j,log4j等)的一些包装,但是到2015年3月为止,幸存的日志库都是slf4j。 这些日志库提供了一些你可以调用info(...)
, debug(...)
等等的log
对象。我不是slf4j的忠实粉丝,但现在它似乎是主要的日志框架。 这里是SLF4J的描述:
对于Java或(SLF4J)的简单日志门面,可以作为各种日志框架(如java.util.logging,log4j和logback)的简单外观或抽象,允许最终用户在部署时插入所需的日志框架。
在部署时更改底层日志库的能力为整个slf4j系列日志logging器带来了独特的特性,您需要注意以下几点:
- classpath作为configuration方法。 slf4j知道你正在使用的底层日志库是通过某个名字加载一个类。 我有问题,其中slf4j无法识别我的logging器时,classloader被定制。
- 因为简单的外观试图成为共同的分母,它仅限于实际的日志调用。 换句话说,configuration不能通过代码完成。
在一个大型项目中,如果每个人都使用slf4j,那么能够控制传递依赖关系的日志logging行为确实很方便。
Scalalogging
Scala Logging由Heiko Seeberger作为他的slf4s的继任者。 它使用macros将呼叫扩展到ifexpression式,以避免可能昂贵的日志调用。
Scala Logging是一个方便和高性能的日志库包装日志库像SLF4J和其他潜在的。
历史logging器
- Logula ,一个由Coda Hale编写的Log4J包装器。 曾经喜欢这个,但现在它被放弃了。
- configgy ,一个java.util.logging包装器,在Scala早期的版本中很stream行。 现在放弃了。
Scala 2.10+考虑types安全的ScalaLogging。 使用macros提供一个非常干净的API
https://github.com/typesafehub/scala-logging
从他们的维基引用:
幸运的是,Scalamacros可以用来使我们的生活更轻松:ScalaLogging为类
Logger
提供了轻量级日志logging方法,这些方法将会扩展到上面的语言。 所以我们要写的是:
logger.debug(s"Some ${expensiveExpression} message!")
macros被应用后,代码将被转换成上述的习惯用法。
此外,ScalaLogging提供了特性Logging
,它可以方便地提供一个Logger
实例,该实例初始化为混合类的名称:
import com.typesafe.scalalogging.slf4j.LazyLogging class MyClass extends LazyLogging { logger.debug("This is very convenient ;-)") }
使用slf4j和一个包装器是不错的,但是当你有两个以上的值进行插值的时候,它的内插使用会被破坏,因为你需要创build一个数组来插入。
更类似Scala的解决scheme是使用thunk或cluster来延迟错误消息的连接。 Lift的logging器就是一个很好的例子
Log.scala Slf4jLog.scala
看起来像这样:
class Log4JLogger(val logger: Logger) extends LiftLogger { override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg) }
请注意,msg是一个名称调用,除非isTraceEnabled为true,否则不会被评估,因此生成一个不错的消息string没有任何代价。 这围绕着slf4j的插值机制,需要parsing错误信息。 使用此模型,可以将任意数量的值插入到错误消息中。
如果你有一个单独的特性,将这个Log4JLogger混合到你的类中,那么你可以做
trace("The foobar from " + a + " doesn't match the foobar from " + b + " and you should reset the baz from " + c")
代替
info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c}, Array(a, b, c))
不要使用Logula
我实际上已经按照尤金的build议进行了尝试,发现它有一个笨拙的configuration,并且受到了一些错误,而这些错误并没有被固定(比如这个 )。 它看起来没有得到很好的维护,它不支持Scala 2.10 。
使用slf4s + slf4j-simple
主要优点:
- 支持最新的Scala 2.10 (迄今为止是M7)
- configuration是多function的,但不能简单。 这是通过系统属性来完成的,您可以通过在脚本中追加类似
-Dorg.slf4j.simplelogger.defaultlog=trace
命令来设置执行命令或硬编码:System.setProperty("org.slf4j.simplelogger.defaultlog", "trace")
。 无需pipe理垃圾configuration文件! - 与IDE很好地匹配。 例如,要在IDEA的特定运行configuration中将日志logging级别设置为“跟踪”,只需进入
Run/Debug Configurations
并将-Dorg.slf4j.simplelogger.defaultlog=trace
添加到VM 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>
这就是我如何得到Scala Logging为我工作:
把它放在你的build.sbt
:
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2", libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
然后,在进行sbt update
,打印出友好的日志消息:
import com.typesafe.scalalogging._ object MyApp extends App with LazyLogging { logger.info("Hello there") }
如果您使用的是Play,那么您当然可以简单地import play.api.Logger
用于编写日志消息的Logger.debug("Hi")
: Logger.debug("Hi")
。
有关更多信息,请参阅文档 。
我从scalax
的Logging
特性中scalax
了一些工作,并创build了一个也集成了一个MessageFormat-based
库的特性。
那么东西看起来像这样:
class Foo extends Loggable { info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 ) }
我们喜欢这个方法。
执行:
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)) }
我使用SLF4J + Logback classic,并像这样应用它:
trait Logging { lazy val logger = LoggerFactory.getLogger(getClass) implicit def logging2Logger(anything: Logging): Logger = anything.logger }
那么你可以使用它更适合你的风格:
class X with Logging { logger.debug("foo") debug("bar") }
但是这种方法当然使用每个类实例的logging器实例。
您应该看看scalax库: http ://scalax.scalaforge.org/在这个库中,有一个Logging特征,使用sl4j作为后端。 通过使用这个特性,你可以很容易地进行login(只需使用inheritance特性的类中的logging器字段)。
Writer
, Monoid
和Monad
实现。
还没有尝试过,但configuration和日志configuration看起来很有希望:
在使用slf4s和logula一段时间后,我写了loglady
,一个简单的日志logging特征,包装slf4j。
它提供了一个类似于Python日志库的API,这使得常见的情况(基本string,简单格式化)变得微不足道,并且避免了对样板文件进行格式化。
我发现使用某种javalogging器,例如sl4j,使用简单的scala包装器非常方便,它带给我这样的语法
val #! = new Logger(..) // somewhere deep in dsl.logging. object User with dsl.logging { #! ! "info message" #! dbg "debug message" #! trace "var a=true" }
在我看来,非常有用的mixin的Javavalidation日志框架和斯卡拉的花式语法。
快速和简单的forms。
Scala 2.10及以上版本:
import com.typesafe.scalalogging.slf4j.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....")
和build.sbt:
libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"
斯卡拉2.11+和更新:
import import com.typesafe.scalalogging.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....")
和build.sbt:
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"
- FB.login对话框在Google Chrome上不会closures
- 浏览器如何知道何时提示用户保存密码?
- 在“使用Facebooklogin示例”中编译错误
- 获取错误org.springframework.beans.factory.NoSuchBeanDefinitionException:没有定义名为“springSecurityFilterChain”的bean
- 用HttpWebRequestlogin到页面
- 尝试调用canOpenURL的iOS 9上的Googlelogin崩溃
- 如何识别Google OAuth2用户?
- Rails的devise:设置密码重置令牌和redirect用户
- 使用Django实现单点login(SSO)