Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 尝试使用异常日志记录_Scala_Exception_Logging - Fatal编程技术网

Scala 尝试使用异常日志记录

Scala 尝试使用异常日志记录,scala,exception,logging,Scala,Exception,Logging,Scala的Try非常有用 我希望使用该模式,但记录所有异常 如何执行此操作?定义以下帮助程序: import scala.util.{Try, Failure} def LogTry[A](computation: => A): Try[A] = { Try(computation) recoverWith { case e: Throwable => log(e) Failure(e) } } 然后您可以像使用Try一样使用它,但是任何

Scala的
Try
非常有用

我希望使用该模式,但记录所有异常


如何执行此操作?

定义以下帮助程序:

import scala.util.{Try, Failure}

def LogTry[A](computation: => A): Try[A] = {
  Try(computation) recoverWith {
    case e: Throwable =>
      log(e)
      Failure(e)
  }
}

然后您可以像使用
Try
一样使用它,但是任何异常都将通过
log(e)

记录。您可以使用隐式类进一步调整它

def someMethod[A](f: => A): Try[A] = Try(f)

implicit class LogTry[A](res: Try[A]) {
  def log() = res match {
    case Success(s) => println("Success :) " + s); res
    case Failure(f) => println("Failure :( " + f); res
  }
}
现在您可以调用
someMethod
并在其结果调用
log
如下:

scala> someMethod(1/0).log
Failure :( java.lang.ArithmeticException: / by zero

当然,隐式类中的
println
方法可以替换为您想要的任何日志记录

您使用的术语“例外情况”模棱两可。是可以放置在
抛出
术语后面的任何内容的根。是(另一种生物)的两个后代之一。使这一点更加模棱两可的是,
异常
的后代,这可能是您最想花费日志时间的地方(除非您正在执行较低级别的应用程序框架或硬件驱动程序实现)

假设您希望逐字记录所有Throwable实例,那么您将需要以下内容(不推荐):

外部
try/catch
需要捕获
try
try
/
catch
块中过滤掉的所有
Throwable
实例

也就是说,有一条Java/JVM规则:您应该(同样,除非您正在执行较低级别的应用程序框架或硬件驱动程序实现)

按照这条规则的意图,您需要将
可丢弃的
范围缩小到只在更细粒度级别发出日志,比如说更精细的
java.lang.RuntimeException
。如果是这样,代码将如下所示(推荐):

在上面的两段代码中,您会注意到我使用了
match
,而不是
.recoverWith
。这有助于轻松添加一个有效的re
throw
。事实证明,
Try
上的所有方法本身也用
Try
/
catch
块包装。这意味着,如果您想记录可丢弃的
文件,然后重新抛出它,如果您使用的是
方法之一,请尝试
recoverWith
,重新
抛出
会立即被重新考虑,并被置于
失败
状态,从而完全破坏故意重新
抛出
的价值。通过使用
match
,可以保证重新
抛出
成功,因为它不在任何
Try
方法的范围内


如果您想在这个特定区域周围看到更多的兔子洞,我创建了一个。

开始
Scala 2.13
,链接操作可用于在返回原始值的同时对任何值应用副作用(在本例中是一些日志记录):

import util.chaining._

val x = Try("aa".toInt).tap(_.failed.foreach(println))
// java.lang.NumberFormatException: For input string: "aa"
// x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")
或等效的模式匹配版本:

val x = Try("aa".toInt).tap { case Failure(e) => println(e) case _ => }
// java.lang.NumberFormatException: For input string: "aa"
// x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")

链接操作对值(在本例中为a
Try
)应用了副作用(在本例中为
println
或某些日志记录),同时返回应用了
tap
的原始未修改值(在
Try
):

def tap[U](f:(A)=>U):A


我会试试的。顺便说一句,为了匹配Try源代码,它不应该只捕获非致命异常吗?@SRobertJames-不,因为它已经只捕获了非致命异常,所以只有那些异常需要恢复。除非您的意思是:我可以记录Try的所有异常,包括它无法捕获的异常吗?那么答案是否定的;您必须插入自己的自定义日志代码。如果禁用了可丢弃的
功能,则此解决方案不会发出日志!非致命。您可能不希望在
log
上有类型参数
A
,因为它会隐藏
LogTry
A
。您也可以只返回
res
,而不返回创建新实例的
Success(s)
Failure(f)
。我稍后会回来写一个正式答案。然而,这里有一篇博文,我刚刚完成了对这个问题(以及其他相关问题)的讨论:
def logAtRuntimeException(f: => A): Try[A] =
  Try(f) match {
    case failure @ Failure(throwable) =>
      throwable match {
        case runtimeException: RuntimeException =>
          log(s"Failure: {runtimeException.getMessage}")
      }
      failure
    case success @ _ =>
      success
  }
import util.chaining._

val x = Try("aa".toInt).tap(_.failed.foreach(println))
// java.lang.NumberFormatException: For input string: "aa"
// x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")
val x = Try("aa".toInt).tap { case Failure(e) => println(e) case _ => }
// java.lang.NumberFormatException: For input string: "aa"
// x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")