Как распечатать полную трассировку стека в исключении?

98

Например, в одном месте ...

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

... и в другом месте ...

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

Я печатаю трассировку стека, она начинается только от a до b, она не включает внутреннюю трассировку стека из WebException.

Как мне распечатать всю трассировку стека ???

Джоджо
источник
1
Обратите внимание, что трассировка стека для исходного WebException не будет напечатана, потому что вы выбросили новое исключение, а не повторно выбросили WebException. Используйте throw;вместо, throw new MyCustomException(...)если вы хотите сохранить (и вывести) исходный стек исключений.
Beel

Ответы:

174

Я обычно использую метод .ToString () для исключений, чтобы представить полную информацию об исключении (включая внутреннюю трассировку стека) в тексте:

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

Пример вывода:

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
Джастин
источник
Очень хорошо. Я искал простой способ сделать это, и вот он. Некоторая небольшая проблема заключается в том, что это не так явно, как если бы вы использовали объект exception.StackTrace (например). Интересно, есть ли более явный способ сделать то же самое?
codea
4
Имейте в виду, что некоторые библиотеки переопределяют ToStringметод и печатают пользовательские сообщения вместо полной информации (это плохая практика кодирования, поэтому никогда не делайте этого)
Dinei
@P ரதீப் Я использую ToStringвсякий раз, когда уверен, что он не перезаписан, а в противном случае использую свойства напрямую (например , ответ Эндрю Хейра ).
Dinei
53

Используйте такую ​​функцию:

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

Тогда вы можете назвать это так:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}
Эндрю Хэйр
источник
13
Или можно использовать ToString?
Джастин
Я использую ToString и думаю, что это нормально. Я бы выбрал решение Эндрю, если мне нужно только самое низкое внутреннее исключение (с реальной причиной) или подобный выбор ... хотя работает и то, и другое :)
EeKay
Это более гибко, чем просто ToString, потому что вы можете выбрать, что входит в эту строку. Возможно, меня интересуют только трассировки стека, не обязательно сообщения. Или я хочу, чтобы это было List <string>, а не одной строкой.
Зар
18

1. Создать метод: если вы передадите свое исключение следующей функции, она предоставит вам все методы и сведения, которые являются причинами исключения.

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. Метод вызова: метод можно вызвать следующим образом.

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

3. Получите результат:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 
Огужан КИРЧАЛИ
источник
1
Довольно полезно. Я сделал на вашем примере метод расширения . Кстати, в случае большого количества итераций лучше использовать StringBuilderclass.
AlexMelw 06
2
Ссылка Андрея была мертва. Это текущая ссылка на его реализацию: github.com/AndreyWD/EasySharp/blob/master/NHelpers/…
Christian Junk
Андрей выглядит профессионально. Я положил вашу библиотеку в свой набор инструментов. Спасибо. @AndreyWD
Oguzhan KIRCALI