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


124

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

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


1
您可以使用此方法Thread.currentThread()的getStackTrace()。stackoverflow.com/questions/1069066/...
user2024270

Answers:


119

有所有带有签名的日志方法的替代(String tag, String msg, Throwable tr)

将异常作为第三个参数传递给您应该在logcat中具有完整的stacktrace。


5
仅供参考,三参数日志方法使用getStackTraceString()幕后@Thomas提到的方法。
菲利普·里查特

6
我已经开发Android两年了,以前从未注意到这一点。非常感谢你。
Anh Tuan

查看源代码,是的,@ PhilippReichart是正确的。下面是代码Log.d上AOSP 4.2.2_r1
Ehtesh乔杜里

152

以下应该可以解决问题:

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

请注意,...x more最后不会从堆栈跟踪中删除任何信息:

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

...或者换句话说,用第一个异常x more的最后x几行替换。


1
getStackTraceString()来自哪里?不会在Eclipse中显示吗?它不属于ThrowableException....
Jake Wilson

9
最后的“ ... 6更多”并没有切断任何信息。它告诉您,堆栈跟踪的其余部分与最常见的异常相同。只需查看第一个异常的最后6行。
Tomasz 2014年

您可能需要导入日志记录库(使用import android.util.Log;)。

10

使用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中检索


Log.getStackTraceString()不记录堆栈跟踪,而只是将其返回为String。上面的代码将不会记录任何内容,如果e.getCause()为NPE也会失败null
菲利普·里查特

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

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


2

您需要使用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


0

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

这是因为每个“ throwable.getCause()”都会向您返回一条新的异常消息,其中包含重复的行和换行。所以这个概念是:如果在主throwable上有一个“ cause”行,所以有一行“ n more ..”,所以我得到了“ n more ..”之前的最后一行,然后得到了原因消息,最后,我将原因消息细分为仅得到最后重复的行之后的部分(出现在最后一行的最后一行):main 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并在出现异常的情况下返回空字符串。(它是递归的,因此返回的空字符串将被连接到先前处理的字符串)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.