Jak wydrukować pełny ślad stosu w wyjątku?

98

Na przykład w jednym miejscu ...

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

... iw innym miejscu ...

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

Drukuję ślad stosu, zaczyna się tylko od a do b, nie zawiera wewnętrznego śladu stosu z WebException.

Jak mogę wydrukować cały ślad stosu ???

jojo
źródło
1
Zwróć uwagę, że ślad stosu dla początkowego WebException nie zostałby wydrukowany, ponieważ zgłosiłeś nowy wyjątek, zamiast ponownie zgłosić WebException. Użyj throw;zamiast, throw new MyCustomException(...)jeśli chcesz zachować (i wyprowadzić) oryginalny stos wyjątków.
Beel

Odpowiedzi:

174

Zwykle używam metody .ToString () na wyjątkach, aby przedstawić pełne informacje o wyjątku (w tym wewnętrzny ślad stosu) w tekście:

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

Przykładowe dane wyjściowe:

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
źródło
Bardzo dobrze. Szukałem prostego sposobu na zrobienie tego i oto on. Niepokojące jest to, że nie jest to tak wyraźne, jak w przypadku użycia obiektuception.StackTrace (na przykład). Zastanawiam się, czy istnieje bardziej wyraźny sposób na zrobienie tego samego?
codea
4
Należy pamiętać, że niektóre biblioteki zastępują tę ToStringmetodę i drukują niestandardowe komunikaty zamiast pełnych informacji (jest to zła praktyka kodowania, więc nigdy tego nie rób)
Dinei
@P ரதீப் Używam, ToStringgdy jestem pewien, że nie jest nadpisane, i używam właściwości bezpośrednio w inny sposób (jak odpowiedź Andrew Hare ).
Dinei
53

Użyj takiej funkcji:

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

Następnie możesz to nazwać tak:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}
Andrew Hare
źródło
13
Lub możesz użyć ToString?
Justin
Używam ToString i myślę, że jest w porządku. Poszedłbym z rozwiązaniem Andrew, jeśli chcę tylko najniższego wewnętrznego wyjątku (z rzeczywistym powodem) lub podobnego wybierania .. działa w obu przypadkach :)
EeKay
Jest to bardziej elastyczne niż tylko ToString, ponieważ możesz wybrać, co ma znaleźć się w tym ciągu. Może interesują mnie tylko ślady stosu, niekoniecznie wiadomości. Lub chcę, aby było to List <string>, a nie pojedynczy ciąg.
Zar Shardan
18

1. Utwórz metodę: jeśli przekażesz wyjątek do następującej funkcji, poda ona wszystkie metody i szczegóły, które są przyczyną wyjątku.

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. Metoda wywołania: Możesz wywołać metodę w ten sposób.

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

3. Uzyskaj wynik:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 
Oguzhan KIRCALI
źródło
1
Całkiem pomocne. Stworzyłem metodę rozszerzenia na podstawie twojego przykładu. Przy okazji, w przypadku dużej liczby iteracji lepiej użyć StringBuilderklasy.
AlexMelw,
2
Link Andreys był martwy. To jest aktualny link do jego implementacji: github.com/AndreyWD/EasySharp/blob/master/NHelpers/ ...
Christian Junk
To wygląda profesjonalnie Andrey. Włożyłem twoją bibliotekę do mojego zestawu narzędzi. Dzięki. @AndreyWD
Oguzhan KIRCALI