traceHelper: Multi-level tracing to OutputDebugString and file

The third and final (for now) support class I wish to describe is called traceHelper, as the name suggests this class helps you to include tracing capabilities in your applications. It allows you to use a multi-level trace system where you at run-time can control how much of the trace information is outputted.

In its simplest usage this class is simply a wrapper around System.Diagnostics.Trace, but is can also be used to trace to file while controlling the amount of trace that is written to the log (using the traceLevel feature).

Please note that this class has a dependency on the configurationHelper class, which is described and can be downloaded here. If you wish to use some other configuration tool you will have to modify the code!

 

Sample Usage

void SomeMethod(int maxRows)
{
traceHelper.WriteLine(3, "SomeMethod: Entry");

if(maxRows < 1)
{
traceHelper.WriteLine(2, "SomeMethod: Warning: maxRows was <1, defaulting to 1");
maxRows = 1;
}

try
{

        // do something
}
catch(Exception ex)
{
traceHelper.WriteLine(1, "SomeMethod: Error retrieving data from database: " + ex.ToString());
throw;
}
}

Using traceLevels

Trace levels are positive numbers with no restriction to any hard-coded values, use whatever you like. However, I always try to use the following guidelines for trace levels:

  • 1 - Errors: Used in catch-blocks and before returning error codes to callers.
  • 2 - Warnings: I have to admit I don't use this much, but when needed it's there.
  • 3 - Information: Interesting stuff that may help to understand the flow of the application when "debugging" in a production environment. Examples are: high-level method entry/exit and useful data which can be used to understand how the application executes.
  • 5 - Very Detailed Information: Things that will not be interesting to other people than the developer of the specific code. Examples are: method execution times (using timerHelper), chosen case-statement in a switch and low-level method entry/exit.

 

Controlling Trace Output

traceHelper will always trace using System.Diagnostics.Trace (which ultimately calls OutputDebugString) and it can optionally also log to a file. You can specify the path to the log file as well as the base filename, but traceHelper will  append the date and time (formatted as yyyyMMddTHHmmss) along with the process id of the tracing application. I always use DebugView from sysinternals.com to view trace output.

You may control the maximum size of each trace file as well as the maximum total trace size (sum of all trace files), when the max size of a single trace file is reached a new file is created. The max total trace size is useful to ensure that the log files don't fill the disk.

During the development phase of a project there is an inconvenience related to the max total trace size... Checking and removal of old trace files is only performed a trace file reaches max size. This means that when you during development (and test) constantly restart your application you will always get a new trace file and the max size is never reached. As a result you may have 100 0.5 MB files even though max total size is 20 MB, but as soon as a single file reaches the 1 MB limit trace files will be removed to ensure that only 20 MB is used in total. However, in a production environment this should not be a problem as you don't restart the application all the time.

 

Configuration for traceHelper

Below is a sample config-file (to be parsed by configurationHelper) which controls some of the settings for traceHelper.

<?xml version="1.0" encoding="utf-8"?>
<configurationHelper>
<appSettings>
<appSetting name="traceHelper.TraceEnabled" value="true" />
<appSetting name="traceHelper.TraceLevel" value="3" />
<appSetting name="traceHelper.File.Enabled" value="true" />
<appSetting name="traceHelper.File.Filename" value="MyApplication" />
<appSetting name="traceHelper.File.Path" value="C:\Temp\" />
<appSetting name="traceHelper.File.MaxFileSizeInMb" value="5" />
<appSetting name="traceHelper.File.MaxTotalFileSizeInMb" value="20" />
</appSettings>
</configurationHelper>

Conclusion

I find this class very useful (hence sharing it with you) as I can add any amount of tracing to my application and then turn everything off but the essential stuff, and if I need more information I can turn it on at any time I choose. But what makes it really useful is the ability to also log to file, that way you can go back a few hours or days and see what caused a problem without having to try to reproduce it.

When debugging in test or production systems I usually use DebugView to monitor the trace live on one machine and when an error occur I use the log files from the other machines to see what they were doing at the same time.

I hope you find this class as useful as I do.

traceHelper.cs