Comment imprimer une trace de pile complète en exception?

97

Par exemple, en un seul endroit ...

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

... et dans un autre endroit ...

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

Le stacktrace que j'imprime, il ne commence que de a à b, il n'inclut pas le stacktrace interne de WebException.

Comment puis-je imprimer tout le stacktrace ???

jojo
la source
1
Notez que le stacktrace de WebException d'origine ne serait pas imprimé car vous avez levé une nouvelle exception plutôt que de relancer l'exception WebException. À utiliser throw;à la place de throw new MyCustomException(...)si vous souhaitez conserver (et générer) la pile d'exceptions d'origine.
Beel

Réponses:

174

J'utilise généralement la méthode .ToString () sur les exceptions pour présenter toutes les informations d'exception (y compris la trace de la pile interne) dans le texte:

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

Exemple de sortie:

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
la source
Très bien. Je cherchais un moyen simple de le faire et le voici. Un petit souci est qu'il n'est pas aussi explicite que si vous utilisez un objet exception.StackTrace (par exemple). Je me demande s'il existe une manière plus explicite de faire de même?
codea
4
Sachez que certaines bibliothèques remplacent la ToStringméthode et affichent des messages personnalisés au lieu des informations complètes (c'est une mauvaise pratique de codage, alors ne faites pas cela, jamais)
Dinei
@P ரதீப் J'utilise ToStringchaque fois que je suis sûr qu'il n'est pas écrasé, et j'utilise directement les propriétés autrement (comme la réponse d'Andrew Hare ).
Dinei
53

Utilisez une fonction comme celle-ci:

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

Ensuite, vous pouvez l'appeler comme ceci:

try
{
    // invoke code above
}
catch(MyCustomException we)
{
    Debug.Writeline(FlattenException(we));
}
Andrew Hare
la source
13
Ou vous pouvez utiliser ToString?
Justin
J'utilise le ToString et je pense que ça va. J'irais avec la solution d'Andrew si je ne veux que l'exception interne la plus basse (avec la raison réelle) ou une cueillette similaire .. fonctionne à la fois cependant :)
EeKay
C'est plus flexible que ToString, car vous pouvez choisir ce qui entre dans cette chaîne. Peut-être que je ne suis intéressé que par les traces de pile, pas nécessairement par les messages. Ou je le veux en tant que List <string> pas une seule chaîne.
Zar Shardan
18

1. Créer une méthode: Si vous passez votre exception à la fonction suivante, elle vous donnera toutes les méthodes et détails qui sont les raisons de l'exception.

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éthode d'appel: Vous pouvez appeler la méthode comme ceci.

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

3. Obtenez le résultat:

File: c:\MyProject\Program.cs, Method:MyFunction, LineNumber: 29  -->  
File: c:\MyProject\Program.cs, Method:Main, LineNumber: 16  --> 
Oguzhan KIRCALI
la source
1
Très utile. J'ai créé une méthode d'extension basée sur votre exemple. BTW, dans le cas d'un grand nombre d'itérations, vous feriez mieux d'utiliser StringBuilderclass.
AlexMelw
2
Andreys Link était mort. Voici le lien actuel vers son implémentation: github.com/AndreyWD/EasySharp/blob/master/NHelpers/…
Christian Junk
Cela a l'air professionnel Andrey. J'ai mis votre bibliothèque dans ma boîte à outils. Merci. @AndreyWD
Oguzhan KIRCALI