Comment imprimer la trace de pile actuelle dans .NET sans aucune exception?

350

J'ai un code C # régulier. Je n'ai aucune exception . Je souhaite enregistrer par programme la trace de pile actuelle à des fins de débogage. Exemple:

public void executeMethod() 
{
    logStackTrace();
    method();
}
Ricibald
la source

Réponses:

400

Jetez un œil à l' System.Diagnosticsespace de noms. Beaucoup de goodies là-dedans!

System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();

C'est vraiment bien d'avoir un coup d'œil pour savoir ce qui se passe sous le capot.

Je vous recommande de jeter un œil aux solutions de journalisation (telles que NLog, log4net ou les modèles et pratiques Microsoft Enterprise Library) qui peuvent atteindre vos objectifs, puis certaines. Bonne chance mec!

Spence
la source
74
Gardez à l'esprit que le chienStackTrace est lent - utilisez-le avec parcimonie.
Jonathan Dickinson
214

Une alternative à System.Diagnostics.StackTraceconsiste à utiliser System.Environment.StackTrace qui retourne une représentation sous forme de chaîne de la trace de pile.

Une autre option utile consiste à utiliser les variables de débogage$CALLER et $CALLSTACK dans Visual Studio car cela peut être activé au moment de l'exécution sans reconstruire l'application.

larsmoa
la source
6
Environment.StackTracejuste nouveau est une instance de StackTrace.
Daniel
9
@Daniel: Oui, mais cela System.Environment.StackTracepourrait être un moyen plus pratique d'accéder à ces informations.
larsmoa
6
@AndreiRinea: En fait, je crois que vous pouvez accéder aux numéros de ligne en utilisant System.Diagnostics.StackTrace- voir msdn.microsoft.com/en-us/library/…
larsmoa
5
N'est-ce pas ennuyeux qui Environment.StackTracecommence toujours par at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace()? Cela ne fait pas partie de la trace de pile actuelle au moment où quelqu'un la recherche.
Rory
7
@Rory, jetez un œil au constructeur StackTrace (int skipFrames, bool fNeedFileInfo), vous pouvez ignorer l'image de départ. ipen la méthode dans ILSpy et vous pouvez voir ce qu'elle fait
Walter Vehoeven
39

Il y a deux façons de faire ça. Le System.Diagnostics.StackTrace()vous donnera une trace de pile pour le thread actuel. Si vous avez une référence à une Threadinstance, vous pouvez obtenir la trace de pile pour cela via la version surchargée de StackTrace().

Vous pouvez également consulter la question de dépassement de pile Comment obtenir la trace de pile d'un thread non actuel? .

Brian Rasmussen
la source
16

Vous pouvez également le faire dans le débogueur Visual Studio sans modifier le code.

  1. Créez un point d'arrêt où vous souhaitez voir la trace de la pile.
  2. Cliquez avec le bouton droit sur le point d'arrêt et sélectionnez "Actions ..." dans VS2015. Dans VS2010, sélectionnez "Lorsque vous frappez ...", puis activez "Imprimer un message".
  3. Assurez-vous que "Continuer l'exécution" est sélectionné.
  4. Tapez le texte que vous souhaitez imprimer.
  5. Ajoutez $ CALLSTACK où vous voulez voir la trace de la pile.
  6. Exécutez le programme dans le débogueur.

Bien sûr, cela n'aide pas si vous exécutez le code sur une autre machine, mais il peut être très pratique de pouvoir cracher automatiquement une trace de pile sans affecter le code de publication ou sans même avoir besoin de redémarrer le programme.

Hank Schultz
la source
7
Si vous voulez voir une trace de pile et que vous êtes déjà dans le débogueur VS à un point d'arrêt, allez simplement dans Debug-> Windows-> Call Stack.
khargoosh
5
Oui, mais si vous le faites de cette façon, le programme ne doit pas s'arrêter pour que vous puissiez voir la trace de la pile.
Hank Schultz
7
Console.WriteLine(
    new System.Diagnostics.StackTrace().ToString()
    );

La sortie sera similaire à:

à YourNamespace.Program.executeMethod (String msg)

à YourNamespace.Program.Main (String [] args)

Remplacez Console.WriteLinepar votre Logméthode. En fait, il n'est pas nécessaire .ToString()pour le boîtier Console.WriteLine comme il l'accepte object. Mais vous en aurez peut-être besoin pour votre méthode Log (string msg).

épox
la source
-2
   private void ExceptionTest()
    {
        try
        {
            int j = 0;
            int i = 5;
            i = 1 / j;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
            var stList = ex.StackTrace.ToString().Split('\\');
            Console.WriteLine("Exception occurred at " + stList[stList.Count() - 1]);
        }
    }

Semble travailler pour moi

Jeff Jacobs
la source
3
Cela ne fait que générer une exception évidente. Pourquoi? Pourquoi ne pas simplement instancier explicitement une exception, plutôt qu'une faille qui déclenchera une exception en soi? Quel est l'avantage de la logique de capture supplémentaire requise pour atteindre l'exception réelle? Et même dans ce cas, vous ignorez toujours la vraie question publiée sur la façon d'obtenir une trace de pile sans aucune exception (lire le titre).
Flater
c'est une réponse valable, mais une horrible solution. PERSONNE NE DEVRAIT L'UTILISER ... @Jeff partout où vous avez fait cela, remplacez-le par un code de descente comme les autres réponses suggérées.
Tomer W