【问题标题】:How to log exception stacktrace into debug level?如何将异常堆栈跟踪记录到调试级别?
【发布时间】:2015-07-30 18:16:40
【问题描述】:

这里是在 akka 中使用的调试级函数列表:

def debug(message : scala.Predef.String)
def debug(template : scala.Predef.String, arg1 : scala.Any)
def debug(template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any)
def debug(template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any, arg3 : scala.Any)
def debug(template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any, arg3 : scala.Any, arg4 : scala.Any)

这里的错误级别函数列表:

def error(cause : scala.Throwable, message : scala.Predef.String)
def error(cause : scala.Throwable, template : scala.Predef.String, arg1 : scala.Any)
def error(cause : scala.Throwable, template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any)
def error(cause : scala.Throwable, template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any, arg3 : scala.Any)
def error(cause : scala.Throwable, template : scala.Predef.String, arg1 : scala.Any, arg2 : scala.Any, arg3 : scala.Any, arg4 : scala.Any)

因为在高负载系统中使用的代码我只需要在调试级别记录异常堆栈跟踪。要在调试级别记录,我必须写:

//some where in try catch block
val log : akka.event.LoggingAdapter
val e : Exception

if (log.isDebugEnabled) {
    log.error(e, "Unexpected error")
}

除了混合关卡之外,akka 中还有更好的选择吗?

【问题讨论】:

  • 标题中有错字。异常?
  • 你为什么不直接使用log.debug?如果检查,底层的日志库也在做同样的事情。如果您的字符串需要连接一些变量,您应该将它们作为其他参数传递(以便字符串连接仅在必要时完成)
  • 因为log.debug 没有 Throuble 参数。并且将异常传递给它的参数只打印exception.getMessage

标签: scala logging akka slf4j


【解决方案1】:

这是一个扩展 Akka 日志记录的类型类,它可以在 warninginfodebug 级别上记录 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, ...) 的日志输出。大多数情况下不会注意到差异,因为异常的格式无论如何都是默认格式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    相关资源
    最近更新 更多