简体   繁体   English

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

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

In Android (Java) how do I print out a full stack trace?在 Android (Java) 中,如何打印出完整的堆栈跟踪? If my application crashes from nullPointerException or something, it prints out a (almost) full stack trace like so:如果我的应用程序因 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

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?或者有什么简单的方法可以打印出来吗?

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:请注意,最后的...x more 不会切断堆栈跟踪中的任何信息:

(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. ...或者换句话说,将x more替换为第一个异常的最后x行。

There's overrides of all the log methods with (String tag, String msg, Throwable tr) signatures.使用(String tag, String msg, Throwable tr)签名覆盖所有日志方法

Passing an exception as the third parameter should give you the full stacktrace in logcat.将异常作为第三个参数传递应该会在 logcat 中为您提供完整的堆栈跟踪。

Use Log.getStackTraceString(Throwable t).使用 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取自http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29

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

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

You can also print a stack trace at any point in your app code using methods such as Thread.dumpStack()您还可以使用Thread.dumpStack()等方法在应用程序代码中的任何位置打印堆栈跟踪

Please go through the link for more details请通过链接了解更多详情

You need use Throwable Object to get the full stackTrace.您需要使用 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();
}

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

I fast did now a recursive function which will iterate the throwable and throwable.getCause().我现在快速做了一个递归函数,它将迭代 throwable 和 throwable.getCause()。

That's because every "throwable.getCause()" return to you a new exception message with some lines repeated and new lines.这是因为每个“throwable.getCause()”都会向您返回一条新的异常消息,其中包含一些重复的行和新的行。 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).所以这个概念是:如果有一个“原因”,则在 main throwable 上有一行带有“n more..”的行,所以我在带有“n more..”的那一行之前得到最后一行,然后我得到原因消息和最后,我将原因消息子串化,仅获取最后重复行之后的部分(出现在两者上的最后一行:主要可抛出对象和可抛出原因)。

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.然后当我得到原因消息时我使用递归,所以重新调用相同的函数来从主要的 throwable 中获取原因消息,我会得到一个已经被替换的消息。 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如果从主 throwable 抛出的原因也有另一个原因,那么主 throwable 有 3 个级别(main -> cause -> cause-of-cause),在主 throwable 上,我将得到“原因消息”一个已经被替换的消息(使用相同的主要概念

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我只尝试了 2 级(主要 -> 原因)而不是更多:/ 如果有任何问题,请编辑函数并写评论:D

have a nice coding and a nice day too :D有一个很好的编码和美好的一天: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).如果“st”不包含“\n”或类似内容,此代码有时会出现异常(我发现某种异常堆栈跟踪有此问题)。 To solve this you need to add some check before code row: "String r1 = ..."要解决这个问题,您需要在代码行之前添加一些检查:“String r1 = ...”

You need to check: "st" contains "\n" and that the start & end indexes of "st.subSequence" are both valid.您需要检查:“st”包含“\n”并且“st.subSequence”的开始和结束索引都有效。

Anyway I suggest to put this inside an try-catch and return an empty string in case of exception.无论如何,我建议把它放在一个 try-catch 中,并在出现异常时返回一个空字符串。 (It is recursive so the returned empty string will be concatenated to the previous processed string). (它是递归的,因此返回的空字符串将连接到先前处理的字符串)。

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.对于 kotlin android 用户,我们不需要创建扩展函数来循环遍历整个堆栈消息,我们在 kotlin 的 throwable 类中内置了一些东西。

This is whats under the hood for kotlin v >1.4这是 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM