Como imprimir o rastreamento de pilha completo em exceção?

97

Por exemplo, em um só lugar ...

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

... e em outro lugar ...

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

O stacktrace eu imprimo, ele só começa de a a b, ele não inclui o stacktrace interno da WebException.

Como posso imprimir todo o stacktrace ???

Jojo
fonte
1
Observe que o rastreamento de pilha da WebException de origem não seria impresso porque você lançou uma nova exceção em vez de relançar a WebException. Use throw;no lugar de throw new MyCustomException(...)se desejar preservar (e gerar) a pilha de exceções original.
Beel

Respostas:

174

Eu geralmente uso o método .ToString () em exceções para apresentar as informações completas da exceção (incluindo o rastreamento de pilha interno) no texto:

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

Saída de amostra:

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
fonte
Muito bom. Eu estava procurando uma maneira simples de fazer isso e aqui está. Uma pequena preocupação é que não seja tão explícito como se você usasse o objeto exception.StackTrace (por exemplo). Será que existe uma maneira mais explícita de fazer o mesmo?
codea
4
Esteja ciente de que algumas bibliotecas substituem o ToStringmétodo e imprimem mensagens personalizadas em vez das informações completas (esta é uma prática de codificação ruim, então não faça isso, nunca)
Dinei
@P ரதீப் eu uso ToStringsempre que tenho certeza de que não foi sobrescrito e uso as propriedades diretamente de outra forma (como a resposta de Andrew Hare ).
Dinei de
53

Use uma função como esta:

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

Então você pode chamá-lo assim:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}
Andrew Hare
fonte
13
Ou você pode usar ToString?
Justin
Estou usando o ToString e acho que está bom. Eu escolheria a solução de Andrew se eu só quisesse a exceção interna mais baixa (com o motivo real) ou escolha semelhante ... mas funciona de ambos :)
EeKay
É mais flexível do que apenas ToString, porque você pode escolher o que vai dentro dessa string. Talvez eu esteja interessado apenas nos rastreamentos de pilha, não necessariamente nas mensagens. Ou eu quero isso como uma List <string> e não uma única string.
Zar Shardan
18

1. Criar Método: Se você passar sua exceção para a função a seguir, ela fornecerá todos os métodos e detalhes que são os motivos da exceção.

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. Método de chamada: Você pode chamar o método assim.

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

3. Obtenha o resultado:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 
Oguzhan KIRCALI
fonte
1
Muito útil. Fiz um método de extensão baseado em seu exemplo. BTW, no caso de um grande número de iterações, é melhor usar StringBuilderclass.
AlexMelw
2
O link de Andreys estava morto. Este é o link atual para sua implementação: github.com/AndreyWD/EasySharp/blob/master/NHelpers/…
Christian Junk
Parece um Andrei profissional. Coloquei sua biblioteca em minha caixa de ferramentas. Obrigado. @AndreyWD
Oguzhan KIRCALI