Jake Wilson
Jake Wilson

Reputation: 91233

Java / Android - How to print out a full stack trace?

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?

Upvotes: 149

Views: 117835

Answers (9)

MDT
MDT

Reputation: 1695

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

Upvotes: 1

I_4m_Z3r0
I_4m_Z3r0

Reputation: 1090

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

Upvotes: 0

Michael Berry
Michael Berry

Reputation: 72379

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.

Upvotes: 194

ajaykoppisetty
ajaykoppisetty

Reputation: 370

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

Upvotes: 7

Houssin Boulla
Houssin Boulla

Reputation: 2869

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

Upvotes: 2

faywong
faywong

Reputation: 141

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

Upvotes: 10

Thomas
Thomas

Reputation: 1508

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

Upvotes: 11

Mohsen Afshin
Mohsen Afshin

Reputation: 13436

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

Upvotes: 6

Philipp Reichart
Philipp Reichart

Reputation: 20961

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.

Upvotes: 133

Related Questions