The System.Diagnostics namespace has gotten some special treatment in Visual Studio 2005 although some of the smaller incremental improvements have been overshadowed by the more glamourous improvements like DebugVisualizer.

What I wanted to post about this time were three new TraceListener’s called ConsoleTraceListener, DelimitedListTraceListener and XmlWriterTraceListener. TraceListeners were a feature that shipped with .NET 1.x as a means of directing debug and trace information to things like files and the Windows event log.

ListenerArchitecture

Despite their general usefulness they tended to be only be used by the .NET Framework boffins who knew about them and when other people needed logging they looked at “third party” frameworks like log4net, EMAB and EIF (including the Logging Application Block).

This was probably due to the fact that the TraceListeners didn’t cater to all the common usage scenarios that people wanted like logging to the screen, emitting CSV files or spitting out XML that could be transformed – the Base Class Library in .NET 2.0 addresses some of these issues.

ConsoleTraceListener

As the name suggests, the ConsoleTraceListener logs out diagnostic information to the console attached to the current process. This is very useful for those quick little utilities that we all write that need to produce output. What is the advantage of doing this over good old Console.WriteLine(…)? Well for one if you also make use of trace switches you can tune out certain parts of the output after you have compiled it.

In order to register a trace listener you need to add an entry to your application configuration file (or instansiate it directly in code). If you have used trace listeners before you should be fairly comfortable doing this.

ConsoleTraceListenerConfig

Once the trace listener is registered its business as usual with the tracing API, but if you look a little bit more closely you will notice that the Trace class has gotten some new static helper methods.

NewTraceMethods

I always thought that the Write(…) and WriteLine(…) methods were a little bit funny in the context of trace listeners like the event log trace listener where you don’t really have the concept of a sequential log file, rather distinct events. It looks like someone on the BCL team had the same idea and decided to make some more useful methods like TraceError(…), TraceInformation(…) and TraceWarning(…). Here I am using TraceInformation(…) in a simple factorising routine.

FactorizeMethod

The beautiful thing about these new trace methods is that they actually spit out a little bit more information than normal – we’ll see more on that in a future post, but for now – here is what the output from the complete program looks like.

ConsoleTraceListenerOutput

Pretty neat eh? Of course, quite often you don’t really see the console on which your code is running so you need to log information to a file, but even if you do that the above format isn’t necessarily the best for import into tools like Excel for analysis. For that the BCL team provided the DelimitedListTraceListener.

DelimitedListTraceListener

The DelimitedListTraceListener can be used to produce a file on disk which can be easily imported into Excel. The first thing you need to do is change the type in application configuration file to “System.Diagnostics.DelimitedListTraceListener” and add an initializeData attribute specifiying the name of the log file to emit and you are away. By default it uses a semi-colon to delimit the data which happens to be supported by Excel - but isn’t as common as comments in log data.

DelimitedExcelImport

Any text is also quoted so there isn’t much chance of poor column handling. Now, the issue with two dimensional delimited files is that its hard to emit complex hierarchical information. This is where the XmlWriterTraceListener comes in handy.

XmlWriterTraceListener

A lot of people want to emit XML files from their diagnostic system, however, in my experience they then to suffer in terms of readability and filesize at write time, and processing at analysis time. Despite this Microsoft did include one in .NET 2.0 – its type name is “System.Diagnostics.XmlWriterTraceListener” – but there are a few things you need to know about its output.

XmlWriterTraceListenerOutput

Looking at this output, there are a few things you should be asking yourself:

  • Where am I going to buy a bigger hard disk?
  • Why isn’t this XML well-formed?
  • What is “E2ETraceEvent”?
  • Why is the sky blue?

Well, as a matter of fact the sky isn’t always blue, it often comes in other colours such as red, pink and orange to understand this and more you should check out this fabulous resource.

Where am I going to buy a bigger hard disk? Obviously XML is a little bit more wordy than your typical text output, and you need to factor that in. While many production systems now have enough disk capacity to turn high level logging on and never run out of disk storage for the lifetime of the application that simply isn’t going to be true if you start throwing things out in XML format.

Why isn’t this XML well-formed? Good question, I did think about that for fifteen seconds, but if I were to make a guess I’d say that its probably for performance. The absense of a root element makes it easier to append information without walking back through the output stream (costly) and virtually ensures that you don’t actually need to treat the XML output as an XML memory structure when writing the data – a quick look at the code with Reflector reveals this to be the case.

The draw back is that you can’t just load it with an XmlReader and emit some nicely formatted output from it, although if you think about the next question that may not be so much of an issue.

What is “E2ETraceEvent”? I was really curious about this too so I decided to do a bit of a search on Google for it. The one and only hit I found was a link to this page which is part of the WinFX documentation for Indigo. It reveals that as part of Indigo there will be a Trace Viewer Tool. By the looks of it, it will be used to diagnose distributed applications where events are occuring on multiple machines – which would explain why the default output includes the computer name.

So in summary, there have been lots of incremental improvements in the System.Diagnostics namespace, please don’t over look them just because some other features are a bit more sexy and have more razzle dazzle (razzle dazzle should be written more in blog entries) – in fact, I haven’t even scratched the surface, I still have to cover off the correlation manager and filters! Stay tuned for a future post.

P.S. You can download the code from this demo here at Project Distributor.