Java stack trace utils

Is there a way to dump a stack trace without throwing an exception in java?

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.

10 Answers 10

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.

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

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

private String getCallingMethodName()

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.

Читайте также:  Горизонтальный скроллинг таблицы html

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.

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 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.

@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.

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.

I like this answer because it offers me the opportunity to direct the output. I can replace t.printStackTrace with t.printStackTrace(System.out) .

and it is easy to send to java.util.Logger log.log(Level.SEVERE, «Failed to do something», new Throwable());

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

new Exception("Stack trace").printStackTrace(); 

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

Here are a few snippets from the Javadoc:

List stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList())); 

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.

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:

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.

Источник

How do I log a stacktrace using java’s Logger class

I am using Java’s Logger class. I want to pass ex.printStackTrace() into Logger.log(loglevel, String) , but printStackTrace() returns void . So I am not able to pass and print the stack trace of the exception. Is there any way that I can convert void into String , or are there any other methods to print the whole stack trace of exceptions?

14 Answers 14

You need to understand that void is actually nothingness . You cannot convert what is nothing. You might end up printing void as a string, but (trust me), you don’t want that.

I think what you are looking for is

// assuming ex is your Exception object logger.error(ex.getMessage(), ex); // OR Logger.log(errorLogLevel, ex.getMessage(), ex) 

This will print the error message using the logger that you have configured. For more details, you can take a look at the java docs for Exception#getMessage()

logger.error() is not java.util.logging , but I’m not going to downvote you because I am glad to discover logger.log(Level, Exception, Supplier) . Looks like Oracle have made java.util.logging.Logger seriously ugly! Since they were doing that, it’s strange that they didn’t take it further and create logger.severe(String, Exception) etc

The question asks for a solution using Java’s Logger class. java.util.logging.Logger does not have a method called «error». I have downvoted this answer only because of that.

This is not answering the initial intention to print the stack trace to a logger, at all. getMessage() is not made for this.

LOGGER.log(Level.INFO, ex.getMessage(), ex); 

It is possible to suppress the stack trace by changing the log format. Which formatter are you using and how does your log format look like?

@PanuHaaramo It depends on which formatter you use. The formatter needs to call record.getThrown() in format . Take a look at SimpleFormatter .

Also another alternative would be:

import org.apache.commons.lang3.exception.ExceptionUtils; log.error("Exception : " + ExceptionUtils.getStackTrace(exception)); 

If you’re refering to org.apache.commons.lang3.exception.ExceptionUtils, it’s ExceptionUtils.getStackTrace(e)

There’s an overloaded printStackTrace method that takes in a PrintWriter.

You can do something like this

Writer buffer = new StringWriter(); PrintWriter pw = new PrintWriter(buffer); ex.printStackTrace(pw); Logger.log(loglevel, buffer.toString()); 

With below format you can have the stack trace:

java.util.logging.SimpleFormatter.format=%1$tF %1$tT [%4$-7s][%2$s] %5$s %6$s%n 

The point in this pattern is %6$s. It will print the stack trace.

You can’t convert void into String ; no such conversion exists. void doesn’t return anything back, so you have no value to retrieve.

What you probably want to do is get the message of the exception instead via ex.getMessage() .

You can use the getStackTrace() method to get an array of StackTraceElements, and generate a String from there. Otherwise, if just the final error message is sufficient, use the getMessage() method as suggested by Makoto.

To get the stack trace as a String from an array of StackTraceElement objects, you need to iterate over the array (taken from JDK7 source):

StringBuilder builder = new StringBuilder(); StackTraceElement[] trace = getOurStackTrace(); for (StackTraceElement traceElement : trace) builder.append("\tat " + traceElement + "\n"); 

Another option is to use printStackTrace(PrintStream s) , where you get to specify where you want the stacktrace to be printed:

ByteArrayOutputStream out1 = new ByteArrayOutputStream(); PrintStream out2 = new PrintStream(out1); ex.printStackTrace(out2); String message = out1.toString("UTF8"); 

Источник

How do I print the stack trace of an exception to a stream other than stderr? One way I found is to use getStackTrace() and print the entire list to the stream.

If you want to get exception trace as String you can call getStackTrace method of Trowable (the Exception) that will return array of StackTraceElement objects that you can combine to one String (using toString method of that object to get one line of a trace).

10 Answers 10

This will print the stack trace to std out instead of std error.

@FranklinYu, the whole point of the question is that he doesn’t want to print to stderr, but to another arbitrary stream.

Not beautiful, but a solution nonetheless:

StringWriter writer = new StringWriter(); PrintWriter printWriter = new PrintWriter( writer ); exception.printStackTrace( printWriter ); printWriter.flush(); String stackTrace = writer.toString(); 

Throwable.printStackTrace(..) can take a PrintWriter or PrintStream argument:

That said, consider using a logger interface like SLF4J with an logging implementation like LOGBack or log4j.

For the android dev minimalists: Log.getStackTraceString(exception)

You can’t use this to print to an arbitrary stream. It is useful only if you have a logger configured.

Apache commons provides utility to convert the stack trace from throwable to string.

ExceptionUtils.getStackTrace(e) 

While this answer looks very much correct, it is not an answer to the question. OP asked how he could print the stack trace to another stream.

Even though this might not answer OP’s question, I think this is the best way to have an exception as a String, using a very well established format. Thanks!

I have created a method that helps with getting the stackTrace:

private static String getStackTrace(Exception ex) < StringBuffer sb = new StringBuffer(500); StackTraceElement[] st = ex.getStackTrace(); sb.append(ex.getClass().getName() + ": " + ex.getMessage() + "\n"); for (int i = 0; i < st.length; i++) < sb.append("\t at " + st[i].toString() + "\n"); >return sb.toString(); > 

The Throwable class provides two methods named printStackTrace , one that accepts a PrintWriter and one that takes in a PrintStream , that outputs the stack trace to the given stream. Consider using one of these.

With slf4j e.g via lombok ‘s @Slf4j annotation

out = some stream . try < >catch ( Exception cause )

If you are interested in a more compact stack trace with more information (package detail) that looks like:

 java.net.SocketTimeoutException:Receive timed out at j.n.PlainDatagramSocketImpl.receive0(Native Method)[na:1.8.0_151] at j.n.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:143)[^] at j.n.DatagramSocket.receive(DatagramSocket.java:812)[^] at o.s.n.SntpClient.requestTime(SntpClient.java:213)[classes/] at o.s.n.SntpClient$1.call(^:145)[^] at ^.call(^:134)[^] at o.s.f.SyncRetryExecutor.call(SyncRetryExecutor.java:124)[^] at o.s.f.RetryPolicy.call(RetryPolicy.java:105)[^] at o.s.f.SyncRetryExecutor.call(SyncRetryExecutor.java:59)[^] at o.s.n.SntpClient.requestTimeHA(SntpClient.java:134)[^] at ^.requestTimeHA(^:122)[^] at o.s.n.SntpClientTest.test2h(SntpClientTest.java:89)[test-classes/] at s.r.NativeMethodAccessorImpl.invoke0(Native Method)[na:1.8.0_151] 

you can try to use Throwables.writeTo from the spf4j lib.

Источник

Оцените статью