Sunday, June 1, 2003

These Are a Few of My Favorite Things




I was writing some code Friday, and I realized I was working with three
of my favorite namespaces all at once:
System.IO, System.Xml, and System.Diagnositcs.
Most people will have used all of these namespaces at least once, but there are a
bunch of hidden gems that not everyone will have seen.



The task I was trying to pull off was to dump an XML document for debugging
purposes. I wanted to send it both to the console and to a logfile, to give me a real-time
idea of what was going on as well as a permanent record I could go back and analyze
later.



The ability to write a piece of information to more than one place
for diagnostic purposes just cries out for
System.Diagnostics.Trace.
So I started my program off with the following lines of code:



using System;

using System.IO;


using System.Diagnostics;




public class App

{

  public static void Main()

  {

    Trace.Listeners.Add(

      new TextWriteTraceListener(Console.Output));


    string logfile =

      DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss")
+ ".txt";


    Trace.Listeners.Add(

      new TextWriteTraceListener(logfile);



which sets it up so that any time I call Trace.WriteLine,
a piece of text is written both to the command console and to a logfile whose name
is derived from the current date and time. The overload of ToString that
lets you specify the exact format for the date and time is pretty cool, I think.



Later, when I wanted to actually dump the XML, I did this:



StringWriter sw = new StringWriter();


XmlTextWriter wtr = new XmlTextWriter(sw);


wtr.Formatting = Formatting.Indented;


xml.WriteTo(wtr);




Trace.WriteLine(sw.ToString());


wtr.Close();



where xml is the XmlDocument that
I wanted to dump out.



There are a number of cool things in these few lines of code:



·        The StringWriter class
give you a stream that  you can use anywhere you’d use a normal TextWriter (e.g.
the constructor of XmlTextWriter),
but it writes to an internally maintained StringBuilder instead.
Handy.



·        The Formatting property
of XmlTextWriter to get that nice “every
nested element gets indented one level” look. Makes for much more readable output.



·        Of
course, the call to Trace.WriteLine to
actually spew this same XML to more than once place.



A few caveats:



·        You
need to define the symbol TRACE in your build (Project Properties->Configuration
Properties->Build->Conditional Compilation Constants – just type in TRACE)
or Trace.WriteLine will not even make
it into the compiled program.



·        I
found that I needed to go through and flush each trace listener independently, or
my log file would get truncated. That was easy, though: just a foreach loop over the Trace.Listeners collection,
calling Flush and Close on
each TraceListenener.  



2 comments:

  1. Nice article. FYI, the first code snippet shows you adding Console.Output to the Trace.Listener collection twice. Also, I think you meant StringBuilder when you said StringBuffer (perhaps you've been doing some Java programming lately).

    ReplyDelete
  2. D'oh. Right on both counts. I'll fix it.

    ReplyDelete