Wie drucke ich in Ausnahmefällen die vollständige Stapelverfolgung?

97

Zum Beispiel an einem Ort ...

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

... und an einem anderen Ort ...

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

Der Stacktrace, den ich drucke, beginnt nur von a nach b, enthält nicht den inneren Stacktrace aus der WebException.

Wie kann ich den gesamten Stacktrace drucken?

Jojo
quelle
1
Beachten Sie, dass der Stacktrace für die ursprüngliche WebException nicht gedruckt wird, da Sie eine neue Ausnahme ausgelöst haben, anstatt die WebException erneut auszulösen. Verwenden Sie throw;anstelle von , throw new MyCustomException(...)wenn Sie wollen , zu erhalten (und Ausgang) , um die ursprüngliche Ausnahme - Stack.
Beel

Antworten:

173

Normalerweise verwende ich die .ToString () -Methode für Ausnahmen, um die vollständigen Ausnahmeinformationen (einschließlich der inneren Stapelverfolgung) im Text darzustellen:

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

Beispielausgabe:

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
Justin
quelle
Sehr gut. Ich suchte nach einem einfachen Weg, und hier ist es. Einige kleine Bedenken sind, dass es nicht so explizit ist, als ob Sie das Objekt exception.StackTrace verwenden (zum Beispiel). Ich frage mich, ob es einen expliziteren Weg gibt, dasselbe zu tun.
Codea
4
Beachten Sie, dass einige Bibliotheken setzen die Zuweisung ToStringMethode und benutzerdefinierte Nachrichten anstelle der vollständigen Informationen drucken (dies eine schlechte Codierung der Praxis ist, so kann nicht das tun, überhaupt)
Dinei
@P ரதீப் Ich verwende es, ToStringwenn ich sicher bin, dass es nicht überschrieben wird, und verwende die Eigenschaften direkt anderweitig (wie die Antwort von Andrew Hare ).
Dinei
53

Verwenden Sie eine Funktion wie diese:

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

Dann können Sie es so nennen:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}
Andrew Hare
quelle
13
Oder können Sie verwenden ToString?
Justin
Ich benutze den ToString und denke, dass es in Ordnung ist. Ich würde mich für Andrews Lösung entscheiden, wenn ich nur die niedrigste innere Ausnahme (mit dem tatsächlichen Grund) oder eine ähnliche Auswahl möchte. Funktioniert jedoch beides :)
EeKay
Dies ist flexibler als nur ToString, da Sie auswählen können, was in diese Zeichenfolge eingefügt werden soll. Vielleicht interessieren mich nur die Stapelspuren, nicht unbedingt die Nachrichten. Oder ich möchte, dass es als List <string> keine einzelne Zeichenfolge ist.
Zar Shardan
18

1. Methode erstellen: Wenn Sie Ihre Ausnahme an die folgende Funktion übergeben, erhalten Sie alle Methoden und Details, die Gründe für die Ausnahme sind.

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. Aufrufmethode: Sie können die Methode folgendermaßen aufrufen.

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

3. Holen Sie sich das Ergebnis:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 
Oguzhan KIRCALI
quelle
1
Sehr hilfreich. Ich habe eine Erweiterungsmethode basierend auf Ihrem Beispiel erstellt. Übrigens, bei einer großen Anzahl von Iterationen sollten Sie die StringBuilderKlasse verwenden.
AlexMelw
2
Andreys Link war tot. Dies ist der aktuelle Link zu seiner Implementierung: github.com/AndreyWD/EasySharp/blob/master/NHelpers/…
Christian Junk
Das sieht professionell aus Andrey. Ich habe Ihre Bibliothek in meine Toolbox gestellt. Vielen Dank. @ AndrewWD
Oguzhan KIRCALI