ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Java 中获取当前堆栈跟踪?

我如何在 Java 中获得当前的 stack trace,就像在 .NET 中你可以如何做 Environment.StackTrace

我找到了 Thread.dumpStack(),但这不是我想要的 - 我想取回堆栈跟踪,而不是打印出来。

在 Eclipse 中调试时,我总是使用“new Exception().printStackTrace()”作为监视表达式。当您在断点处暂停并想知道您来自哪里时,这很方便。
@TimBüthe:当您处于调试模式时,Eclipse 不是已经告诉您堆栈跟踪了吗?我认同。
Arrays.toString(Thread.currentThread().getStackTrace());很简单。
@Arkanon它指的是java,并展示了他们将如何在.net中做到这一点以及java中的等价物。
要很好地打印它,您可以使用 apache StringUtils: StringUtils.join(currentThread().getStackTrace(), "\n");

D
David Newcomb

您可以使用 Thread.currentThread().getStackTrace()

这将返回一个表示程序当前堆栈跟踪的 StackTraceElement 数组。


如果您已经在使用 apache commons 来获取字符串,这是一个很酷的单行:String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
数组中的第一个元素(索引 0)是 java.lang.Thread.getStackTrace 方法,第二个(索引 1)通常是第一个感兴趣的元素。
将堆栈跟踪转换为在没有异常且未使用 Apache Arrays.toString(Thread.currentThread().getStackTrace()) 时有效的字符串
@Tony 的解决方案更好,因为它不需要 throwable
正如下面的许多答案所指出的 - new Throwable().getStackTrace() 更快,因为它不需要检查 this != Thread.currentThread() 并绕过通过子类 (Exception extends Throwable) 调用它的潜在 JVM 开销
J
JohnK
StackTraceElement[] st = Thread.currentThread().getStackTrace();

如果您不在乎堆栈的第一个元素是什么,那很好。

StackTraceElement[] st = new Throwable().getStackTrace();

如果这很重要,将为您当前的方法定义一个位置。


(new Throwable()).getStackTrace() 的执行速度也更快(参见 bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
您能否更详细地解释 Thread.currentThread().getStackTrace() 的结果与 new Throwable().getStackTrace() 的结果有何不同?我两种都试过了,发现 Thread.currentThread().getStackTrace() 返回一个数组, Thread.getStackTrace 在索引 0 中,调用方法在索引 1 处。新的 Throwable().getStackTrace() 方法返回一个数组,调用索引 0 处的方法。似乎这两种方法都为当前方法定义了位置,但位置不同。您还指出了另一个区别吗?
@Ryan,不能保证 Thread.currentThread().getStackTrace() 不承诺在方法的不同版本上保持该位置。因此,当您碰巧检查它在索引 1 处。在 Sun 的某些版本的 JVM(1.5 或 1.6,不记得)上,它是索引 2。这就是我所说的定义位置的意思——规范要求它在那里,并在未来留在那里。
@MightyE 该错误现在报告为已在 Java 6 中修复。查看内部结构,当请求的堆栈跟踪位于当前线程上时,它现在看起来像 (new Exception()).getStackTrace() (对于 Thread.currentThread().getStackTrace(); 始终是这种情况
@MJustin:该错误并未“现在”报告为已修复,甚至在 MightyE 撰写评论之前已经修复了六年。事实上,它甚至在 Stackoverflow 成立之前就已经修复了……
d
dStulle
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}

java在Throwable上定义了一个printStackTrace方法,你可以这样做:new Exception().printStackTrace(System.out)我记得,for循环的开销可能更少,但无论如何你应该只将它用作调试......
我最喜欢这个,因为你有机会通过包装你的 println 语句来去除噪音,例如 for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
j
jjnguy
Thread.currentThread().getStackTrace();

从JDK1.5开始可用。

对于旧版本,您可以将 exception.printStackTrace() 重定向到 StringWriter()

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

new Throwable().getStackTrace() 从 JDK1.4 开始可用...
m
mike rodent

托尼作为对已接受答案的评论,给出了似乎是实际回答 OP 问题的最佳答案:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );

... OP 确实 NOT 询问如何从 Exception 的堆栈跟踪中获取 String。尽管我是 Apache Commons 的忠实粉丝,但当有像上面这样简单的东西时,没有合乎逻辑的理由使用外部库。


我有一个线程列表,我需要打印它们的堆栈跟踪。
在这种情况下,请确保使用 Thread.getAllStackTraces(),它会为您提供 Map<Thread, StackTraceElement[]>。 Hotspot 将在需要安全点时对所有线程进行安全点。 Zing 可以将单个线程带到安全点,而不会干扰其他线程。获取堆栈跟踪需要一个安全点。 Thread.getAllStackTraces() 获取所有堆栈跟踪并仅停止所有线程一次。当然,您必须找出您真正感兴趣的映射。
s
stikkos

您可以为此使用 Apache 的公共资源:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

这是一个很好的单行解决方案。仅供参考,对于使用 org.apache.commons.lang3 的任何人,整行是:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
只是重申一下 fileoffset 在移至 org.apache.commons.lang3 时的评论,我最初忽略了这一点 - 导入使用 lang3 而不是 lang,并将 getFullStackTrace 替换为 getStackTrace
这是非常有用的!使用 IDE(例如 IntelliJ IDEA)进行调试时,最好使用 ExceptionUtils.getStackTrace(new Throwable()) 表达式来获取堆栈跟踪。
V
Vicky Kapadia

在 android 上一个更简单的方法是使用这个:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 

getStackTraceString 在哪里定义?这是来自第三方日志库吗?
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
k
kukis

另一种解决方案(仅 35 31 个字符):

new Exception().printStackTrace();   
new Error().printStackTrace();

很棒的解决方案。现在我不必遍历所有堆栈帧
A
Adamski

要获取所有线程的堆栈跟踪,您可以使用 jstack 实用程序 JConsole 或发送 kill -quit 信号(在 Posix 操作系统上)。

但是,如果您想以编程方式执行此操作,您可以尝试使用 ThreadMXBean:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);

for (ThreadInfo info : infos) {
  StackTraceElement[] elems = info.getStackTrace();
  // Print out elements, etc.
}

如前所述,如果您只想要当前线程的堆栈跟踪,它会容易得多 - 只需使用 Thread.currentThread().getStackTrace();


此答案中的代码片段最接近以编程方式生成您在向 JVM 发送 QUIT 信号(在类 Unix 系统上)或 <ctrl><break> 时看到的那种转储。在 Windows 上。与其他答案不同,您可以看到监视器和同步器以及堆栈跟踪(例如,如果您遍历 StackTraceElement 数组并在每个数组上执行 System.err.println(elems[i]))。片段中的第二行在 dumpAllThreads 之前缺少 bean.,但我想大多数人都可以解决这个问题。
j
jjnguy

傻我,这是Thread.currentThread().getStackTrace();


C
Christian Ullenboom

在 Java 9 中有一种新方法:

public static void showTrace() {

  List<StackFrame> frames =
    StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
               .walk( stream  -> stream.collect( Collectors.toList() ) );

  for ( StackFrame stackFrame : frames )
    System.out.println( stackFrame );
}

有趣的。 :-)
E
Evan Knowles

获取堆栈跟踪:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();

打印堆栈跟踪(JAVA 8+):

Arrays.asList(ste).forEach(System.out::println);

打印堆栈(JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);

T
Thomas Adkins

我建议

  Thread.dumpStack()

是一种更简单的方法,并且具有在可能根本没有问题时实际上不构造异常或可抛出的优点,并且更重要。


好的,实际上,dumpStack() 是一个静态方法,应该以静态方式访问。谢谢,日食!
我喜欢这个快捷方式,但是这个方法的源代码是:new Exception("Stack trace").printStackTrace(); 所以它实际上是在构建一个 Throwable
问题是“我找到了 Thread.dumpStack() 但这不是我想要的 - 我想取回堆栈跟踪,而不是打印出来。”
Z
Zitrax

用番石榴串起来:

Throwables.getStackTraceAsString(new Throwable())

S
Salvador Valencia

我有一个实用方法,它返回一个带有堆栈跟踪的字符串:

static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
}

就像logit一样...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}

这看起来像是由 Netbeans 自动生成的。
logger 是内置记录器还是您创建并写入文件的记录器。
@Doug Hauf,logger 是对内置 Java Logger 的引用。确保您配置了 logging.properties 文件。像这样在类的开头添加它: private static final Logger logger = Logger.getLogger( Your_Class_Name.class.getName() );
java.util.logging.Logger#log(Level, String, Throwable) 已经这样做了。这是在不必要地重写 Java 标准库中已经存在的东西,并将新开发人员指向错误的方向,即远离文档。现在通过执行此操作,您已强制 Stacktrace 以某种方式格式化,其中 logging API 允许您在指定时动态改变日志语句的格式。据我所知,log4j 也有类似的行为。不要重新发明轮子,因为你最终会失去我已经解释过的东西。
它也存在于 2012 年。不幸的是,日期对您的情况没有影响。请参阅 [链接](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.Level, java.lang.String, java.lang .Throwable))、[链接](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.LogRecord))等(那里有几个函数将 Throwable 传递到 HandlerFormatter 在 2012 年,即 Java7,比我在这里列出的要多。这些函数的历史比 Java7 存在的时间要长得多;因此 J2SE 5.0 javadocs)
b
butterchicken
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

或者

Thread.currentThread().getStackTrace()

您的顶级示例不会只为您提供相对于 try/catch 块的堆栈跟踪吗?
两者有什么区别
P
Peter Mortensen

也许你可以试试这个:

catch(Exception e)
{
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    e.printStackTrace(pw);
    String errorDetail = writer.toString();
}

字符串 'errorDetail' 包含堆栈跟踪。


Z
Zar E Ahmer
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

数组的最后一个元素表示堆栈的底部,它是序列中最近的方法调用。

A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().

循环通过 StackTraceElement 并获得您想要的结果。

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}

感谢您提到最后一个元素包含最新的。违反直觉,为我节省了一些时间。
.toString() 也会很好地将所有数据输出到一个字符串中
S
Sampath

如果要检查进程的当前调用堆栈,可以使用 jstack 实用程序。

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

佚名

我使用了上面的答案并添加了格式

public final class DebugUtil {

    private static final String SEPARATOR = "\n";

    private DebugUtil() {
    }

    public static String formatStackTrace(StackTraceElement[] stackTrace) {
        StringBuilder buffer = new StringBuilder();
        for (StackTraceElement element : stackTrace) {
            buffer.append(element).append(SEPARATOR);
        }
        return buffer.toString();
    }

    public static String formatCurrentStacktrace() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return formatStackTrace(stackTrace);
    }
}

K
Kubach

对于只想将当前堆栈跟踪记录到他们的日志的人,我会选择:

getLogger().debug("Message", new Throwable());

干杯


不要忘记创建 Throwable 的新实例是一项缓慢的操作,并且会减慢您的代码速度,即使您禁用了日志上的调试级别。最好的方法是验证是否启用了调试级别“if (getLogger().isDebugEnabled()) {/*log code*/}。无论如何,问题是“我想取回堆栈跟踪,而不是打印出来” ...
S
SkyWalker

这是一篇旧帖子,但这是我的解决方案:

Thread.currentThread().dumpStack();

更多信息和更多方法:http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


由于 Thread.dumpStack() 是静态的,你应该直接调用它。
OP 表示他们希望在代码中引用堆栈跟踪,而不是打印出来。
正如@DavidAvendasora 提到的,您应该直接调用 Thread.dumpStack() 因为它的静态方法。
问题是“我找到了 Thread.dumpStack() 但这不是我想要的 - 我想取回堆栈跟踪,而不是打印出来。”