这是一个扩展 Akka 日志记录的类型类,它可以在 warning、info 和 debug 级别上记录 throwable:
AkkaThrowableLogging
import java.io.{PrintWriter, StringWriter}
import akka.event.LoggingAdapter
object AkkaThrowableLogging {
implicit class LoggingAdapterOps(logger: LoggingAdapter) {
private def throwableStr(t: Throwable): String = {
val sw = new StringWriter()
val pw = new PrintWriter(sw, true)
t.printStackTrace(pw)
sw.getBuffer.toString
}
private def concat(cause: Throwable, message: String) = s"$message\n${throwableStr(cause)}"
/**
* Log message at warning level, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def warning(cause: Throwable, message: String): Unit =
logger.warning(concat(cause, message))
/**
* Message template with 1 replacement argument, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def warning(cause: Throwable, template: String, arg1: Any): Unit =
logger.warning(concat(cause, template), arg1)
/**
* Message template with 2 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit =
logger.warning(concat(cause, template), arg1, arg2)
/**
* Message template with 3 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit =
logger.warning(concat(cause, template), arg1, arg2, arg3)
/**
* Message template with 4 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit =
logger.warning(concat(cause, template), arg1, arg2, arg3, arg4)
/**
* Log message at info level, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def info(cause: Throwable, message: String): Unit =
logger.info(concat(cause, message))
/**
* Message template with 1 replacement argument.
* @see [[LoggingAdapter]]
*/
def info(cause: Throwable, template: String, arg1: Any): Unit =
logger.info(concat(cause, template), arg1)
/**
* Message template with 2 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def info(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit =
logger.info(concat(cause, template), arg1, arg2)
/**
* Message template with 3 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def info(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit =
logger.info(concat(cause, template), arg1, arg2, arg3)
/**
* Message template with 4 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def info(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit =
logger.info(concat(cause, template), arg1, arg2, arg3, arg4)
/**
* Log message at debug level, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def debug(cause: Throwable, message: String): Unit =
logger.debug(concat(cause, message))
/**
* Message template with 1 replacement argument.
* @see [[LoggingAdapter]]
*/
def debug(cause: Throwable, template: String, arg1: Any): Unit =
logger.debug(concat(cause, template), arg1)
/**
* Message template with 2 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def debug(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit =
logger.debug(concat(cause, template), arg1, arg2)
/**
* Message template with 3 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def debug(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit =
logger.debug(concat(cause, template), arg1, arg2, arg3)
/**
* Message template with 4 replacement arguments, including the exception that caused the error.
* @see [[LoggingAdapter]]
*/
def debug(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit =
logger.debug(concat(cause, template), arg1, arg2, arg3, arg4)
}
}
用法
import AkkaThrowableLogging._
log.warning(new Exception("FooBarBaz"), "Hello {}", "world")
输出:
[WARN] [10/16/2016 19:05:50.614] [ScalaTest-run-running-AkkaThrowableLoggingTest] [AkkaThrowableLoggingTest(akka://AkkaTest)] Hello world
java.lang.Exception: FooBarBaz
at test.AkkaThrowableLoggingTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(AkkaThrowableLoggingTest.scala:12)
at test.AkkaThrowableLoggingTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(AkkaThrowableLoggingTest.scala:11)
at test.AkkaThrowableLoggingTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(AkkaThrowableLoggingTest.scala:11)
at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
...
警告:错误级别的日志输出可能与较低级别不同
异常不能传递给底层的日志框架(例如log4j、logback等),因为Akka的LoggingAdapter没有提供API来做这些。因此,该异常不能在该级别上进行格式化,而是由throwableStr 函数处理,该函数使用默认的Java 格式(调用printStackTrace 时得到的)。 log.error(e, ...) 的日志输出可能因此不同于log.warning(, ...)、log.info(e, ...) 或log.debug(e, ...) 的日志输出。大多数情况下不会注意到差异,因为异常的格式无论如何都是默认格式。