Java / Android - Làm thế nào để in ra một dấu vết ngăn xếp đầy đủ?


124

Trong Android (Java), làm cách nào để in ra một dấu vết ngăn xếp đầy đủ? Nếu ứng dụng của tôi gặp sự cố từ nullPulumException hoặc một cái gì đó, nó sẽ in ra một dấu vết ngăn xếp đầy đủ (gần như) như vậy:

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

Tuy nhiên, đôi khi, với mục đích gỡ lỗi, tôi muốn đăng nhập một dấu vết ngăn xếp đầy đủ từ nơi tôi đang ở trong mã. Tôi hình dung tôi có thể làm điều này:

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

Nhưng điều này chỉ in ra con trỏ đến đối tượng ... Tôi có phải lặp qua tất cả các thành phần theo dõi ngăn xếp để in chúng ra không? Hoặc có một phương pháp đơn giản để in tất cả ra?


1
Bạn có thể sử dụng phương thức này Thread.cienThread (). GetStackTrace () stackoverflow.com/questions/1069066/
trộm

Câu trả lời:


119

Có ghi đè của tất cả các phương thức đăng nhập với (String tag, String msg, Throwable tr)chữ ký.

Truyền một ngoại lệ là tham số thứ ba sẽ cung cấp cho bạn toàn bộ stacktrace trong logcat.


5
FYI các phương thức nhật ký ba đối số sử dụng getStackTraceString()phương thức được đề cập bởi @Thomas đằng sau hậu trường.
Philipp Reichart

6
Tôi đã phát triển Android được hai năm và chưa bao giờ nhận thấy điều này trước đây. Cảm ơn rât nhiều.
Anh Tuấn

Nhìn vào mã nguồn, yup bạn đúng @PhilippReichart. Đây là mã cho Log.d trên AOSP 4.2.2_r1
Ehtesh Choudhury

152

Sau đây nên làm thủ thuật:

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

Lưu ý rằng ...x moreở cuối không cắt bỏ bất kỳ thông tin nào từ dấu vết ngăn xếp:

(Điều này cho biết) phần còn lại của dấu vết ngăn xếp cho ngoại lệ này khớp với số khung được chỉ định từ dưới cùng của dấu vết ngăn xếp của ngoại lệ do ngoại lệ này gây ra (ngoại lệ "kèm theo").

... Hoặc nói cách khác, thay thế x morebằng các xdòng cuối cùng từ ngoại lệ đầu tiên.


1
Từ đâu getStackTraceString()đến Không hiển thị trong Eclipse? Nó không phải là một phần của Throwablehoặc Exception....
Jake Wilson

9
"... 6 nữa" cuối cùng không cắt bỏ bất kỳ thông tin nào. Nó đang nói với bạn, rằng phần còn lại của dấu vết ngăn xếp giống như ngoại lệ hàng đầu. Chỉ cần nhìn vào 6 dòng cuối cùng từ ngoại lệ đầu tiên.
Tomasz

Bạn có thể cần phải nhập thư viện đăng nhập (sử dụng import android.util.Log;).
Dân

10

Sử dụng Log.getStackTraceString (Có thể ném t). Bạn có thể nhận được dấu vết ngăn xếp dài hơn bằng cách đào sâu hơn. Ví dụ:

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

Được truy xuất từ http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29


Log.getStackTraceString()không ghi nhật ký theo dõi ngăn xếp, nó chỉ trả về dưới dạng Chuỗi. Đoạn mã trên sẽ không đăng bất cứ điều gì và cũng sẽ thất bại với một NPE nếu e.getCause()null.
Philipp Reichart

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

Bạn có thể sử dụng điều này:

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

4

Bạn cũng có thể in theo dõi ngăn xếp tại bất kỳ điểm nào trong mã ứng dụng của mình bằng các phương thức như Thread.dumpStack()

Vui lòng đi qua liên kết để biết thêm chi tiết


2

Bạn cần sử dụng throwable Object để có được stackTrace đầy đủ.

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

Tham chiếu: https://stackoverflow.com/a/18546861


0

Bây giờ tôi đã nhanh chóng thực hiện một hàm đệ quy sẽ lặp lại hàm throwable và throwable.getCause ().

Đó là bởi vì mọi "throwable.getCause ()" đều trả về cho bạn một thông báo ngoại lệ mới với một số dòng được lặp lại và dòng mới. Vì vậy, khái niệm này là: nếu có "nguyên nhân" thì có một dòng có "n more .." trên chính có thể ném được để tôi có được dòng cuối cùng trước "n more .." thì tôi nhận được thông báo nguyên nhân và cuối cùng tôi chuỗi con thông báo nguyên nhân chỉ nhận được phần sau dòng lặp lại cuối cùng (dòng cuối cùng xuất hiện trên cả hai: có thể ném chính và ném được nguyên nhân).

Sau đó, tôi sử dụng đệ quy khi tôi nhận được thông báo nguyên nhân, vì vậy gọi lại cùng chức năng để nhận thông báo nguyên nhân từ chính có thể ném tôi sẽ nhận được một tin nhắn đã được thay thế. Nếu nguyên nhân có thể ném được từ khả năng ném chính cũng có một nguyên nhân khác, thì nguyên nhân có thể ném chính có 3 cấp độ (chính -> nguyên nhân -> nguyên nhân), trên loại ném chính tôi sẽ nhận được "thông báo nguyên nhân" một thông điệp đã được thay thế (sử dụng cùng một khái niệm chính

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

Tôi đã thử nó chỉ với 2 cấp độ (chính -> nguyên nhân) chứ không phải với nhiều cấp độ khác: / Nếu có gì sai xin vui lòng chỉnh sửa chức năng và viết nhận xét: D

có một mã hóa tốt và một ngày tốt đẹp quá: D

Quan trọng:

Mã này đôi khi có một ngoại lệ nếu "st" không chứa "\ n" hoặc tương tự (tôi đã tìm thấy một số loại ngoại lệ stacktraces có vấn đề này). Để giải quyết vấn đề này, bạn cần thêm một số kiểm tra trước hàng mã: "Chuỗi r1 = ..."

Bạn cần kiểm tra: "st" chứa "\ n" và các chỉ mục bắt đầu và kết thúc của "st.subSequence" đều hợp lệ.

Dù sao, tôi đề nghị đặt cái này vào trong một lần thử và trả về một chuỗi rỗng trong trường hợp ngoại lệ. (Nó được đệ quy để chuỗi rỗng được trả về sẽ được nối với chuỗi đã xử lý trước đó).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.