Come stampare la traccia dello stack completo in eccezione?


97

Ad esempio, in un posto ...

//---------------a
try
{
    // some network call
}
catch(WebException we)
{
    throw new MyCustomException("some message ....", we);
}

... e in un altro luogo ...

//--------------b
try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(we.stacktrace);   // <----------------
}

Lo stacktrace che stampo, inizia solo da a a b, non include lo stacktrace interno da WebException.

Come posso stampare tutto lo stacktrace ???


1
Si noti che lo stacktrace per la WebException di origine non verrebbe stampato perché è stata generata una nuova eccezione anziché rilanciare la WebException. Utilizzare throw;al posto di throw new MyCustomException(...)se si desidera preservare (e produrre) lo stack di eccezioni originale.
Beel

Risposte:


174

Di solito uso il metodo .ToString () sulle eccezioni per presentare le informazioni complete sull'eccezione (inclusa la traccia dello stack interno) nel testo:

catch (MyCustomException ex)
{
    Debug.WriteLine(ex.ToString());
}

Output di esempio:

ConsoleApplication1.MyCustomException: some message .... ---> System.Exception: Oh noes!
   at ConsoleApplication1.SomeObject.OtherMethod() in C:\ConsoleApplication1\SomeObject.cs:line 24
   at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 14
   --- End of inner exception stack trace ---
   at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 18
   at ConsoleApplication1.Program.DoSomething() in C:\ConsoleApplication1\Program.cs:line 23
   at ConsoleApplication1.Program.Main(String[] args) in C:\ConsoleApplication1\Program.cs:line 13

Molto bene. Stavo cercando un modo semplice per farlo ed eccolo qui. Qualche piccola preoccupazione è che non è tanto esplicito come se si usasse un oggetto exception.StackTrace (per esempio). Mi chiedo se esiste un modo più esplicito per fare lo stesso?
codea

4
Tieni presente che alcune biblioteche sovrascrivono il ToStringmetodo e stampano messaggi personalizzati invece delle informazioni complete (questa è una cattiva pratica di codifica, quindi non farlo mai)
Dinei

@P ரதீப் Lo uso ToStringogni volta che sono sicuro che non viene sovrascritto e altrimenti uso le proprietà direttamente (come la risposta di Andrew Hare ).
Dinei

53

Usa una funzione come questa:

    public static string FlattenException(Exception exception)
    {
        var stringBuilder = new StringBuilder();

        while (exception != null)
        {
            stringBuilder.AppendLine(exception.Message);
            stringBuilder.AppendLine(exception.StackTrace);

            exception = exception.InnerException;
        }

        return stringBuilder.ToString();
    }

Quindi puoi chiamarlo in questo modo:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}

13
Oppure puoi usare ToString?
Justin

Sto usando ToString e penso che vada bene. Andrei con la soluzione di Andrew se voglio solo l'eccezione interna più bassa (con il motivo effettivo) o una scelta simile .. funziona entrambi però :)
EeKay

Questo è più flessibile di ToString, perché puoi scegliere cosa inserire in quella stringa. Forse mi interessano solo le tracce dello stack, non necessariamente i messaggi. Oppure lo voglio come List <string> non una singola stringa.
Zar Shardan

18

1. Crea metodo: se passi la tua eccezione alla seguente funzione, ti verranno forniti tutti i metodi e i dettagli che sono i motivi dell'eccezione.

public string GetAllFootprints(Exception x)
{
        var st = new StackTrace(x, true);
        var frames = st.GetFrames();
        var traceString = new StringBuilder();

        foreach (var frame in frames)
        {
            if (frame.GetFileLineNumber() < 1)
                continue;

            traceString.Append("File: " + frame.GetFileName());
            traceString.Append(", Method:" + frame.GetMethod().Name);
            traceString.Append(", LineNumber: " + frame.GetFileLineNumber());
            traceString.Append("  -->  ");
        }

        return traceString.ToString();
}

2. Metodo di chiamata: è possibile chiamare il metodo in questo modo.

try
{
    // code part which you want to catch exception on it
}
catch(Exception ex)
{
    Debug.Writeline(GetAllFootprints(ex));
}

3. Ottieni il risultato:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 

1
Abbastanza utile. Ho creato un metodo di estensione basato sul tuo esempio. A proposito, in caso di un gran numero di iterazioni è meglio usare StringBuilderclass.
AlexMelw

2
Il collegamento di Andreys era morto. Questo è il collegamento corrente alla sua implementazione: github.com/AndreyWD/EasySharp/blob/master/NHelpers/…
Christian Junk

Sembra professionale, Andrey. Ho messo la tua libreria nella mia cassetta degli attrezzi. Grazie. @AndreyWD
Oguzhan KIRCALI
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.