208

I am thinking of creating a debug tool for my Java application.

I am wondering if it is possible to get a stack trace, just like Exception.printStackTrace() but without actually throwing an exception?

My goal is to, in any given method, dump a stack to see who the method caller is.

bruno
  • 2,213
  • 1
  • 19
  • 31
corgrath
  • 11,673
  • 15
  • 68
  • 99

10 Answers10

324

Yes, simply use

Thread.dumpStack()
jjnguy
  • 136,852
  • 53
  • 295
  • 323
Rob Di Marco
  • 43,054
  • 9
  • 66
  • 56
  • 9
    That is the answer that actually addresses the question. – bruno Jun 10 '15 at 16:53
  • 11
    Very simple and elegant. This should have been the accepted answer. – deLock May 08 '18 at 11:53
  • 20
    Fwiw, the source of this method: `public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }` – JohnK Nov 26 '18 at 19:04
  • 1
    This is by far the best answer to the question if you are happy with outputting to `stderr`, which seems to be the implication of the question. – mike rodent May 02 '20 at 08:24
88

You can also try Thread.getAllStackTraces() to get a map of stack traces for all the threads that are alive.​​​​​​

Jonas Czech
  • 12,018
  • 6
  • 44
  • 65
Prabhu R
  • 13,836
  • 21
  • 78
  • 112
58

If you want the trace for just the current thread (rather than all the threads in the system, as Ram's suggestion does), do:

Thread.currentThread().getStackTrace()

To find the caller, do:

private String getCallingMethodName() {
    StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
    return callingFrame.getMethodName();
}

And call that method from within the method that needs to know who its caller is. However, a word of warning: the index of the calling frame within the list could vary according to the JVM! It all depends on how many layers of calls there are within getStackTrace before you hit the point where the trace is generated. A more robust solution would be to get the trace, and iterate over it looking for the frame for getCallingMethodName, then take two steps further up to find the true caller.

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • 2
    So just create a new Exception on your own and use [1] as the index! – Daniel Jul 07 '11 at 06:21
  • 3
    The title of this question says "without throwing an exception". Granted, you suggest creating the exception but not throwing it, but i still think that's not in the spirit of the question. – Tom Anderson Jul 07 '11 at 10:16
  • 1
    Of course it is. Creating an Exception is the most lowlevel way to get a stacktrace. Even your Thread.currentThread().getStackTrace() does it, but my way does it faster :). – Daniel Jul 07 '11 at 17:19
  • 1
    @Daniel There's another consideration: with many testing frameworks, e.g. Spock, just creating an Exception (without throwing it) will be enough for the framework to pick up on: the test will then consider that an Exception has "occurred" and the test will end, with a fail. – mike rodent Apr 13 '18 at 14:06
  • 1
    @mikerodent: Are you sure? Spock would have to use agents to do that. But anyway, because I just needed to calling class I used Reflection.getCallerClass(2) in an utility function. You won't get the function and line number that way, thought. – Daniel Apr 14 '18 at 22:34
42

You can get a stack trace like this:

Throwable t = new Throwable();
t.printStackTrace();

If you want to access the frame, you can use t.getStackTrace() to get an array of stack frames.

Be aware that this stacktrace (just like any other) may be missing some frames if the hotspot compiler has been busy optimizing things.

Gerco Dries
  • 6,682
  • 1
  • 26
  • 35
  • I like this answer because it offers me the opportunity to direct the output. I can replace `t.printStackTrace` with `t.printStackTrace(System.out)`. –  Oct 31 '15 at 23:21
  • 4
    In one line: `new Throwable().printStackTrace(System.out);` –  Nov 15 '15 at 11:20
  • 1
    This should be the accepted answer. It is simple and straight forward! Thanks for sharing – Sam Oct 08 '17 at 02:26
  • 5
    and it is easy to send to java.util.Logger `log.log(Level.SEVERE, "Failed to do something", new Throwable());` – MitchBroadhead Mar 26 '18 at 10:49
15

Notice that Thread.dumpStack() actually throws an exception:

new Exception("Stack trace").printStackTrace();
Ariel T
  • 2,879
  • 1
  • 21
  • 21
12

Java 9 introduced the StackWalker and supporting classes for walking the stack.

Here are a few snippets from the Javadoc:

The walk method opens a sequential stream of StackFrames for the current thread and then applies the given function to walk the StackFrame stream. The stream reports stack frame elements in order, from the top most frame that represents the execution point at which the stack was generated to the bottom most frame. The StackFrame stream is closed when the walk method returns. If an attempt is made to reuse the closed stream, IllegalStateException will be thrown.

...

  1. To snapshot the top 10 stack frames of the current thread,

    List<StackFrame> stack = StackWalker.getInstance().walk(s ->
     s.limit(10).collect(Collectors.toList()));
    
mkobit
  • 43,979
  • 12
  • 156
  • 150
7

If you need capture output

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

The answer by Rob Di Marco is by far the best if you are happy to output to stderr.

If you want to capture to a String, with new lines as per a normal trace, you could do this:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
mike rodent
  • 14,126
  • 11
  • 103
  • 157
7

You can also send a signal to the JVM to execute Thread.getAllStackTraces() on a running Java process by sending a QUIT signal to the process.

On Unix/Linux use:

kill -QUIT process_id, where process_id is the process number of your Java program.

On Windows, you can press Ctrl-Break in the application, although you usually won't see this unless you're running a console process.

JDK6 introduced another option, the jstack command, which will display the stack from any running JDK6 process on your computer:

jstack [-l] <pid>

These options are very useful for applications which are running in a production environment and cannot be modified easily. They're especially useful for diagnosing runtime deadlocks or performance problems.

http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html

Andrew Newdigate
  • 6,005
  • 3
  • 37
  • 31
0

HPROF Java Profiler

You don't even have to do this in the code. You can attach the Java HPROF to your process and at any point hit Control-\ to output heap dump, running threads, etc . . . without mucking up your application code. This is a bit outdated, Java 6 comes with the GUI jconsole, but I still find HPROF to be very useful.

Kenster
  • 23,465
  • 21
  • 80
  • 106
Gandalf
  • 9,648
  • 8
  • 53
  • 88