How can I convert a stack trace to a string?
Asked Answered
C

32

1718

What is the easiest way to convert the result of Throwable.getStackTrace() to a string that depicts the stacktrace?

Cloyd answered 19/7, 2009 at 11:31 Comment(12)
Because jqno's answer actually uses the Throwable.getStackTrace() method that you specified in your question, whereas Brian doesn't. He uses Throwable.printStackTrace() instead.Miche
Just about every Java project should include Apache commons-lang. It includes many convenience methods implementing extremely common development needs.Suspensive
@StijndeWitt Those three lines of code almost certainly need factoring out of the place you've called them. Since you don't know where to put them, they'll go in your utility toolbox with all the other useful snippets. Bingo! you've just reinvented guava / commons-lang / whatever... only not so well. Import a sensible utilities library instead, and save reinventing the wheel. The true sign of a novice is thinking you can do a better job than the library writers.Abilene
NB Single Level of Abstraction Principle is the reason this sort of thing should be factored out. Aids readability and testability, uncovers reusable elements. See: slideshare.net/guestebde/10-ways-to-improve-your-code-neal-fordAbilene
1. Guava has - Throwables.getStackTraceAsString(e) 2. Apache Commons Lang - ExceptionUtils.getFullStackTrace 3. Write our own custom methodsBash
@AndrewSpencer I don't understand why you guys try so hard to bash StijndeWitt for wanting to achieve this with some small snippet. There is really not much danger in writing a tiny utility method (I don't see it as "SHEER ARROGANCE oh nooooo!! he thinks he's better than Apache!!"). There are tons of projects especially in non-Java JVM languages that really don't want to include Guava or Commons Lang just to log a stacktrace. I write Scala & Clojure libraries and certainly will not be making Apache Commons Lang a transitive dependency just for one method.Subzero
@Subzero Not bashing, just qualified disagreement. It was a bit too snide, I was spoiling for a fight after seeing some bad homebrewed utilities. I agree there are reasons not to add a dependency, I just more often see the opposite mistake.Abilene
@Gewure We're so much more evolved and advanced now in our knowledge and understanding of the code. No need for such petty questions any longer. Let the commonfolk rot in their deficiencies.Viewfinder
I came here because when writing Amazon Lambda functions in Java you may want to avoid importing libraries, since they make the container startup time suck. So sometimes it's still necessary to reinvent the wheel. Or maybe I could solve this with ProGuard...Lanneret
@Viewfinder i don't know wether i interpret your sarcasm? correctly, but i think you didn't interprete me correctly either: I wanted to say, that SO has a Problem. Indeed it has turned elitist. It completely fails to open a connection for newbies to enter. E.g. they didn't want a non-english SO. Which is undemocratic and elitist. There are ppl who can program/want to but don't speak proper english.Robers
@Robers It would have helped if you didn't delete your comment... It was obviously sarcasm though. S.O. has always been full of elitists and close-minded snobs. It's not really S.O.'s fault, I don't think, but just a general flaw with mankind that gets put on display very prominently here. As for English speaking: there is some sensibility to both sides; I can only speak to the argument itself though.Viewfinder
Use commons-lang. Josh Bloch says: "Know and use the libraries.[...] don’t reinvent the wheel.If you need to do something that seems like it should be reasonably common,there may already be a class in the libraries that does what you want. If there is, use it; if you don’t know, check.[...]Library code is likely to be better than code that you’d write yourself and is likely to improve over time.This is no reflection on your abilities as a programmer.Economies of scale dictate that library code receives far more attention than most developers could afford to devote to the same functionality."Actuality
C
1145

One can use the following method to convert an Exception stack trace to String. This class is available in Apache commons-lang which is most common dependent library with many popular open sources

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

Cassowary answered 21/1, 2010 at 14:39 Comment(6)
@Stijn - to be fair (I wrote the current highest voted answer below) it's worth looking at commons-lang for a lot more functionalityAnticyclone
@StijndeWitt Commons Lang is pretty common. It's already present in most of my projects/proyects at work.Affiance
@Hugo thanks, was going to use the StringWriter to avoid adding a new library--turns out it's already a dependency of 3 of my dependencies. So to the rest, check if you have it already.Kinetics
@MartinAsenov - following your logic you'd never use such a library, would you ? You wouldn't use it unless you're already using it ?Anticyclone
Fyi, the package has changed and the class is now at: org.apache.commons.lang3.exception.ExceptionUtils.Tentmaker
This method was most useful for me to just log the entire error (message + cause + stacktrace) into my database for further debugging: ExceptionUtils.getFullStackTrace(e)Buhr
A
2370

Use Throwable.printStackTrace(PrintWriter pw) to send the stack trace to an appropriate writer.

import java.io.StringWriter;
import java.io.PrintWriter;

// ...

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);
Anticyclone answered 19/7, 2009 at 11:36 Comment(7)
This does trim the stack trace, the same way printStackTrace(). All exceptions in the stack are visible but for each exception the stack may be trimmed. Anyone requiring the entire trace should consider this.Harrell
This, as it turns out, is pretty much exactly what apache's ExceptionUtils.getStackTrace() method does. Almost to the letter actually.Cherrylchersonese
@BrianAgnew, shouldn't you close the StringWriter and PrintWriter ?Denn
@MuhammadGelbana - yes. The above is shown for expediency. I suspect if you don't it wouldn't cause a problem, but I would advocate it on grounds of good practiseAnticyclone
@BrianAgnew, thanks for the reply. It got me curious and here is what I found: #14543035Denn
This should be the chosen answer. no external libraries, simple, quick, and functions perfectly.Degenerate
@MuhammadGelbana In general, yes, but since it's a string writer, there's nothing to close. StringWriter's implementation of close is an empty method and PrintWriter does some locking trickery, before calling the close method on the wrapped writer, which in this case with StringWriter is nothing. Therefore closing would just waste cpu cycles here, which is probably also why Apache didn't add any close or try-with-resources to their implementation.Sox
C
1145

One can use the following method to convert an Exception stack trace to String. This class is available in Apache commons-lang which is most common dependent library with many popular open sources

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

Cassowary answered 21/1, 2010 at 14:39 Comment(6)
@Stijn - to be fair (I wrote the current highest voted answer below) it's worth looking at commons-lang for a lot more functionalityAnticyclone
@StijndeWitt Commons Lang is pretty common. It's already present in most of my projects/proyects at work.Affiance
@Hugo thanks, was going to use the StringWriter to avoid adding a new library--turns out it's already a dependency of 3 of my dependencies. So to the rest, check if you have it already.Kinetics
@MartinAsenov - following your logic you'd never use such a library, would you ? You wouldn't use it unless you're already using it ?Anticyclone
Fyi, the package has changed and the class is now at: org.apache.commons.lang3.exception.ExceptionUtils.Tentmaker
This method was most useful for me to just log the entire error (message + cause + stacktrace) into my database for further debugging: ExceptionUtils.getFullStackTrace(e)Buhr
I
506

This should work:

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Impulse answered 19/7, 2009 at 11:41 Comment(8)
Concise in java context is always hillarious. That printStackTrace should just return string, leaving decision on whether print it or not to user :)Daffodil
printStackTrace printing in the console is acceptable, but at least a getStackTrace returning it as a String should be available by defaultSauer
What part of this is concise? You have to construct 2 objects which exist for no purpose other than to put the stack trace into a string.Melloney
@Daffodil A method called printXXX() should print XXX.Urease
@Greg Actually that wasn't even sarcasm, it just required a plain reading of what he said.Viewfinder
Printing an exception without a stack trace is (nearly) worthless most of the time. The default behavior of Throwable.toString() should be to return a human readable explanation followed by the stack trace. If I want only the message, I'll ask for it, likewise the stack. Again, Java developers are mostly schoolkids, who seem to not ever actually do any development except for Java itself. If they did, they would design their stuff to be much easier to use.Keratin
@Keratin well, in a professional environment, I hardly ever had the need to directly print an exception anywhere - it is usually passed to a logging library, and the logging configuration takes care of all the details on what level of detail about the exception ends up in which logfile, and how it gets formatted there.Blackcap
Do i need to close Printwriter when using this code?Nullifidian
B
267

If you are developing for Android, a far easier way is to use this:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

The format is the same as getStacktrace, for e.g.

09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException
09-24 16:09:07.042: I/System.out(4844):   at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43)
09-24 16:09:07.042: I/System.out(4844):   at android.app.Activity.performCreate(Activity.java:5248)
09-24 16:09:07.043: I/System.out(4844):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.access$800(ActivityThread.java:139)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Looper.loop(Looper.java:136)
09-24 16:09:07.044: I/System.out(4844):   at android.app.ActivityThread.main(ActivityThread.java:5097)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invokeNative(Native Method)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invoke(Method.java:515)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
Brownfield answered 30/4, 2012 at 7:29 Comment(1)
If any of the throwables in the cause chain is an UnknownHostException, this returns an empty string. See developer.android.com/reference/android/util/LogGaudette
N
156

Guava's Throwables class

If you have the actual Throwable instance, Google Guava provides Throwables.getStackTraceAsString().

Example:

String s = Throwables.getStackTraceAsString ( myException ) ;

This uses printStackTrace under the covers so it outputs a recurisve, trimmed stack trace (i.e., one where frames common to multiple causes in the cause chain are printed only once).

Nishanishi answered 15/2, 2012 at 10:20 Comment(0)
C
120

WARNING: Does not include cause (which is usually the useful bit!)

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}
Conium answered 19/7, 2009 at 11:38 Comment(0)
B
108

For me the cleanest and easiest way was:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());
Banditry answered 15/12, 2011 at 14:37 Comment(2)
The code is clean, but the output is not. You have to do a .replaceAll(", ", "\n") in the end. However you lose the indentation that printStackTrace proposes.Heretofore
This is useful when you log trace in a single linePennell
A
30
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}
Algar answered 3/10, 2013 at 19:15 Comment(1)
Hi, I would just like to point out that the comments section of the answer being cited points out that the StringWriter and PrintWriter objects ought to be closed....(or i guess only the PrintWriter needs to be closed since closing it should close the StringWriter too)Rampart
B
27

The following code allows you to get the entire stackTrace with a String format, without using APIs like log4J or even java.util.Logger:

catch (Exception e) {
    StackTraceElement[] stack = e.getStackTrace();
    String exception = "";
    for (StackTraceElement s : stack) {
        exception = exception + s.toString() + "\n\t\t";
    }
    System.out.println(exception);
    // then you can send the exception string to a external file.
}
Braise answered 24/10, 2012 at 16:57 Comment(0)
J
24

Here is a version that is copy-pastable directly into code:

import java.io.StringWriter; 
import java.io.PrintWriter;

//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));

//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());

Or, in a catch block

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}
Jobbery answered 12/6, 2012 at 16:15 Comment(0)
I
24

Print the stack trace to a PrintStream, then convert it to a String:

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}
Intersex answered 23/4, 2018 at 12:6 Comment(0)
S
21
Arrays.toString(thrown.getStackTrace())

Is the easiest way to convert the result into String I am using this in my program to print the stack trace

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Sampson answered 26/12, 2017 at 13:37 Comment(0)
G
20

Kotlin >= 1.4

Use the built-in function stackTraceToString() on a Throwable.

Kotlin < 1.4

Extending the Throwable class will give you the String property error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }
Gest answered 10/3, 2017 at 11:24 Comment(1)
Starting Kotlin 1.4 there is now a built-in API to do this kotlinlang.org/api/latest/jvm/stdlib/kotlin/…Delacourt
W
14

if you are using Java 8, try this

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

you can find the code for getStackTrace() function provided by Throwable.java as :

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

and for StackTraceElement, it provides toString() as follows:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

So just join the StackTraceElement with "\n".

Wame answered 10/4, 2018 at 7:58 Comment(1)
And if you want limit it, you can use the method limit(5) on the stream.Coronation
E
13

Printing stack trace to string

import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceUtils {
    public static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringWriter sw = new StringWriter();
        printStackTrace(stackTrace, new PrintWriter(sw));
        return sw.toString();
    }
    public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
        for(StackTraceElement stackTraceEl : stackTrace) {
            pw.println(stackTraceEl);
        }
    }
}

It's useful when you want to print the current thread stack trace without creating instance of Throwable - but note that creating new Throwable and getting stack trace from there is actually faster and cheaper than calling Thread.getStackTrace.

Edd answered 11/5, 2011 at 18:40 Comment(0)
N
11
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}
Nowadays answered 14/9, 2017 at 9:44 Comment(0)
C
10

Code from Apache Commons Lang 3.4 (JavaDoc):

public static String getStackTrace(final Throwable throwable) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw, true);
    throwable.printStackTrace(pw);
    return sw.getBuffer().toString();
}

The difference with the other answers is that it uses autoFlush on the PrintWriter.

Charley answered 7/7, 2015 at 16:59 Comment(0)
B
9

The clever sniping in the first set of comments was very amusing, but it really depends on what you are trying to do. If you don't already have the correct library, then 3 lines of code (as in D. Wroblewski's answer) is perfect. OTOH, if you already have the apache.commons library (as most large projects will), then Amar's answer is shorter. OK, it might take you ten minutes to get the library and install it correctly (less than one if you know what you're doing). But the clock is ticking, so you may not have the time to spare. Jarek Przygódzki had an interesting caveat--"If you don't need nested exceptions".

But what if I do need the full stack traces, nested and all? In that case, the secret is to use apache.common's getFullStackTrace (see http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html#getFullStackTrace%28java.lang.Throwable%29)

It saved my bacon. Thanks, Amar, for the hint!

Boatbill answered 15/4, 2014 at 15:7 Comment(0)
U
9

With Java 8 Stream API you can do something like this:

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

It will take array of stack trace elements, convert them to string and join into multiline string.

Untwist answered 29/9, 2019 at 8:56 Comment(1)
This solution is removing message and is ignoring all parent traceLeastways
P
8

Without java.io.* it can be done like this.

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

And then the trace variable holds your stack trace. Output also holds the initial cause, the output is identical to printStackTrace()

Example, printStackTrace() yields:

java.io.FileNotFoundException: / (Is a directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
    at Test.main(Test.java:9)

The trace String holds, when printed to stdout

java.io.FileNotFoundException: / (Is a directory)
     at java.io.FileOutputStream.open0(Native Method)
     at java.io.FileOutputStream.open(FileOutputStream.java:270)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
     at Test.main(Test.java:9)
Philana answered 7/6, 2016 at 20:30 Comment(0)
O
5

an exapansion on Gala's answer that will also include the causes for the exception:

private String extrapolateStackTrace(Exception ex) {
    Throwable e = ex;
    String trace = e.toString() + "\n";
    for (StackTraceElement e1 : e.getStackTrace()) {
        trace += "\t at " + e1.toString() + "\n";
    }
    while (e.getCause() != null) {
        e = e.getCause();
        trace += "Cause by: " + e.toString() + "\n";
        for (StackTraceElement e1 : e.getStackTrace()) {
            trace += "\t at " + e1.toString() + "\n";
        }
    }
    return trace;
}
Oliphant answered 15/7, 2016 at 10:11 Comment(0)
G
5

Scala version

def stackTraceToString(e: Exception): String = {
  import java.io.{PrintWriter, StringWriter}
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}
Glassworks answered 5/3, 2019 at 15:43 Comment(0)
M
4

If you don't want to use an external library and you're not developing for Android, you could create an 'extension' method like this:

public static String getStackTraceString(Throwable e) {
    return getStackTraceString(e, "");
}

private static String getStackTraceString(Throwable e, String indent) {
    StringBuilder sb = new StringBuilder();
    sb.append(e.toString());
    sb.append("\n");

    StackTraceElement[] stack = e.getStackTrace();
    if (stack != null) {
        for (StackTraceElement stackTraceElement : stack) {
            sb.append(indent);
            sb.append("\tat ");
            sb.append(stackTraceElement.toString());
            sb.append("\n");
        }
    }

    Throwable[] suppressedExceptions = e.getSuppressed();
    // Print suppressed exceptions indented one level deeper.
    if (suppressedExceptions != null) {
        for (Throwable throwable : suppressedExceptions) {
            sb.append(indent);
            sb.append("\tSuppressed: ");
            sb.append(getStackTraceString(throwable, indent + "\t"));
        }
    }

    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(indent);
        sb.append("Caused by: ");
        sb.append(getStackTraceString(cause, indent));
    }

    return sb.toString();
}
Myocarditis answered 13/9, 2014 at 11:59 Comment(0)
R
4

The solution is to convert the stackTrace of array to string data type. See the following example:

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}
Recognizance answered 30/3, 2018 at 18:39 Comment(0)
P
3

My oneliner to convert stack trace to the enclosed multi-line string:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

Easy to pass to the logger "as is".

Pansypant answered 17/3, 2018 at 10:32 Comment(2)
You get something that differs from printStackTrace() Here you will loose: 1) Exception which was thrown; 2) Causes and their stacktracePucida
The difference is quite expected, since converting of the printStackTrace() never was a part of the question.Pansypant
R
3

Few options

  1. StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString();

  2. Using Google Guava lib String stackTrace = Throwables.getStackTraceAsString ( myException ) ;

  3. org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

Rampart answered 30/10, 2018 at 17:46 Comment(0)
A
3
 import java.io.PrintWriter;
import java.io.StringWriter;

public class PrintStackTrace {

    public static void main(String[] args) {

        try {
            int division = 0 / 0;
        } catch (ArithmeticException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            String exceptionAsString = sw.toString();
            System.out.println(exceptionAsString);
        }
    }
}

When you run the program, the output will be something similar:

java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Afford answered 17/11, 2018 at 10:45 Comment(0)
C
3

I wonder why no one mentioned ExceptionUtils.getStackFrames(exception)

For me it's the most convenient way to dump stacktrace with all its causes to the end:

String.join("\n", ExceptionUtils.getStackFrames(exception));
Crater answered 13/4, 2020 at 12:19 Comment(2)
and what is ExceptionUtils?Inflationism
It's a commons lang util classCrater
C
2

Warning: This may be a bit off topic, but oh well... ;)

I don't know what the original posters reason was for wanting the stack trace as string in the first place. When the stack trace should end up in an SLF4J/Logback LOG, but no exception was or should be thrown here's what I do:

public void remove(List<String> ids) {
    if(ids == null || ids.isEmpty()) {
        LOG.warn(
            "An empty list (or null) was passed to {}.remove(List). " +
            "Clearly, this call is unneccessary, the caller should " + 
            "avoid making it. A stacktrace follows.", 
            getClass().getName(),
            new Throwable ("Stacktrace")
        );

        return;
    }

    // actual work, remove stuff
}

I like it because it does not require an external library (other than your logging backend, which will be in place most of the time anyway, of course).

Clevis answered 6/12, 2017 at 19:39 Comment(0)
R
2

I wrote a few methods for this a while ago, so I figured why not throw my two cents at this.

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceElementsToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceElementsToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += padding + (!stackTrace.toString().startsWith("Caused By") ? "\tat " : "") + stackTrace.toString() + lineSeparator;
        }
    }
    return str;
}

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += (!stackTrace.toString().startsWith("Caused By") ? "" : padding + stackTrace.toString() + lineSeparator);
        }
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e) {
    return throwableToStrNoStackTraces(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator) {
    return throwableToStrNoStackTraces(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceCausedByElementsOnlyToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + throwableToStrNoStackTraces(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStrNoStackTraces(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStr(Throwable e) {
    return throwableToStr(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator) {
    return throwableToStr(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = padding + e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceElementsToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + "Suppressed: " + throwableToStr(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStr(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

Example:

try(InputStream in = new FileInputStream(file)) {
    ...
} catch(IOException e) {
    String exceptionToString = throwableToStr(e);
    someLoggingUtility.println(exceptionToString);
    ...
}

Prints:

java.io.FileNotFoundException: C:\test.txt (The system cannot find the file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(Unknown Source)
    at java.io.FileInputStream.<init>(Unknown Source)
    at com.gmail.br45entei.Example.main(Example.java:32)
Riant answered 13/1, 2019 at 4:38 Comment(0)
L
1

Old question, but I would just like to add the special case where you don't want to print all the stack, by removing some parts you are not actually interested in, excluding certain classes or packages.

Instead of a PrintWriter use a SelectivePrintWriter:

// This filters out this package and up.
String packageNameToFilter = "org.springframework";

StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); 
System.out.println(sStackTrace);

Where the SelectivePrintWriter class is given by:

public class SelectivePrintWriter extends PrintWriter {
    private boolean on = true;
    private static final String AT = "\tat";
    private String internal;

    public SelectivePrintWriter(Writer out, String packageOrClassName) {
        super(out);
        internal = "\tat " + packageOrClassName;
    }

    public void println(Object obj) {
        if (obj instanceof String) {
            String txt = (String) obj;
            if (!txt.startsWith(AT)) on = true;
            else if (txt.startsWith(internal)) on = false;
            if (on) super.println(txt);
        } else {
            super.println(obj);
        }
    }
}

Please note this class may be easily adapted to filter out by Regex, contains or other criteria. Also note it depends upon Throwable implementation details (not likely to change, but still).

Lanneret answered 16/10, 2017 at 21:59 Comment(0)
O
0

Shortcut Kotlin to write a stacktrace into an existing StringBuilder:

This version is very fast as it avoids creating a temporary string and copying it around

private fun StringBuilder.appendStackTrace(thr: Throwable) =
    thr.printStackTrace(object : PrintWriter(StringWriter()) {
        override fun println(x: Any?) {
            [email protected](x)
            [email protected]('\n')
        }
    })

You can call it like:

val s = buildString {
    append("Some text before the stack trace ...\n")
    appendStackTrace(throwable)
    append("Some other stuff")
}
Outcast answered 22/4, 2023 at 11:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.