143

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?

Jake Wilson
  • 88,616
  • 93
  • 252
  • 370
  • 1
    You can use this method Thread.currentThread().getStackTrace() http://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java – user2024270 Dec 09 '14 at 11:00
  • 1
    Possible duplicate of [Android - print full exception backtrace to log](https://stackoverflow.com/questions/4341363/android-print-full-exception-backtrace-to-log) – TT-- Jul 15 '19 at 20:11

9 Answers9

185

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.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • 1
    Where is `getStackTraceString()` from? Doesn't show up in Eclipse? It's not part of `Throwable` or `Exception`.... – Jake Wilson Nov 04 '11 at 17:46
  • 9
    "...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. – Tomasz Mar 19 '14 at 14:20
  • 1
    You'd probably need to import the logging library (using `import android.util.Log;`). – Dan May 13 '16 at 10:31
127

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.

Philipp Reichart
  • 20,771
  • 6
  • 58
  • 65
  • 5
    FYI the three-argument log methods use the [`getStackTraceString()`](http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29) method mentioned by @Thomas behind the scenes. – Philipp Reichart Oct 20 '11 at 19:44
  • 6
    I've developed Android for two years and never noticed this before. Thank you very much. – Anh Tuan Nov 30 '11 at 04:32
  • Looking at the source code, yup you're right @PhilippReichart. Here's the code for [Log.d](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/util/Log.java#Log.d%28java.lang.String%2Cjava.lang.String%2Cjava.lang.Throwable%29) on AOSP 4.2.2_r1 – Ehtesh Choudhury Apr 25 '13 at 17:06
  • Log.e and Log.d not working :( – blinker Sep 23 '21 at 08:15
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

Thomas
  • 1,508
  • 2
  • 22
  • 35
  • `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`. – Philipp Reichart Dec 19 '13 at 13:47
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()));
Joe
  • 841
  • 2
  • 10
  • 25
faywong
  • 141
  • 1
  • 5
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

ajaykoppisetty
  • 364
  • 4
  • 10
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();
}
Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90
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

Houssin Boulla
  • 2,687
  • 1
  • 16
  • 22
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).

Community
  • 1
  • 1
Z3R0
  • 1,011
  • 10
  • 19
0

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
MDT
  • 1,535
  • 3
  • 16
  • 29