Java异常堆栈跟踪未打印。

10

我有以下代码:

import org.apache.commons.lang.exception.ExceptionUtils;
public void myMethod() {
    try {
        // do something
    } catch (Exception e) {
        System.out.println(ExceptionUtils.getStackTrace(e)); // prints "java.lang.NullPointerException"
        System.out.println(ExceptionUtils.getFullStackTrace(e)); // prints "java.lang.NullPointerException"
        e.printStackTrace(); // prints "java.lang.NullPointerException"
    }
}

我希望看到的输出是一个完整的堆栈跟踪,包括行号以及失败类的层次结构。例如:
Exception in thread "main" java.lang.NullPointerException
        at org.Test.myMethod(Test.java:674)
        at org.TestRunner.anotherMethod(TestRunner.java:505)
        at java.util.ArrayList(ArrayList.java:405)

这段代码正在一个更大的应用程序中运行,该应用程序也有log4j,但我希望能够将异常获取为字符串,以便我可以将其作为电子邮件发送给Java开发人员。
有没有人有任何关于如何将完整的堆栈跟踪捕获为字符串的想法?由于此应用程序在Java 4上运行,因此无法使用Thread.currentThread().getStackTrace()。可能会阻止上述代码打印完整的堆栈跟踪是什么?

看起来NPE中的StackTraceElement数组被重置为空了。有什么东西在NPE上调用setStackTrace吗? - Dan Gravell
@DanGravell - 不,没有任何东西应该调用setStackTrace。 - David
你能在IDE中调试这个吗?或许值得在catch块中设置一个断点,看看异常是否“完美形成”。 - Dan Gravell
添加您的 myMethod() 函数或实际函数的已记录输出。e.printStackTrace(); 通常应打印完整跟踪。 - basiljames
8个回答

18

1
不要在生产服务器上关闭此优化,我会遵循Peter的建议并查看日志中较早的错误。 - Sarel Botha
我同意,如果你拥有代码,那么这是可以做到的。但如果你依赖于别人,只能等待他们修复,这是你能做的最好的事情。 - Vinesh
1
这绝对是我在生产环境遇到类似问题的原因。感谢您的答案! - dpetruha
这个在OpenJDK7上存在,但在OpenJDK8上不存在。 - Champ

13

如果您反复抛出异常,JVM将停止填充堆栈跟踪。我不确定原因,可能是为了减轻JVM的负担。您需要查看早期的堆栈跟踪以查看详细信息。

for (int n = 0; ; n++) {
    try {
        Integer i = null;
        i.hashCode();
    } catch (Exception e) {
        if (e.getStackTrace().length == 0) {
            System.out.println("No more stack trace after " + n + " thrown.");
            break;
        }
    }

打印

No more stack trace after 20707 thrown.

4
有没有任何办法可以将整个堆栈跟踪捕获到字符串中呢?您可以使用以下方法(StringWriter.toString())将堆栈跟踪转换为字符串。
 StringWriter writer = new StringWriter();
 e.printStackTrace( new PrintWriter(writer,true ));
 System. out.println("exeption stack is :\n"+writer.toString());

2

在你的catch块之前,异常可能会被捕获并抛出。也许是在另一个类中,你正在调用该类来执行逻辑。

使用类似于
new Exception(new Throwable("java.lang.NullPointerException")); 创建的异常将打印出类似于您所看到的内容。


事实证明,在try块内部,它调用了另一个方法,该方法具有一个try块和一个catch语句,该语句显式地减少了异常(类似于您的示例,只是他们没有硬编码“NullPointerException”,而是截断了堆栈跟踪的原因)。 - David
@David - 我会认真考虑转向其他产品。故意压制异常信息是违背客户/用户最佳利益的行为。找一个不做这种烂事的替代供应商。 - Stephen C

1

可能您没有控制台输出的appender。建议添加一个。如果没有,可以使用log4j或SLF4J将其记录为LOGGER.error(ex);


有一段时间,我认为这可能是由于控制台日志记录引起的。因此,我尝试将异常存储在字符串中并将其发送到我的电子邮件。但是电子邮件只包含“java.lang.NullPointerException”。 - David

1

我只能想到两个原因,为什么e.printStackTrace()可能只输出字符串"java.lang.NullPointerException"

  • 某些东西可能已经在异常上调用了setStackTrace(new StackTraceElement[0])
  • 异常对象可能是一个棘手的类的实例,该类已覆盖printStackTrace()或其他一些方法以返回误导信息。

1

以上代码为什么无法打印完整的堆栈跟踪信息?

在我的情况下,我捕获的异常的一个超类有以下代码:

/* avoid the expensive and useless stack trace for API exceptions */
@Override
public Throwable fillInStackTrace() {
    return this;
}

这意味着堆栈跟踪数组从未被填充,所以我得到的只有:
org.apache.kafka.AuthException: Auth failed: Invalid username or password

没有堆栈信息,所以不知道发生在哪里。太棒了。
我能够通过获取Exception的源代码,将其复制到我的项目中,并删除fillInStackTrace()方法来覆盖此行为。虽然是一种hack方法,但我需要从那个Exception中获取信息。

-1

请确保使用 e.printStackTrace(),而不是 e.getStackTrace();


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接