Click here to Skip to main content
15,886,110 members
Articles / Programming Languages / XML
Article

Write Debug/Trace Information to XML

Rate me:
Please Sign up or sign in to vote.
3.47/5 (7 votes)
6 Apr 20053 min read 68.2K   662   24   4
An article which demonstrates how to direct trace/debug information to an XML file.

Debug output shown in a DataGrid.

Introduction

This article shows how you can create a subclass of System.Diagnostics.TraceListener which writes trace/debug information to an XML file. This is useful if you want to, for example:

  • Read the resultant XML into a DataSet and then view it in a grid. Perhaps you might bind the grid to a DataView which only shows a certain subset of the output messages (e.g.: you might only want to see the messages that were logged between midnight and 1:00 a.m.).
  • Perform XPath queries on the XML data.
  • Save the results of debugging sessions in a structured format for later use. Perhaps you might store the XML in a database so that the output of multiple debugging sessions can be retrieved and compared easily.

Background

The .NET Framework offers ample support for debugging and monitoring applications. The System.Diagnostics namespace contains flexible classes which can be easily incorporated into any application. Within the System.Diagnostics namespace lives an abstract class named TraceListener. TraceListener-derived classes are used when you call, for instance, Debug.WriteLine(...) or Trace.Write(...) to direct the output messages to some backing store (the default listener targets the Output window in Visual Studio and Assertion Failed message boxes). It is possible to create your own TraceListener which can write out your messages to any destination you can think of (within the realm of reason :).

This article shows how to subclass TraceListener and direct the debug messages to an XML file. This is accomplished via an XmlTextWriter, which remains open throughout the duration of the object's existence. Please note that you must call Dispose() on the XmlTraceListener object when you are finished using it so that it will close the stream it uses. Once the object has been disposed of, it's probably a good idea to remove it from the Listeners collection of Trace and Debug. Keep in mind that those two classes share the same ListenerCollection, so removing it from one of them will remove it from both.

Each output message is stored in a separate XML element. All of the data is contained in attributes within the element. By default, the XmlTraceListener does not add in too much extra information to each XML element. Since everyone's requirements will be different, the provided implementation just provides some basic data. If you find a need to write out extra attributes containing data you need, modify the WriteElement method in XmlTraceListener.

Using the code

Using the code is pretty simple. The attached WinForms sample project shows exactly how to do it. Of course, you can use the XmlTraceListener in any type of .NET application. If you are working in low-trust environments, you might need to consider whether the machine on which the process that the XmlTraceListener is running in will grant your code the requisite FileIOPermission. Below are some relevant fragments which show how to use this class:

C#
XmlTraceListener xmlListener;

private void XmlTracerForm_Load(object sender, System.EventArgs e)
{
   // Create the XmlTraceListener and add it to the Listener's collection.
   //
   this.xmlListener = new System.Diagnostics.XmlTraceListener( "debug.xml" );
   Debug.Listeners.Add( this.xmlListener );

   Debug.Write( "Form has loaded", "Marker" );
}

protected override void Dispose( bool disposing )
{
   if( disposing )
   {
      // When the form is being disposed, be sure to dispose the listener
      // so that its internal stream will be closed.
      //
      if( this.xmlListener != null )
      {
         this.xmlListener.Dispose();
         Debug.Listeners.Remove( this.xmlListener );
         this.xmlListener = null;
      }

      if (components != null) 
      {
         components.Dispose();
      }
   }
   base.Dispose( disposing );
}

The code in the XmlTraceListener class is simple. The heart of this class is in the WriteElement method. All of the output methods of TraceListener were overridden and they simply pass the call off to this method.

C#
private void WriteElement( string message, string extraInfo, bool isFailure )
{
   this.xmlWriter.WriteStartElement( "output" );

   this.xmlWriter.WriteAttributeString( "failure", isFailure.ToString() );

   this.xmlWriter.WriteAttributeString( "time", 
                  DateTime.Now.TimeOfDay.ToString() );

   // If this was called due to a failed assertion
   // or an explicit call to Fail(), then 
   // the 'extraInfo' param is the detailed message about what went wrong.
   //
   if( isFailure )
   {
      this.xmlWriter.WriteAttributeString( "message", message );
      this.xmlWriter.WriteAttributeString( "detailMessage", extraInfo );
   }
   else
   {
      this.xmlWriter.WriteAttributeString( "category", extraInfo );
      this.xmlWriter.WriteAttributeString( "message", message );
   }

   this.xmlWriter.WriteEndElement();

   this.xmlWriter.Flush();
}

The XML output is straightforward. The output used to populate the DataGrid seen at the top of the article is listed below. Besides for the sake of simplicity, the XML has elements with attributes only (as opposed to nested child elements) because this provides the most natural mapping to a DataTable in a DataSet.

XML
<?xml version="1.0" encoding="Windows-1252"?>
<traceOutput>
    <output failure="False" time="18:25:01.4843750" 
        category="Marker" message="Form has loaded" />
    <output failure="False" time="18:25:03.2343750" 
        category="TextChanged In TextBox" message="T" />
    <output failure="False" time="18:25:03.4843750" 
        category="TextChanged In TextBox" message="Te" />
    <output failure="False" time="18:25:03.7187500" 
        category="TextChanged In TextBox" message="Tes" />
    <output failure="False" time="18:25:04.2187500" 
        category="TextChanged In TextBox" message="Test" />
    <output failure="False" time="18:25:05.2187500" 
        category="TextChanged In TextBox" message="Testi" />
    <output failure="False" time="18:25:05.3906250" 
        category="TextChanged In TextBox" message="Testin" />
    <output failure="False" time="18:25:05.5625000" 
        category="TextChanged In TextBox" message="Testing" />
    <output failure="False" time="18:25:07.0156250" 
        category="Marker" message="AddToList Button Clicked" />
    <output failure="False" time="18:25:08.1406250" 
        category="SelectedIndexChanged In ListBox" message="0" />
    <output failure="False" time="18:25:09.7968750" 
        category="Marker" message="Form Is Closing" />
</traceOutput>

Points of Interest

I hope that this little utility helps you shave some time off of your debugging sessions. Once you have the debug output in XML format, the possibilities of how you can view/filter/sort/compare/etc. it are endless. I also hope that if you devise a clever trick or technique using this utility that you'll take the time to share it with us!

History

  • 4/3/05 - Created article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Josh creates software, for iOS and Windows.

He works at Black Pixel as a Senior Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].

See his website Josh Smith Digital[^].

Comments and Discussions

 
Generalamazing Pin
GERMAN REYES6-Feb-07 8:32
GERMAN REYES6-Feb-07 8:32 
GeneralTraceTool Pin
Thierry Parent13-Apr-05 20:39
Thierry Parent13-Apr-05 20:39 
GeneralRe: TraceTool Pin
Josh Smith14-Apr-05 3:36
Josh Smith14-Apr-05 3:36 
GeneralNot valid XML while running Pin
Urs Enzler12-Apr-05 21:54
Urs Enzler12-Apr-05 21:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.