Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tracing Code: Part 1


Tracing Code: Part 1

The .NET framework library has classes that allow you to add diagnostic messages to your code. These classes can be invaluable, but they can also provide more problems in your code. In this article, and the few that will follow it, I will explain how these classes work, how to use them, and the problems that these classes can cause.

Diagnostic messages are useful for reporting intermediate results so that you can determine whether your algorithm is working. They are also useful to indicate which methods are being executed, giving you an idea of code coverage-that is, how often, if at all, a method is executed-and you can determine whether your decision making code is working correctly. All of this is useful when you are diagnosing a fault, but this information is of no use to the end user who will use your retail build.

The diagnostics classes are contained in the system.dll assembly and naturally are part of the System::Diagnostics namespace. The main classes are described in the following table:

System::Diagnostic Class Description
Debug, Trace Used to provide diagnostic messages and perform assertions.
EventLog Read and write messages to the NT event log.
PerformanceCounter, PerformanceCounterCategory Provide diagnostic information for the NT Performance Monitor.
StackFrame, StackTrace Provide information about the current call stack.
Switch Base class used to read the application’s configuration file.
TraceListener Base class used for all ‘listener’ classes that handle messages generated by the Trace and Debug classes.

The EventLog class is great for reading the NT event log. It is lousy for writing events because it puts the responsibility of localization on the code that generates the event (do you really know who will read your messages?), which works against the design of the Win32 event log API that puts this responsibility on the code that reads the event log. If you want to generate event log messages call the Win32 function ::ReportEvent through Platform Invoke.

The PerformanceCounter and PerformanceCounterCategory classes allow you to generate performance data that can be viewed with the Performance Monitor. Anyone who has written perfmon code for Win32 will love these classes because they make the generation of this data so simple. I just wish the developer who created these classes could have used his talents on the event log generating code also, we then would not have the white elephant that is the EventLog class.

The StackTrace class allows you to get information about the current call stack. You get information about the current method, the position in that method, and even the memory location of the JIT-compiled code. There is a bug in this class that makes it show one more stack frame than actually exists, so the assert dialogs shown by Trace and Debug do not give the stack location.

Trace and Debug are classes used to generate trace messages and perform assertions (that will generate trace messages when the assertion fails). These trace messages are passed to a collection of TraceListener objects maintained by the process. These listener object decide what will happen to the message: The framework has classes that will report the message as an event log message, a message to the system debug stream, a line in a text file, or a message on a modal dialog.

By default, you will get an instance of the DefaultTraceListener class in the listeners collection, but you can change this either through code or through the application's configuration file. You can add or remove listener objects. The default listener will show failed assertions through a modal dialog (this can be configured) and trace messages will be directed through the Win32 ::OutputDebugString() function. As I will explain in an upcoming article, there is a danger associated with allowing failed assertions to be shown in retail builds (do you really want your customers to know that you suspected there was a bug in your code and didn't fix it?) and there is a hidden danger in using ::OutputDebugString().

The methods on the Debug and Trace classes are marked with the [Conditional] attribute, which means that if an appropriate compiler symbol is not defined, the compiler will ignore calls to these methods. Although this works fine for C#, it does not work with the C++ compiler. Again, I will leave a more detailed description for the next article. ::OutputDebugString() essentially couples your code to the code that reads the debug stream that can be harmful. As a consequence, Debug and Trace have WriteIf() and WriteLineIf(), which allow you to provide a runtime check to determine whether the message will be generated. One way that you can turn on diagnostics at run time is through a switch in the application's configuration file, and your code can get information about these switches with a class derived from Switch.

I have given a basic description of the main classes in the System::Diagnostics namespace, and in the next few articles, I will go into more details about how they work and point out the problems that occur when using these classes.


Richard Grimes speaks at conferences and writes extensively on .NET, COM, and COM+. He is the author of Developing Applications with Visual Studio .NET (Addison-Wesley, 2002). If you have comments about this topic, Richard can be reached at [email protected]. For questions regarding your newsletter subscription, please contact [email protected]. To subscribe, visit http://www.wd-mag.com/newsletters/.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.