Protokollierung und Ablaufverfolgung in .NET-Anwendungen
Wenn Sie ihre Anwendung weiter entwickeln und komplexer werden, müssen Sie möglicherweise weitere Debugdiagnosen auf Ihre Anwendung anwenden.
Die Ablaufverfolgung bietet Ihnen eine Möglichkeit, Ihre Anwendung während der Ausführung zu überwachen. Sie können Instrumente für Ablaufverfolgung und Debugging bereits in der Entwicklungsphase zu Ihren .NET-Anwendungen hinzufügen. Sie können diese Instrumentierung während der Entwicklung der Anwendung und nach der Bereitstellung verwenden.
Diese einfache Technik ist überraschend leistungsfähig. Sie kann in Situationen verwendet werden, in denen Sie mehr als bloß einen Debugger benötigen:
- Probleme, die über längere Zeiträume auftreten, sind mit einem herkömmlichen Debugger unter Umständen nur schwer zu finden und zu beheben. Protokolle ermöglichen eine detaillierte Post-mortem-Überprüfung, die sich über lange Zeiträume erstrecken kann. Im Gegensatz dazu sind Debugger auf Echtzeitanalysen beschränkt.
- Multithreadanwendungen und verteilte Anwendungen sind häufig schwierig zu debuggen. Durch das Anfügen eines Debuggers wird häufig das Verhalten geändert. Sie können detaillierte Protokolle nach Bedarf analysieren, um komplexe Systeme zu verstehen.
- Probleme in verteilten Anwendungen können aus der komplexen Interaktion zwischen einer Vielzahl von Komponenten erwachsen. Häufig ist es nicht sinnvoll, jeden Teil des Systems mit einem Debugger zu verbinden.
- Viele Dienste sollten nicht verzögert werden. Das Anfügen eines Debuggers verursacht häufig Timeoutfehler.
- Probleme sind nicht immer vorhersehbar. Protokollierung und Ablaufverfolgung sind auf einen geringen Mehraufwand ausgelegt, sodass Programme immer aufzeichnen können, falls ein Problem auftritt.
Ausgeben von Informationen in Ausgabefenstern
Bisher haben wir die Konsole dazu verwendet, dem Benutzer der Anwendung Informationen anzuzeigen. Es gibt andere Arten von Anwendungen, die mit .NET erstellt werden, die Benutzeroberflächen und keine sichtbare Konsole aufweisen, z. B. mobile, Web- und Desktop-Apps. In diesen Anwendungen wird System.Console verwendet, um Meldungen „im Hintergrund“ zu protokollieren. Diese Meldungen werden möglicherweise in einem Ausgabefenster in Visual Studio oder Visual Studio Code angezeigt. Vielleicht werden sie auch in ein Systemprotokoll wie z. B. logcat von Android ausgegeben. Daher sollten Sie bei verwendung System.Console.WriteLine in einer nichtconsole-Anwendung sehr berücksichtigen.
In dieser Situation können System.Diagnostics.DebugSystem.Diagnostics.Trace Sie zusätzlich zu System.Console. Beide Debug sind Teil Trace und System.Diagnostics schreiben nur dann in Protokolle, wenn ein entsprechender Listener angefügt ist.
Welche Ausgabeformat-API Sie verwenden, ist Ihnen überlassen. Hauptunterschiede:
-
System.Console
- Immer aktiviert und schreibt immer in die Konsole.
- Dies ist nützlich für Informationen, die der Kunde möglicherweise im Release sehen muss.
- Da es sich um den einfachsten Ansatz handelt,
System.Consolewird häufig für das temporäre Ad-hoc-Debuggen verwendet. Dieser Debugcode wird häufig nicht in die Quellcodeverwaltung eingecheckt.
-
System.Diagnostics.Trace
- Nur aktiviert, wenn
TRACEdefiniert ist. - Schreibt in angefügte Listener (standardmäßig DefaultTraceListener).
- Verwenden Sie diese API, wenn Sie Protokolle erstellen, die Sie in den meisten Builds aktivieren möchten.
- Nur aktiviert, wenn
-
System.Diagnostics.Debug
- Nur aktiviert, wenn
DEBUGdefiniert ist (im Debugmodus). - Schreibt in einen angefügten Debugger.
- Verwenden Sie diese API, wenn Sie Protokolle erstellen, die Sie nur in Debugbuilds aktivieren möchten.
- Nur aktiviert, wenn
Console.WriteLine("This message is readable by the end user.")
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");
Überlegen Sie beim Entwerfen Ihrer Strategie für Ablaufverfolgung und Debugging, wie die Ausgabe aussehen soll. Mehrere Write-Anweisungen, die mit nicht verknüpften Informationen gefüllt sind, erstellen ein Protokoll, das schwer zu lesen ist. Andererseits kann die Verwendung von WriteLine zur Anzeige zusammengehöriger Anweisungen auf separaten Zeilen dazu führen, dass Benutzer nur schwer erkennen können, welche Informationen zusammengehören. Im Allgemeinen sollten Sie mehrere Write-Anweisungen verwenden, wenn Sie Informationen aus mehreren Quellen zu einer einzelnen Informationsmeldung zusammenfassen möchten. Verwenden Sie dagegen die WriteLine-Anweisung, wenn Sie eine einzelne vollständige Meldung erstellen möchten.
Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");
Die folgende Ausgabe stammt aus der vorherigen Protokollierung mit Debug:
Debug - This is a full line.
This is another full line.
Definieren von TRACE- und DEBUG-Konstanten
Wenn eine Anwendung im Debugmodus ausgeführt wird, ist die Konstante DEBUG standardmäßig definiert. Sie können diese Definition steuern, indem Sie in einer Eigenschaftengruppe einen DefineConstants Eintrag in der Projektdatei hinzufügen. Im Folgenden sehen Sie ein Beispiel der Aktivierung von TRACE sowohl für Debug- als auch für Release-Konfigurationen zusätzlich zur Aktivierung von DEBUG für Debug-Konfigurationen.
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
Wenn Sie verwenden Trace , wenn Sie nicht an den Debugger angefügt sind, müssen Sie einen Ablaufverfolgungslistener konfigurieren, z. B. dotnet-trace.
Bedingte Ablaufverfolgung
Zusätzlich zu den einfachen Methoden Write und WriteLine gibt es auch die Möglichkeit, mit WriteIf und WriteLineIf Bedingungen hinzuzufügen. Beispiel: Die folgende Logik prüft, ob die Anzahl 0 ist und gibt dann eine Debugmeldung aus:
if(count == 0)
{
Debug.WriteLine("The count is 0 and this may cause an exception.");
}
Sie kann zu einer einzigen Codezeile umgeschrieben werden:
Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");
Sie können diese Bedingungen auch mit Trace und Flags verwenden, die Sie in Ihrer Anwendung definieren:
bool errorFlag = false;
System.Diagnostics.Trace.WriteIf(errorFlag, "Error in AppendData procedure.");
System.Diagnostics.Debug.WriteIf(errorFlag, "Transaction abandoned.");
System.Diagnostics.Trace.Write("Invalid value for data request");
Überprüfen, ob bestimmte Bedingungen erfüllt sind
Mithilfe einer Assertion oder einer Assert-Anweisung wird eine Bedingung überprüft, die Sie als Argument der Assert-Anweisung angeben. Wenn die Bedingung als "True" ausgewertet wird, erfolgt keine Aktion. Wenn die Bedingung auf "False" ausgewertet wird, schlägt die Assertion fehl. Wenn Sie das Programm mit einem Debugbuild erneut ausführen, wechselt es in den Unterbrechungsmodus.
Sie können die Assert-Methode von entweder Debug oder Trace verwenden, die sich im Namespace System.Diagnostics befinden.
Debug-Klassenmethoden sind in einer Releaseversion des Programms nicht enthalten, daher vergrößern sie weder den Releasecode noch reduzieren dessen Geschwindigkeit.
Sie können die System.Diagnostics.Debug.Assert-Methode beliebig verwenden, um Bedingungen zu überprüfen, die bei fehlerfreiem Code "True" ergeben sollten. Angenommen, Sie haben eine Funktion geschrieben, die ganze Zahlen dividiert. Gemäß den Regeln der Mathematik kann der Divisor niemals 0 sein. Sie können diese Bedingung mithilfe einer Assertion testen:
int IntegerDivide(int dividend, int divisor)
{
Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");
return dividend / divisor;
}
Wenn Sie diesen Code im Debugger ausführen, wird die Assertionsanweisung ausgewertet. Aber in der Releaseversion wird der Vergleich nicht gemacht, daher gibt es keinen zusätzlichen Aufwand.
Hinweis
Wenn Sie System.Diagnostics.Debug.Assert verwenden, stellen Sie sicher, dass kein Code innerhalb von Assert die Ergebnisse des Programms verändert, nachdem „Assert“ entfernt wurde. Andernfalls führen Sie möglicherweise versehentlich einen Fehler ein, der erst in der Releaseversion Ihres Programms zutage tritt. Seien Sie besonders vorsichtig bei Assertionen, die Funktions- oder Prozeduraufrufe enthalten.
Wie Sie sehen können, ist die Verwendung Debug und Trace aus dem System.Diagnostics Namespace eine hervorragende Möglichkeit, wichtigen Kontext bereitzustellen, wenn Sie Ihre Anwendung ausführen und debuggen.