Wie drucke ich ausnahmslos den aktuellen Stack Trace in .NET?

349

Ich habe einen regulären C # -Code. Ich habe keine Ausnahmen . Ich möchte den aktuellen Stack-Trace zum Debuggen programmgesteuert protokollieren. Beispiel:

public void executeMethod() 
{
    logStackTrace();
    method();
}
Ricibald
quelle

Antworten:

399

Schauen Sie sich den System.DiagnosticsNamespace an. Viele Leckereien drin!

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

Es ist wirklich gut, sich umzuschauen, um zu erfahren, was unter der Haube vor sich geht.

Ich würde empfehlen, dass Sie sich mit Protokollierungslösungen (wie NLog, log4net oder den Microsoft-Mustern und -Praktiken der Enterprise Library) befassen, die möglicherweise Ihre Ziele erreichen, und noch einige mehr. Viel Glück, Junge!

Spence
quelle
74
Beachten Sie, dass StackTraceist Hund langsam - es ist so sparsam zu verwenden.
Jonathan Dickinson
214

Eine Alternative dazu System.Diagnostics.StackTraceist die Verwendung von System.Environment.StackTrace, das eine Zeichenfolgendarstellung des Stacktraces zurückgibt.

Eine weitere nützliche Option ist die Verwendung der Variablen$CALLER und $CALLSTACK Debugging in Visual Studio, da dies zur Laufzeit aktiviert werden kann, ohne die Anwendung neu zu erstellen.

Larsmoa
quelle
6
Environment.StackTraceNur neu ist eine Instanz von StackTrace.
Daniel
9
@ Daniel: Ja, System.Environment.StackTracekönnte aber eine bequemere Möglichkeit sein, auf diese Informationen zuzugreifen.
Larsmoa
6
@AndreiRinea: Eigentlich glaube ich, dass Sie auf Zeilennummern zugreifen können mit System.Diagnostics.StackTrace- siehe msdn.microsoft.com/en-us/library/…
larsmoa
5
Ist es nicht ärgerlich, dass Environment.StackTraceimmer damit beginnt at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace()? Dies ist nicht Teil der aktuellen Stapelverfolgung, da an dem Punkt, an dem jemand danach sucht.
Rory
7
@Rory, schauen Sie sich den Konstruktor StackTrace an (int skipFrames, bool fNeedFileInfo), Sie können den Startrahmen überspringen. Wenn Sie die Methode in ILSpy öffnen, können Sie sehen, was sie bewirkt
Walter Vehoeven,
39

Es gibt zwei Möglichkeiten, dies zu tun. Das System.Diagnostics.StackTrace()gibt Ihnen einen Stack-Trace für den aktuellen Thread. Wenn Sie einen Verweis auf eine ThreadInstanz haben, können Sie den Stack-Trace dafür über die überladene Version von abrufen StackTrace().

Vielleicht möchten Sie auch die Frage zum Stapelüberlauf lesen. Wie erhalte ich die Stapelverfolgung eines nicht aktuellen Threads? .

Brian Rasmussen
quelle
16

Sie können dies auch im Visual Studio-Debugger tun, ohne den Code zu ändern.

  1. Erstellen Sie einen Haltepunkt, an dem die Stapelverfolgung angezeigt werden soll.
  2. Klicken Sie mit der rechten Maustaste auf den Haltepunkt und wählen Sie in VS2015 "Aktionen ...". Wählen Sie in VS2010 "When Hit ..." und aktivieren Sie "Print a message".
  3. Stellen Sie sicher, dass "Ausführung fortsetzen" ausgewählt ist.
  4. Geben Sie einen Text ein, den Sie ausdrucken möchten.
  5. Fügen Sie $ CALLSTACK hinzu, wo immer Sie den Stack-Trace sehen möchten.
  6. Führen Sie das Programm im Debugger aus.

Dies hilft natürlich nicht, wenn Sie den Code auf einem anderen Computer ausführen, aber es kann sehr praktisch sein, einen Stack-Trace automatisch auszuspucken, ohne den Release-Code zu beeinflussen oder das Programm neu starten zu müssen.

Hank Schultz
quelle
7
Wenn Sie einen Stack-Trace sehen möchten und sich bereits an einem Haltepunkt im VS-Debugger befinden, gehen Sie einfach zu Debug-> Windows-> Call Stack.
khargoosh
5
Ja, aber wenn Sie dies auf diese Weise tun, muss das Programm nicht anhalten, damit Sie die Stapelverfolgung sehen können.
Hank Schultz
7
Console.WriteLine(
    new System.Diagnostics.StackTrace().ToString()
    );

Die Ausgabe ist ähnlich wie:

at YourNamespace.Program.executeMethod (String msg)

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

Ersetzen Sie Console.WriteLinedurch Ihre LogMethode. Tatsächlich ist .ToString()der Console.WriteLine-Fall nicht erforderlich, da er akzeptiert wird object. Möglicherweise benötigen Sie dies jedoch für Ihre Protokollmethode (Zeichenfolge msg).

Epox
quelle
-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]);
        }
    }

Scheint für mich zu arbeiten

Jeff Jacobs
quelle
3
Dies erzeugt nur eine offensichtliche Ausnahme. Warum? Warum nicht einfach explizit eine Ausnahme instanziieren und nicht einen Fehler, der eine Ausnahme an und für sich auslöst? Was ist der Vorteil der zusätzlichen Fanglogik, die erforderlich ist, um zur eigentlichen Ausnahme zu gelangen? Und selbst dann ignorieren Sie immer noch die tatsächlich gestellte Frage, wie Sie ausnahmslos einen Stack-Trace erhalten (lesen Sie den Titel).
Flater
Es ist eine gültige Antwort, aber eine gottesfürchtige Lösung. Niemand sollte es benutzen ... @Jeff, wo immer Sie das getan haben, ersetzen Sie es durch einen Abstiegscode wie die anderen vorgeschlagenen Antworten.
Tomer W