151

In Android (Java) how do I print out a full stack trace? If my application crashes from nullPointerException or something, it prints out a (almost) full stack trace like so:

java.io.IOException: Attempted read from closed stream.
com.android.music.sync.common.SoftSyncException: java.io.IOException: Attempted read from closed stream.
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:545)
    at com.android.music.sync.google.MusicSyncAdapter.fetchDataFromServer(MusicSyncAdapter.java:488)
    at com.android.music.sync.common.AbstractSyncAdapter.download(AbstractSyncAdapter.java:417)
    at com.android.music.sync.common.AbstractSyncAdapter.innerPerformSync(AbstractSyncAdapter.java:313)
    at com.android.music.sync.common.AbstractSyncAdapter.onPerformLoggedSync(AbstractSyncAdapter.java:243)
    at com.google.android.common.LoggingThreadedSyncAdapter.onPerformSync(LoggingThreadedSyncAdapter.java:33)
    at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:164)
Caused by: java.io.IOException: Attempted read from closed stream.
    at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:148)
    at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:159)
    at java.util.zip.GZIPInputStream.readFully(GZIPInputStream.java:212)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:64)
    at android.net.http.AndroidHttpClient.getUngzippedContent(AndroidHttpClient.java:218)
    at com.android.music.sync.api.MusicApiClientImpl.createAndExecuteMethod(MusicApiClientImpl.java:312)
    at com.android.music.sync.api.MusicApiClientImpl.getItems(MusicApiClientImpl.java:588)
    at com.android.music.sync.api.MusicApiClientImpl.getTracks(MusicApiClientImpl.java:638)
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:512)
    ... 6 more

However sometimes, for debugging purposes, I want to log a full stack trace from where I am in the code. I figured I could just do this:

StackTraceElement trace = new Exception().getStackTrace();
Log.d("myapp", trace.toString());

But this just prints out the pointer to the object... Do I have to iterate through all the stack trace elements to print them out? Or is there a simple method to print it all out?

2

9 Answers 9

197

The following should do the trick:

Log.d("myapp", Log.getStackTraceString(new Exception()));

Note that ...x more at the end does not cut off any information from the stack trace:

(This indicates) that the remainder of the stack trace for this exception matches the indicated number of frames from the bottom of the stack trace of the exception that was caused by this exception (the "enclosing" exception).

...or in other words, replace x more with the last x lines from the first exception.

Sign up to request clarification or add additional context in comments.

6 Comments

Where is getStackTraceString() from? Doesn't show up in Eclipse? It's not part of Throwable or Exception....
"...6 more" at the end is not cutting off any information. It is telling you, that the rest of the stack trace is the the same as it was for the top exception. Just look at the last 6 lines from the first exception.
You'd probably need to import the logging library (using import android.util.Log;).
StackTraceElement trace = new Exception().getStackTrace(); Log.d("myapp", trace.toString()); This won’t work because: getStackTrace() returns an array of StackTraceElement[], not a single element. Calling toString() on the array just prints a reference (like [Ljava.lang.StackTraceElement;@someHash).
Correct Solution is: You can either use printStackTrace() or iterate the elements properly. Example 1: Easiest way using printStackTrace() try { // Force an exception for testing throw new Exception("Testing stack trace"); } catch (Exception e) { // Prints the full stack trace in Logcat e.printStackTrace(); }
|
133

There's overrides of all the log methods with (String tag, String msg, Throwable tr) signatures.

Passing an exception as the third parameter should give you the full stacktrace in logcat.

5 Comments

FYI the three-argument log methods use the getStackTraceString() method mentioned by @Thomas behind the scenes.
I've developed Android for two years and never noticed this before. Thank you very much.
Looking at the source code, yup you're right @PhilippReichart. Here's the code for Log.d on AOSP 4.2.2_r1
Log.e and Log.d not working :(
@blinker They do.
11

Use Log.getStackTraceString(Throwable t). You can get longer stack traces by digging deeper. For example:

try {
    ...
} catch(Exception e) {
    Log.d("Some tag", Log.getStackTraceString(e.getCause().getCause()));
}

Retreived from http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29

1 Comment

Log.getStackTraceString() does not log the stack trace it just returns it as String. The above code won't log anything and will also fail with a NPE if e.getCause() is null.
10
private static String buildStackTraceString(final StackTraceElement[] elements) {
    StringBuilder sb = new StringBuilder();
    if (elements != null && elements.length > 0) {
        for (StackTraceElement element : elements) {
            sb.append(element.toString());
        }
    }
    return sb.toString();
}


// call this at your check point
Log.d(TAG, buildStackTraceString(Thread.currentThread().getStackTrace()));

Comments

7

You can also print a stack trace at any point in your app code using methods such as Thread.dumpStack()

Please go through the link for more details

Comments

6

You may use this:

public static String toString(StackTraceElement[] stackTraceElements) {
    if (stackTraceElements == null)
        return "";
    StringBuilder stringBuilder = new StringBuilder();
    for (StackTraceElement element : stackTraceElements)
        stringBuilder.append(element.toString()).append("\n");
    return stringBuilder.toString();
}

Comments

2

You need use Throwable Object to get the full stackTrace.

try{
 // code here
}catch(Exception e){
    String exception = getStackTrace(e);
}

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();
}

Ref: https://stackoverflow.com/a/18546861

Comments

1

For kotlin android users, we dont need to create extension functions for looping through the entire stack message we have something built in to the throwable class by kotlin.

This is whats under the hood for kotlin v >1.4

@SinceKotlin("1.4")
public actual fun Throwable.stackTraceToString(): String {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    printStackTrace(pw)
    pw.flush()
    return sw.toString()
} 

Usage :

 Log.d("ERROR_STACKTRACE","${t.stackTraceToString()}") // 't' is the throwable obj

Comments

0

I fast did now a recursive function which will iterate the throwable and throwable.getCause().

That's because every "throwable.getCause()" return to you a new exception message with some lines repeated and new lines. So the the concept is: if there is a "cause" there is a line with "n more.." on main throwable so I get the last line before the one with "n more.." then I get the cause message and finally i substring the cause message getting only the part after the last repeated line (the last line which appear on both: the main throwable and the cause throwable).

Then I use recursion when I get the cause message, so re-calling the same function to get the cause message from the main throwable I will get an already replaced message. If the cause throwable from the main throwable has also another cause, so the main throwable has 3 levels (main -> cause -> cause-of-cause), on the main throwable I will get has "cause message" an already replaced message (using same concept of the main

public static <T extends Throwable> String printStackTraceString(T ex) {     // Recursive
    Throwable tr = ex;
    if (tr != null) {
        String st = Log.getStackTraceString(tr);
        if (tr.getCause() != null) {
            // Recursion...
            String cs = printStackTraceString(tr.getCause());

            String r1 = st.subSequence(0x0, st.lastIndexOf("\n", st.lastIndexOf("\n") - "\n".length())).toString();
            String replace = r1.substring(r1.lastIndexOf("\n"));
            if (cs.contains(replace)) {
                return r1.concat(cs.subSequence(cs.indexOf(replace) + replace.length(), cs.length()).toString());
            }
        }
        return st;
    }
    return "";
}

I tried it only with 2 level (main -> cause) and not with more :/ If there is anything wrong please edit the function and write a comment :D

have a nice coding and a nice day too :D

Important:

This code sometimes get an exception if the "st" doesn't contains "\n" or similar (I found some kind of exceptions stacktraces have this problem). To solve this you need to add some check before code row: "String r1 = ..."

You need to check: "st" contains "\n" and that the start & end indexes of "st.subSequence" are both valid.

Anyway I suggest to put this inside an try-catch and return an empty string in case of exception. (It is recursive so the returned empty string will be concatenated to the previous processed string).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.