Java / Android - Tam yığın izi nasıl yazdırılır?


125

Android'de (Java) tam yığın izlemesini nasıl yazdırırım? Uygulamam nullPointerException veya başka bir şeyden çökerse, şöyle bir (neredeyse) tam yığın izi yazdırır:

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

Ancak bazen, hata ayıklama amacıyla, kodda bulunduğum yerden tam bir yığın izlemesi kaydetmek istiyorum. Bunu yapabileceğimi düşündüm:

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

Ancak bu, yalnızca nesnenin işaretçisini yazdırır ... Bunları yazdırmak için tüm yığın izleme öğelerini yinelemem gerekir mi? Yoksa hepsini yazdırmanın basit bir yöntemi var mı?


1
Bu yöntemi Thread.currentThread () kullanabilirsiniz. GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270

Yanıtlar:


120

Herşeyden geçersiz kılma var günlük yöntemleriyle birlikte (String tag, String msg, Throwable tr)imzalar.

Üçüncü parametre olarak bir istisna iletmek size logcat'te tam yığın izini vermelidir.


5
Bilginize, üç bağımsız değişkenli günlük yöntemleri getStackTraceString()perde arkasında @Thomas tarafından belirtilen yöntemi kullanır .
Philipp Reichart

6
Android'i iki yıldır geliştirdim ve bunu daha önce hiç fark etmedim. Çok teşekkür ederim.
Anh Tuan

Kaynak koduna baktığınızda, evet haklısınız @PhilippReichart. İşte AOSP 4.2.2_r1'deki Log.d kodu
Ehtesh Choudhury

152

Aşağıdakiler hile yapmalı:

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

...x moreSonunda yığın izlemeden herhangi bir bilgiyi kesmediğini unutmayın :

(Bu, bu özel durum için yığın izlemenin geri kalanının, bu özel durumun neden olduğu istisnanın yığın izlemesinin altından belirtilen çerçeve sayısıyla eşleştiğini gösterir ("çevreleyen" istisna).

... veya başka bir deyişle, ilk istisnadan x moreson xsatırlarla değiştirin .


1
Nereden getStackTraceString()geliyor? Eclipse'de görünmüyor mu? Bir parçası değil Throwableya da Exception....
Jake Wilson

9
Sondaki "... 6 tane daha" herhangi bir bilgiyi kesmiyor. Size, yığın izlemenin geri kalanının en büyük istisna için olduğu gibi aynı olduğunu söylüyor. İlk istisnadan son 6 satıra bakın.
Tomasz

Muhtemelen günlük kitaplığını (kullanarak import android.util.Log;) içe aktarmanız gerekir .
Dan

10

Log.getStackTraceString (Throwable t) kullanın. Daha derine inerek daha uzun yığın izleri elde edebilirsiniz. Örneğin:

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 adresinden alındı


Log.getStackTraceString()yığın izlemesini günlüğe kaydetmez, yalnızca String olarak döndürür. Yukarıdaki kod şey log olmayacak ve eğer aynı zamanda bir NPE başarısız olur e.getCause()ise 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

Bunu kullanabilirsiniz:

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

Ayrıca, uygulama kodunuzun herhangi bir noktasında aşağıdaki gibi yöntemleri kullanarak yığın izi yazdırabilirsiniz. Thread.dumpStack()

Daha fazla ayrıntı için lütfen bağlantıya gidin


2

StackTrace'in tamamını almak için Throwable Object kullanmanız gerekir.

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

Referans: https://stackoverflow.com/a/18546861


0

Hızlı bir şekilde, atılabilir ve atılabilir.getCause () işlevlerini yineleyecek özyinelemeli bir işlev yaptım.

Çünkü her "throwable.getCause ()" size tekrarlanan bazı satırlar ve yeni satırlar içeren yeni bir istisna mesajı döndürür. Yani konsept şudur: eğer bir "neden" varsa, ana atılabilirde "n more .." ile bir satır vardır, böylece "n more .." ile olandan önceki son satırı alırım, o zaman neden mesajını alırım ve son olarak, neden mesajının yalnızca son yinelenen satırdan sonraki kısmı (her ikisinde de görünen son satır: ana atılabilir ve atılabilir neden) alt satırını yazıyorum.

Daha sonra neden mesajını aldığımda özyinelemeyi kullanırım, bu nedenle ana atılabilirden neden mesajını almak için aynı işlevi yeniden çağırmak, zaten değiştirilmiş bir mesaj alacağım. Ana fırlatılabilir nedenin başka bir nedeni varsa, ana fırlatılabilirin 3 seviyesi vardır (ana -> neden -> neden-neden), ana atılabilirde zaten değiştirilmiş bir mesaj "neden mesajı" alacağım (aynı ana kavramını kullanarak

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

Sadece 2 seviye ile denedim (ana -> neden) ve daha fazlasıyla değil: / Yanlış bir şey varsa lütfen işlevi düzenleyin ve bir yorum yazın: D

güzel bir kodlama ve size de iyi günler: D

Önemli:

Bu kod bazen "st" "\ n" veya benzerini içermiyorsa bir istisna alır (bazı istisnalar yığın izlerinde bu sorun olduğunu buldum). Bunu çözmek için, kod satırından önce bir kontrol eklemeniz gerekir: "String r1 = ..."

Kontrol etmeniz gereken: "st" "\ n" içeriyor ve "st.subSequence" ın başlangıç ​​ve bitiş dizinlerinin her ikisinin de geçerli olduğunu.

Her neyse, bunu bir try-catch içine koymanızı ve istisna durumunda boş bir dizge döndürmenizi öneririm. (Özyinelemeli olduğundan, döndürülen boş dizge önceki işlenmiş dizeyle birleştirilecektir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.