Reputation: 91233
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
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
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
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
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
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
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
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
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
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
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