Java / Android - 如何打印出完整的堆栈跟踪?

时间:2011-10-20 19:34:03

标签: java android exception stack stack-trace

在Android(Java)中,如何打印出完整的堆栈跟踪?如果我的应用程序从nullPointerException或其他东西崩溃,它会打印出一个(几乎)完整的堆栈跟踪,如下所示:

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

但是,有时,出于调试目的,我想从代码中的位置记录完整的堆栈跟踪。我想我可以这样做:

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

但是这只是打印出指向对象的指针......我是否必须遍历所有堆栈跟踪元素才能将它们打印出来?或者有一种简单的方法可以将它全部打印出来吗?

8 个答案:

答案 0 :(得分:138)

以下应该可以解决问题:

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

请注意...x more

的最后x more
  

(这表明)此异常的堆栈跟踪的剩余部分与此异常引起的异常堆栈跟踪底部的指示帧数相匹配(“封闭” “例外)。

...或换句话说,将x替换为第一个例外中的最后{{1}}行。

答案 1 :(得分:109)

所有带有(String tag, String msg, Throwable tr)签名的log methods都有覆盖。

作为第三个参数传递给你应该在logcat中提供完整的堆栈跟踪。

答案 2 :(得分:9)

使用Log.getStackTraceString(Throwable t)。通过深入挖掘可以获得更长的堆栈跟踪。例如:

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

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

答案 3 :(得分:9)

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

答案 4 :(得分:6)

你可以用这个:

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

答案 5 :(得分:2)

您还可以使用Thread.dumpStack()

等方法在应用代码中的任意位置打印堆栈跟踪

请浏览more details

的链接

答案 6 :(得分:0)

您需要使用Throwable Object来获取完整的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();
}

参考:https://stackoverflow.com/a/18546861

答案 7 :(得分:0)

我现在快速执行了一个递归函数,该函数将迭代throwable和throwable.getCause()。

那是因为每个“ throwable.getCause()”都会向您返回一条新的异常消息,其中包含重复的行和换行。 所以这个概念是:如果在主throwable上有一个“ cause”行,所以我得到了“ n more ..”行之前的最后一行,然后得到了原因消息,最终,我将原因消息细分为仅得到最后重复的行(最后出现在这两个行之后的部分:主要的throwable和cause throwable)之后的原因消息。

然后,当我收到原因消息时,我使用递归,因此重新调用同一函数从主throwable中获取原因消息,我将得到一个已经替换的消息。如果从主要可抛出对象引发的原因也有另一个原因,那么主要可引发对象具有3个级别(主要->原因->原因),在主要可引发对象上,我将获得具有“原因消息”的已替换消息(使用与主广告相同的概念

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 "";
}

我只用2级(主要->原因)尝试过它,而不用更多的:/ 如果有任何错误,请编辑函数并写评论:D

也有不错的编码和美好的一天:D

重要提示:

如果“ st”不包含“ \ n”或类似字符,则此代码有时会出现异常(我发现某些堆栈跟踪异常存在此问题)。 为了解决这个问题,您需要在代码行之前添加一些检查:“ String r1 = ...”

您需要检查:“ st”包含“ \ n”,并且“ st.subSequence”的开始索引和结束索引均有效。

无论如何,我建议将其放入try-catch并在出现异常的情况下返回空字符串。 (它是递归的,因此返回的空字符串将连接到先前处理的字符串)。