Lesson 2: Using the Debug and Trace Classes

Lesson 2: Using the Debug and Trace Classes

The Debug and Trace classes allow you to produce and log informative messages about your application s conditions without having to interrupt application execution. In this lesson, you will learn how to use the Debug and Trace classes, how to add Trace Listeners and Trace switches, and how to configure Trace switches in a program that is already compiled and released.

After this lesson, you will be able to

  • Explain how to display error messages using the Debug and Trace classes

  • Describe how to create Trace Listeners and log Trace output

  • Describe how to create and use Trace switches

  • Explain how to configure Trace switches in the application s .config file

Estimated lesson time: 45 minutes

When debugging simple applications, debugging tasks more complex than examining your code line-by-line, as described in the previous lesson, are usually unneeded. Complex applications are another matter, however. Large programs can have hundreds of thousands of lines of code. When an error occurs, it might be impossible to uncover logical errors by simply stepping through code and examining application variables. The Debug class is a way for you to create and log informative messages about program conditions while your application executes. The Trace class allows you to create diagnostic instrumentation that can deliver informative messages about program conditions even after your application is compiled and released.

How Tracing Works

Trace and Debug are classes in the System.Diagnostics namespace that contain Shared (static) methods that allow you to test conditions at run time and log the results. Output from these methods is displayed in the Output window and can be viewed while debugging. The output also is sent to the Listeners collection. The Listeners collection contains a group of classes that can receive output from the Trace and Debug classes. Trace and Debug share the same Listeners collection, and all the Listeners in the collection receive the input from Trace and Debug. There are different kinds of Listeners, including some that write to text files and Trace Listeners, which write to event logs. After program execution, you can examine the Listener traces to identify errors in your application. Tracing is also useful in program optimization, which is discussed in Chapter 9.

The Trace and Debug classes are identical. They expose the same methods and properties and write output to the same set of Listeners. The only difference between Trace and Debug is that Trace statements are included by default when the program is compiled into a release build, whereas Debug statements are not. Thus, the Debug class is principally used for debugging in the development phase, while Trace can be used for testing and optimization after an application is compiled and released.

Writing Trace and Debug Output

You can write output to the Listeners collection by using the methods exposed by the Trace and Debug classes. These classes expose six methods for writing output, which are:

  • Write.

    Writes text to the Listeners collection unconditionally.

  • WriteLine.

    Writes text to the Listeners collection and follows the text with a carriage return.

  • WriteIf.

    Writes text to the Listeners collection if the specified Boolean expression is true.

  • WriteLineIf.

    Writes text and a carriage return to the Listeners collection if the specified Boolean expression is true.

  • Assert.

    Writes an assertion message to the Listeners collection if the specified Boolean expression is false. It also causes a message box to be displayed with the assertion message.

  • Fail.

    Creates an assertion that automatically fails without testing a condition. An assertion message is written to the Listeners collection, and a message box is displayed with the message.

The following code example demonstrates how to invoke these methods:

Visual Basic .NET

' Since Trace and Debug expose only static methods and properties, you ' do not need to create an instance of either class. ' Writes text to the Listeners collection. Trace.Write("Trace Message 1") ' Writes text and a carriage return to the Listeners collection. Trace.WriteLine("Trace Message 2") ' Writes text if the supplied expression is true Debug.WriteIf(X=Y, "X equals Y") ' Writes text and a carriage return if the supplied expression is true Debug.WriteLineIf(X=Y, "X equals Y") ' Writes output and displays a message box if the condition is false Trace.Assert(X=Y, "X does not equal Y!") ' Writes output and displays a message box unconditionally Debug.Fail("Drive B is no longer valid.")

Visual C#

// Since Trace and Debug expose only static methods and properties, you // do not need to create an instance of either class. // Writes text to the Listeners collection. Trace.Write("Trace Message 1"); // Writes text and a carriage return to the Listeners collection. Trace.WriteLine("Trace Message 2"); // Writes text if the supplied expression is true Debug.WriteIf(X==Y, "X equals Y"); // Writes text and a carriage return if the supplied expression is true Debug.WriteLineIf(X==Y, "X equals Y"); // Writes output and displays a message box if the condition is false Trace.Assert(X==Y, "X does not equal Y!"); // Writes output and displays a message box unconditionally Debug.Fail("Drive B is no longer valid.");

You can alter the indentation level of Trace messages as they are written to the Listeners collection by calling the Indent and Unindent methods, and by setting the IndentSize and IndentLevel properties. These methods and properties are useful for creating hierarchical displays of error messages. The IndentSize property gets or sets the number of spaces in a single indent, and IndentLevel gets or sets the number of indents currently being applied. The Indent method increases the IndentLevel by one, while the Unindent method decreases the IndentLevel by one.

To write output using Trace or Debug

  1. If necessary, set the indent level to the appropriate position by using the Indent and Unindent methods. For example:

    Visual Basic .NET

    ' Increases the IndentLevel by one Trace.Indent()

    Visual C#

    // Increases the IndentLevel by one Trace.Indent();

  2. Call one of the following methods to write output to the Listeners collection:

    • Call Write or WriteLine to write Trace output unconditionally.

    • Call WriteIf or WriteLineIf to test a condition and write output if the condition is true.

    • Call Fail to write Trace output unconditionally and display a message box.

    • Call Assert to test a condition, write output, and display a message box if the condition proves false.

The Listeners Collection

All output from the Trace and Debug classes is directed to the Listeners collection. The Listeners collection is a collection that organizes and exposes classes that are capable of receiving Trace output. Each member of the Listeners collection receives any and all output from the Trace and Debug classes. How that output is handled is then up to the individual listener.

The Listeners collection is initialized with one member, which is an instance of the DefaultTraceListener class. As the name implies, the DefaultTraceListener is created automatically and will receive Trace and Debug output even if no other listeners are attached. Trace output received by the DefaultTraceListener is directed to the debugger. It is through the DefaultTraceListener that Trace output is displayed in the Visual Studio Output window. If you want to log Trace messages to refer to them separate from the debugger, you must add at least one more listener. The .NET Framework base class library provides two classes that can log Trace output: the EventLogTraceListener class and the TextWriterTraceListener class. Both classes inherit from the MustInherit (abstract) class TraceListener.

Logging Trace Output to Text

The TextWriterTraceListener class writes its output as text, either to a Stream object or to a TextWriter object. For example, the Console.Out property is a TextWriter. Thus, you could create a TextWriterTraceListener that writes all its output to the Console window. Another use for Stream and TextWriter objects is writing to text files. To create a TextWriterTraceListener that writes Trace output to a text file, you must first create or open the file that will be used to record the output. Next you need to create an instance of the TextWriterTraceListener that specifies that file as its target. In addition, you need to add the TextWriterTraceListener to the Listeners collection. The following example demonstrates how to create a listener that logs Trace output to a text file:

Visual Basic .NET

' This line opens the specified file or creates it if it does not exist Dim myLog As New System.IO.FileStream("C:\myFile.txt", _ IO.FileMode.OpenOrCreate) ' Creates the new Trace Listener that specifies myLog as the target for ' output. Dim myListener As New TextWriterTraceListener(myLog) ' Adds myListener to the Listeners collection. Trace.Listeners.Add(myListener)

Visual C#

// This line opens the specified file or creates it if it does not // exist. Note that you must use a double slash in the string instead // of a single because the slash is an escape character in C# System.IO.FileStream myLog = new System.IO.FileStream("C:\\myFile.txt", System.IO.FileMode.OpenOrCreate); // Creates the new TraceListener that specifies myLog as the target for // output TextWriterTraceListener myListener = new TextWriterTraceListener(myLog); // Adds myListener to the Listeners collection Trace.Listeners.Add(myListener);

NOTE
If a file by the specified name already exists, opening the file with IO.FileMode.OpenOrCreate will overwrite any content present. If you want to add content to an existing file, specify IO.FileMode.Append when declaring your FileStream object.

Another overload of the TextWriterTraceListener constructor allows you to simply name the text file to be written to. Using this constructor, the text file will be created if it does not exist, and appended to if it does. A code example is shown here:

Visual Basic .NET

Dim myListener As New TextWriterTraceListener("C:\myFile.txt")

Visual C#

TextWriterTraceListener myListener = new    TextWriterTraceListener("C:\\myFile.txt");

When the code in either of these two samples executes, all output from the Trace and Debug classes is written to myListener. In order for them to be written to the file, however, you must flush the Trace buffer by calling the Flush method as follows:

Visual Basic .NET

Trace.Flush()

Visual C#

Trace.Flush();

Alternatively, you can set the Trace.AutoFlush property to true, as shown in the following example. This technique causes the buffer to be flushed after every write:

Visual Basic .NET

Trace.AutoFlush = True

Visual C#

Trace.AutoFlush = true;

To log Trace and Debug output to a text file

  1. Create an instance of a FileStream object that specifies the appropriate text file.

  2. Create an instance of a TextWriterTraceListener that specifies the new FileStream object as its target.

  3. Add the new listener to the Trace.Listeners collection.

  4. Set Trace.AutoFlush to true, or call Trace.Flush after making a write.

Logging Trace Output to an EventLog

You can use the EventLogTraceListener to log Trace output to an EventLog object. The method for doing this is essentially the same as logging to a text file. You create a new EventLog or specify an already existing log, create a new EventLogTraceListener, and add it to the Listeners collection. Trace output is then logged to the specified EventLog as EventLogEntry objects.

To log Trace and Debug output to an EventLog

  1. Declare an instance of an EventLog object and assign it to an existing event log or to a new event log.

    Visual Basic .NET

    ' Creates a new event log. "Debug Log" is the log's display name. Dim myLog As New EventLog("Debug Log")

    Visual C#

    // Creates a new event log. "Debug Log" is the log's display name. EventLog myLog = new EventLog("Debug Log");

  2. Set the Source property for the EventLog. If the Source property is not set, an error will result.

    Visual Basic .NET

    myLog.Source = "Trace Output"

    Visual C#

    myLog.Source = "Trace Output";

  3. Create a new instance of EventLogTraceWriter that specifies the new log as the target for Trace output.

    Visual Basic .NET

    Dim myListener As New EventLogTraceListener(myLog)

    Visual C#

    EventLogTraceListener myListener = new EventLogTraceListener(myLog);

  4. If necessary, set the Trace.AutoFlush property to true, or call Trace.Flush after each write.

Using Trace Switches

When debugging, you usually will want to receive all output from your Debug and Trace statements. After an application is compiled and released, however, it is more typical to enable tracing only in special cases. Trace switches are configurable switches used to display Trace statements. Trace switches can be configured within the application by altering the application configuration file after it has been compiled and distributed.

The .NET Framework base class library contains two kinds of Trace switches. Instances of the BooleanSwitch class return a Boolean value. Thus, like a toggle switch, they are either on or off. The TraceSwitch class allows users to set the level represented by the switch to one of five settings, depending on the kind of output the user wants to receive.

You create an instance of a BooleanSwitch or a TraceSwitch the same way as any other class. Both switches require two parameters in their constructor: a DisplayName, which is the name of the switch in the user interface, and a Description, which contains a short description of the switch. For example:

Visual Basic .NET

Dim myBooleanSwitch As New BooleanSwitch("Switch1", _  "Controls Data Tracing") Dim myTraceSwitch As New TraceSwitch("Switch2", _  "Controls Form1 Tracing")

Visual C#

BooleanSwitch myBooleanSwitch = new BooleanSwitch("Switch1",  "Controls Data Tracing"); TraceSwitch myTraceSwitch = new TraceSwitch("Switch2",  "Controls Form1 Tracing");

The TraceSwitch class has five settings that represent different levels of errors. These settings are exposed by the TraceSwitch.Level property. This property can be set to any of five values represented by the TraceLevel enumerator. The five values are as follows:

  • TraceLevel.Off.

    Represents a TraceSwitch that is inactive. The integer value is 0.

  • TraceLevel.Error.

    Represents brief error messages. The integer value is 1.

  • TraceLevel.Warning.

    Represents error messages and warnings. The integer value is 2.

  • TraceLevel.Info.

    Represents error messages, warnings, and short informative messages. The integer value is 3.

  • TraceLevel.Verbose.

    Represents error messages, warnings, and detailed descriptions of program execution. The integer value is 4.

Additionally, the TraceSwitch class exposes four read-only Boolean properties that represent the Trace levels. The Boolean properties are:

  • TraceSwitch.TraceError

  • TraceSwitch.TraceWarning

  • TraceSwitch.TraceInfo

  • TraceSwitch.TraceVerbose

These read-only properties correspond to Trace levels of the same names. When the TraceSwitch.Level property is set, these four properties are also set to the appropriate level. For example, if the TraceSwitch.Level property is set to TraceLevel.Info, the TraceSwitch.TraceInfo property will return true. Additionally, TraceSwitch.TraceError and TraceSwitch.TraceWarning also will return true. When a specified level is set, it and all lower levels return true.

Trace statements use Trace switches to test whether Trace output is needed. The Trace.WriteIf and Trace.WriteLineIf methods test a Trace switch to learn whether the switch is enabled or set to the appropriate Trace level. For example:

Visual Basic .NET

' This example assumes the existence of a BooleanSwitch object named ' myBooleanSwitch and a TraceSwitch object named myTraceSwitch Trace.WriteIf(myBooleanSwitch.Enabled = True, "Error.") Trace.WriteLineIf(myTraceSwitch.TraceInfo = True, _  "Type Mismatch Error")

Visual C#

// This example assumes the existence of a BooleanSwitch object named // myBooleanSwitch and a TraceSwitch object named myTraceSwitch Trace.WriteIf(myBooleanSwitch.Enabled == true, "Error"); Trace.WriteLineIf(myTraceSwitch.TraceInfo == true,  "Type Mismatch Error");

Note that there is no automatic hookup between Trace switches and Trace statements. It is up to you to create the connection by testing the switches in code. If you use the unconditional write methods, such as Trace.Write and Trace.WriteLine, Trace output will be written regardless of the status of any switches.

To create and use Trace switches

  1. Create an instance of either the BooleanSwitch class or the TraceSwitch class, as appropriate. You must supply the DisplayName parameter and the Description parameter.

  2. Test the status of the switches in code by using the Trace.WriteIf and Trace.WriteLineIf methods.

Configuring Trace Switches

Trace switches can be turned on and off after your application has been compiled and distributed. Trace switches are configured by manipulating the application s .config file, which is an XML file that contains information for the application. The .config file must be located in the same folder as the executable and must have the name (application name).exe.config. Not all applications have a .config file, so if you want to use Trace switches, you might need to create a .config file for your program. When your application executes code that creates a Trace switch, it checks the .config file for information about that switch. This file is examined once per switch. If you want to change any settings after a particular Trace switch has been created, you must stop the application, make changes to the .config file, and then restart the application.

When you create an instance of a Trace switch, one of the parameters you must supply is the DisplayName. This is the name used to configure the Trace switch in the .config file. When editing the .config file, you must specify not only the name of the switch, but also the value to which it is to be set. The value must be an integer. For BooleanSwitch objects, zero represents off, and any nonzero value represents on. For TraceSwitch objects, the values zero, one, two, three, and four correspond to TraceLevel.Off, TraceLevel.Error, TraceLevel.Warning, TraceLevel.Info, and TraceLevel.Verbose, respectively. Any value greater than 4 is treated as TraceLevel.Verbose.

To enable the end user to configure tracing when necessary, you should include extensive inline documentation in the .config file.

To create the .config file and configure Trace switches

  1. Create your Trace switches in code and give them appropriate DisplayName values.

  2. If your application does not have a .config file, create a new one as follows:

    • In Visual Basic .NET, choose Add New Item from the Project menu. From the Add New Item dialog box, choose Application Configuration File. The .config file opens.

    • In Visual C#, choose Add New Item from the Project menu. From the Add New Item Dialog box, choose Text File. Name the file app.config. The text editor opens. Type the following XML into the text editor:

      <?xml version="1.0" encoding="utf-8" ?> <configuration> </configuration>

  3. Between the <configuration> and </configuration> tags, add the appropriate XML to declare your Trace switches and set the values. The following code demonstrates how to add XML for switches named myBooleanSwitch and myTraceSwitch:

    <system.diagnostics> <switches> <add name="myBooleanSwitch" value="0" /> <add name="myTraceSwitch" value="3" /> </switches> </system.diagnostics>

    In this example, myBooleanSwitch is set to off, and myTraceSwitch is set to TraceLevel.Info.

  4. If you need to activate or deactivate any of your Trace switches, change the switch value as appropriate. For example, to activate myBooleanSwitch, you would change the XML element to read:

    <add name="myBooleanSwitch" value="1" />

    The rest of the XML remains unchanged.

  5. Add inline comments that document each switch and explain the different levels. Explicit documentation is crucial to helping your users understand how to use your application. The final file might look like this:

    <system.diagnostics> <switches> <!-- This switch controls tracing globally. If you want to receive Trace messages, set the value to a non-zero integer. To disable tracing, set this switch to zero --> <add name="myBooleanSwitch" value="0" /> <!-- This switch controls the level of information from Trace. For no information set the value to zero. Set the value to 1,2,3, or 4 for minimal, normal, detailed, or verbose messages respectively --> <add name="myTraceSwitch" value="3" /> </switches> </system.diagnostics>

Lesson Summary

  • The Debug and Trace classes allow you to display and log messages about application conditions while the program is executing. The Debug and Trace classes are identical. Both classes expose methods used to create Trace output.

  • Output from Trace and Debug statements is received by members of the Trace.Listeners collection, a collection of objects that are able to receive Trace output and process it. The three kinds of TraceListeners are

    • DefaultTraceListener

    • TextWriterTraceListener

    • EventLogTraceListener

  • Trace switches are used to configure Trace statements. BooleanSwitch objects are either on or off. TraceSwitch objects expose a TraceSwitch.Level property that is used to determine the verbosity of Trace statements.

  • You can configure Trace switches after the application is compiled by setting appropriate values in the application s .config file.



MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[.  .. ]0-316
MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[. .. ]0-316
ISBN: 735619263
EAN: N/A
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net