Debuggen – TraceListener – Dein Freund und Helfer – C#

Jeder der sich mit der Entwicklung von Programmen beschäftigt kommt früher oder später um die Verwendung eines Debuggers zur Fehlersuche nicht umhin.

Doch bevor ich weiter schreibe zuerst eine kurze Begriffserklärung der wichtigsten Begriffe:

Bug-1 debugger

Was bedeutet denn Debuggen und was machen wir um einen Fehler zu finden?

  • Das Programm wird in der Entwicklungsumgebung im Debug Modus gestartet.
  • Es werden Breakpoints gesetzt.
  • Inhalte von Variablen werden angesehen (evtl. verändert)
  • Der Ablauf des Programms wird verfolgt

Um Komplexere Abläufe zu beobachten bietet es sich an Werte einfach über nachfolgende Methoden

  • System.Diagnostics.Debug.WriteLine(„“)
  • System.Diagnostics.Trace.WriteLine(„“)

im Ausgabefenster von Visual Studio auszugeben.

Soweit sind die Möglichkeiten recht umfangreich um einem Fehler auf die Spur zu kommen.

Was aber wenn der Fehler, der beim Kunden auftritt, einfach nicht auf unserem Entwicklungsrechner reproduzierbar ist. Wie kann man vorgehen um mehr Informationen über das Problem zu erhalten, ohne dem Kunden eine Entwicklungsumgebung auf seinen Rechner zu bügeln.

Eventuell würde es ja schon helfen wenn wir die Originaldaten (Datenbank, Dokumente etc.) vom Kunden hätten, auch das können wir uns in vielen Fällen einfach abschminken und darüber sollten wir in den meisten Fällen auch gar nicht nachdenken.

Man kann aber bereits während der Entwicklung eine Menge dazu beitragen, später einmal eine recht gute Fehleranalyse auch vor Ort beim Kunden zu erhalten.

Wenn wir während der Entwicklung, an Stellen an von welchen wir glauben Informationen für eine Fehleranalyse bekommen zu können bereits vorsorglich über die Write… Methoden der Klassen Debug und Trace des System.Diagnostics Namespace Informationen bereitstellen, dann können wir später diese Informationen dazu verwenden einen möglichen Fehler zu analysieren.

Damit wir aber später in einer Anwendung, die dann nicht im Debugger ausgeführt wird, an diese Informationen herankommen, können wir durch Einrichtung eines TraceListener dafür sorgen, dass diese Informationen auf einem beliebigen (na ja fast, es muss ein TraceListener für die gewünschte Ausgabe vorhanden sein, oder wir müssen uns einen eigenen TraceListener schreiben) Ausgabemedium wie Standard Output, einer Textdatei, einer XML Datei eine … usw. einfach ausgeben werden.

Schauen wir uns doch kurz nachfolgende Aufstellung an welche TraceListener uns das NET Framework (ab 2.0) bereits zur Verfügung stellt:

Die Abstrakte Basis Klasse im Namespace System.Diagnostics (Von der können wir eigene TraceListener ableiten):

  • TraceListener

Folgende Implementierungen sind im Namespace System.Diagnostics verfügbar:

  • ConsoleTraceListener
  • DefaultTraceListener
  • DelimitedListTraceListener
  • Eventing.EventProviderTraceListener
  • EventLogTraceListener
  • EventSchemaTraceListener
  • TextWriterTraceListener
  • XmlWriterTraceListener

Was mach nun ein solcher TraceListener und wie können wir Ihn verwenden.

In einer .NET Anwendung wird in der Klasse Trace des  Namespace System.Diagnostics unter anderem eine statische Eigenschaft Listeners vorgehalten, diese Auflistung enthält alle TraceListener die bei den Debug und Trace Methoden aufgerufen werden.

Wird nun in unserem Code ein Methodenaufruf wie System.Diagnostics.Debug.WriteLine(txtName.Text) durchgeführt, dann führt das dazu, dass für jede in der Auflistung enthaltenen Listener die implementierte Methode WriteLine aufgerufen wird.

Wenn wir das in einem Visual Studio Projekt im Debugger Mode machen ohne irgendwelche Änderungen an der Konfiguration oder Manipulation der Auflistung in unserem Code vorzunehmen, dann enthält die Auflistung Listeners lediglich den Default TraceListener, und das ist der Listener, welche die Ausgabe im Ausgabefenster von Visual Studio vornimmt.

Wie können wir nun einen anderen TraceListener, als Beispiel den TextWriterTraceListener (Dieser Listener schreibt die Daten in eine Textdatei) verwenden um die Ausgaben für uns verwendbar zu machen, auch ohne die Anwendung im Visual Studio auszuführen?

Es gibt 2 Arten wie wir den/die Listener angeben können:

  • Aus dem Source Code
  • Aus der App.config
Angabe eines Listener aus dem Source Code

Hier im Beispiel einer Windows Forms Anwendung:

Wir fügen einfach in den Konstruktor der Windows Form folgenden Code hinzu:

System.Diagnostics.TextWriterTraceListener tListener = new System.Diagnostics.TextWriterTraceListener(„Trace.Log“);
System.Diagnostics.Trace.Listeners.Add(tListener);

Dieser Code fügt einen neuen Listener, in unserem Fall den TextWriterTraceListener zur Auflistung des Listener hinzu (siehe nachfolgende Abbildung):

Listener Auflistung

Es geht aber noch einfacher, ja wirklich „noch einfacher“.

Angabe des Listener in der App.Config

Um einen oder auch mehrere Listener hinzuzufügen oder auch um einen Listener (z.B. den Default Listener) zu entfernen können wir innerhalb des Bereich „Config“ einen eigenen Unter-Bereich System.Diagnostics hinzufügen.

In diesem Bereich können wir dann über die App.Config Datei auf die Listeners Auflistung zugreifen und Veränderungen durchführen.

Hier ein Beispiel, welche den TextWriterListener hinzufügt und außerdem noch den Default Listener entfernt.

<configuration>
<system.diagnostics>
<trace autoflush=“true“ indentsize=“4″>
<listeners>
<add name=“FileListener“ type=“System.Diagnostics.TextWriterTraceListener“ initializeData=“Trace.log“ />
<remove name=“Default“ />
</listeners>
</trace>
</system.diagnostics>
</configuration>

Soweit zur Einrichtung von TraceListener zur besseren Fehleranalyse beim Kunden.

imageÜbrigens sind Trace und Debug Statements eigentlich vollkommen gleich, ob ein Trace oder ein Debug Aufruf ausgeführt wird, hängt davon ab, ob die vordefinierten Konstanten für bedingte Compilierung während der Erstellung des Programms gesetzt waren (In Visual Studio findet man diese Schalter übrigens in den Projekt Eigenschaften auf dem Karteireiter Build (Erstellen)).

Und nun viel Spaß bei der Suche nach den Käfern !

Ich finde die Geschichte um die Herkunft der Bezeichnung Bug für einen Programmfehler trotz der Behauptung das es sich um eine moderne Legende handeln soll, schön und lesenswert.

Wer möchte kann hier mehr über diese Legende lesen

PS: Ich Denke, in nicht so ferner Zukunft, werde ich dann mal über die Erstellung eines eigenen Listener berichten.

Ein Gedanke zu „Debuggen – TraceListener – Dein Freund und Helfer – C#“

  1. Hallo

    Nur zur Ergänzung, app.config soll heissen daß man eine Datei hat die, wenn das Programm zB Server.exe heisst, dann Server.exe.config heissen muß. Die Datei muß im Projekt als zB Textdatei unter diesem Namen hinzugefügt werden.

    Also kurz: app entspricht dem kompletten Program Namen inclusive suffix.

    Gruß
    Andy

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.