【问题标题】:Java / Android - How to print out a full stack trace?Java / Android - 如何打印出完整的堆栈跟踪?
【发布时间】:2011-12-12 01:51:31
【问题描述】:

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

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

【问题讨论】:

标签: java android exception stack stack-trace


【解决方案1】:

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

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

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

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

祝你编码愉快,度过愉快的一天:D

重要:

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

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

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

【讨论】:

    【解决方案2】:

    以下应该可以解决问题:

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

    注意...x more在结尾does not cut off any information from the stack trace:

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

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

    【讨论】:

    • getStackTraceString() 来自哪里?没有出现在 Eclipse 中?它不属于ThrowableException....
    • "...6 more" 最后没有切断任何信息。它告诉您,堆栈跟踪的其余部分与顶部异常的相同。只需查看第一个异常的最后 6 行。
    • 您可能需要导入日志库(使用import android.util.Log;)。
    【解决方案3】:

    您还可以使用 Thread.dumpStack() 等方法在应用代码中的任何位置打印堆栈跟踪

    请通过more details的链接

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:
        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】:

          使用 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() 不记录堆栈跟踪,它只是将其作为字符串返回。如果e.getCause()null,上面的代码不会记录任何内容并且也会失败并出现NPE。
          【解决方案7】:

          你可以使用这个:

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

          【讨论】:

            【解决方案8】:

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

            将异常作为 third 参数传递应该会在 logcat 中为您提供完整的堆栈跟踪。

            【讨论】:

            • 仅供参考,三参数日志方法使用@Thomas 在幕后提到的getStackTraceString() 方法。
            • 我已经开发 Android 两年了,之前从未注意到这一点。非常感谢。
            • 查看源代码,是的,你是对的@PhilippReichart。这是 AOSP 4.2.2_r1 上Log.d 的代码
            • Log.e 和 Log.d 不工作 :(
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-01
            • 2011-05-15
            • 1970-01-01
            • 2013-09-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多