如何将堆栈跟踪发送到log4j?

Syn*_*r0r 147 java logging log4j stack-trace

假如您执行e.printStackTrace(),则会捕获异常并在标准输出(例如,控制台)上获取以下内容:

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)
Run Code Online (Sandbox Code Playgroud)

现在我想把它发送到一个记录器,比如log4j,以获得以下内容:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}
Run Code Online (Sandbox Code Playgroud)

ska*_*man 253

您将异常直接传递给记录器,例如

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}
Run Code Online (Sandbox Code Playgroud)

由log4j来渲染堆栈跟踪.

  • 记录器为其第一个参数获取一个对象,并将toString()它.但是第二个参数必须是Throwable并显示堆栈跟踪. (32认同)
  • @Mark:尝试给它一个与上下文相关的消息而不是异常消息,例如当时它实际上尝试做什么? (5认同)
  • 我永远不知道要在第一个字符串中填充什么,通常我只是最终执行“log.error(e.getLocalizedMessage(), e)”,这是完全多余的。它是否处理第一个参数的空值? (2认同)
  • @Mark Peters,一个很好的例子可能是将参数作为消息记录到当前方法,或者 - 对于FileNotFound异常,尝试打开的路径的全名.任何可以帮助你找出问题的东西 - 只是认为你无法调试情况. (2认同)

kts*_*ter 9

您还可以将堆栈跟踪作为字符串通过ExceptionUtils.getStackTrace.

请参阅:ExceptionUtils.java

我只是用它log.debug来保持log.error简单.


bor*_*jab 8

如果要在不涉及异常的情况下记录堆栈跟踪,请执行以下操作:

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);
Run Code Online (Sandbox Code Playgroud)

  • System.lineSeparator()的+1,这帮我打印了一个堆栈跟踪,我从远程服务得到了一个响应 (2认同)
  • 我搜索过什么,但你应该在这里使用 StringBuilder (2认同)

Mic*_*man 8

来自 skaffman 的答案绝对是正确的答案。所有记录器方法,例如error(), warn(), info(),都debug()将 Throwable 作为第二个参数:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}
Run Code Online (Sandbox Code Playgroud)

但是,您也可以将堆栈跟踪提取为字符串。有时,如果您希望使用“{}”占位符来利用格式化功能,这可能很有用 - 请参阅方法void info(String var1, Object... var2);在这种情况下,假设您有一个作为字符串的堆栈跟踪,那么您实际上可以执行以下操作:

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}
Run Code Online (Sandbox Code Playgroud)

这将在最后以与方法相同的方式打印参数化消息和堆栈跟踪: logger.error("error: ", e);

我实际上写了一个开源库,它有一个实用程序,用于将堆栈跟踪提取为字符串,并带有一个选项,可以从堆栈跟踪中巧妙地过滤掉一些噪音。即,如果您指定您对提取的堆栈跟踪感兴趣的包前缀,则会从一些不相关的部分中过滤掉,并为您留下非常大的信息。这是文章的链接,该链接解释了该库具有哪些实用程序以及从何处获取它(作为 maven 工件和 git 源)以及如何使用它。具有堆栈跟踪过滤、Silent String 解析 Unicode 转换器和版本比较的开源 Java 库 参见段落“堆栈跟踪噪声过滤器


ibe*_*beu 6

只是因为它发生在我身上并且可能有用。如果你这样做

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}
Run Code Online (Sandbox Code Playgroud)

您将获得异常的标头,而不是整个堆栈跟踪。因为记录器会认为你在传递一个字符串。不要{}像斯卡夫曼所说的那样做


mbo*_*ess 5

在 Log4j 2 中,您可以使用Logger.having()来记录捕获的异常的堆栈跟踪。

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }
Run Code Online (Sandbox Code Playgroud)