C# Tutorials and offshore development in India
    Tutorials   Resources   Forum   Communities   Interview   Jobs   Projects   Offshore Development    
Silverlight Tutorials | Mentor | Code Converter | Articles | Code Factory | Computer Jokes | Members | Peer Appraisal | IT Companies | Bookmarks | Revenue Sharing |


Prizes & Awards
My Profile



Active Members
TodayLast 7 Days more...

New Feature: Community Sites: Create your own .NET community website and start earning from Google AdSense ! It's Free !




Trace Debugging in .Net


Posted Date: 31 May 2006    Resource Type: Articles    Category: .NET Framework
Author: Amod kumarMember Level: Silver    
Rating: Points: 10



Trace Debugging
Back in the bad old days of computer programming, before source-level debuggers and integrated development environments, about the only way to "see" inside your executing program was to add output messages in key places using Basic's PRINT statement or C's printf function. That worked reasonably well for console mode applications, but service and GUI applications required a little more work to create a log file on disk. Some programmers wrote code to pass debugging output to other systems via a serial or other communications port. Regardless of how we did it, we grumbled at the need to add these statements in conditional compilation blocks (if the language supported it), and to re-compile the program for debugging in order to enable tracing.
Along came source level debuggers and all kinds of fancy development technology, and the art of program tracing fell out of vogue. In the early 1990's, it was common to meet a programmer who'd never used tracing. It wasn't a lost art, but its use became much less common; source level debuggers and IDEs made it so much easier to break into a program and see what was happening. There are disadvantages to depending on a source debugger, though. The program has to be compiled with debug information, and it has to be running on a developer's machine in order to diagnose the problems. As Web applications became more prevalent, it became increasingly necessary to have some way to diagnose an application while it was running in the production environment. Re-enter tracing.
.NET Support for Tracing
The .NET Framework has an integrated tracing mechanism that allows you to add trace output statements to your program and then selectively enable those statements at runtime by setting values in the application's configuration file. The Framework allows you to define your own classes that collect the trace information and send it to whatever output device you choose. Two very similar classes make use of trace output:
· The Debug class is enabled when you compile with the DEBUG conditional enabled. In Visual Studio .NET, the DEBUG conditional is enabled by default when you compile a debug build.
· The TRACE conditional is enabled by default in both debug and release builds, and enables the use of tracing output through the Trace class.
In theory, you would use Debug output for messages that you only want to view during debugging--that is, during program development and never in production. You would use Trace output statements for messages that you might want to view after the program has been placed in production. In practice, I've found it much more convenient to ignore Debug and use only Trace output, reserving the Verbose trace level (described below) for debug-level messages.
Although the following discussion describes only the Trace class, the discussion applies equally to the Debug class unless otherwise noted. The process of adding trace statements to your program is called instrumentation. The Trace class defines six different output methods:
· Assert: Outputs the specified text (or the call stack if no text is specified) if the condition supplied in the first argument evaluates to false.
· Fail: Outputs the specified text (or the call stack if no text is specified). This method is typically used inside an error-handling code block. Write Outputs the specified text.
· WriteIf: Outputs the specified text if the condition supplied in the first argument evaluates to true. WriteLine Outputs the specified text and a carriage return.
· WriteLineIf Outputs the specified text and a carriage return, only if the condition supplied in the first argument evaluates to true.
The Assert and Fail methods not only output messages, but also pop up dialog boxes that display an error message and allow you to Abort the program, Retry the operation, or Ignore the error. You probably do not want to use Assert and Fail in programs that are supposed to run unattended.
Where Does The Trace Output Go?
The Trace class routes messages to listeners: classes that are designed to accept Trace messages and send them to the appropriate output device. The Trace.Listeners collection contains a list of the listeners that are registered with the system. Calling any of the Trace output methods will send a message to all of the registered listeners. A class called DebugTraceListener is automatically added to the Listeners collection, and routes messages to the OutputDebugString API function. If you want trace messages to be routed somewhere else (the console perhaps, or a log file), you have to create an instance of a TraceListener class and add it to the Listeners collection.
The .NET Framework defines a class, TextWriterTraceListener that will direct trace output to a pre-defined TextWriter or Stream, or to a named file. Another class, EventLogTraceListener will direct output to the system event log. If you want trace output directed to some other device, you will have to create your own class that inherits from TraceListener.
Trace Debugging
The .NET Framework defines a class, TextWriterTraceListener that will direct trace output to a pre-defined TextWriter or Stream, or to a named file. Another class, EventLogTraceListener will direct output to the system event log. If you want trace output directed to some other device, you will have to create your own class that inherits from TraceListener.
Using Trace
Using the Trace class is very simple. The class is located in the System.Diagnostics namespace, so you need to include a reference (using in C#, or Imports) to that namespace in your program. Inside your main program, create an instance of a TraceListener class, and add Trace output statements to your code. The program below provides a very simple example that outputs tracing information to a file called "traceout.txt".
using System;
using System.Diagnostics;
namespace tracecon_cs
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// create the listener and add it to the Listeners collection
TextWriterTraceListener tracer = new TextWriterTraceListener("traceout.txt");
try
{
Trace.Listeners.Add(tracer);
Trace.WriteLine("Starting program");
Trace.Indent();
FirstOperation(false);
SecondOperation(true);
Trace.Unindent();
Trace.WriteLine("Program complete");
}
finally
{
// Free unmanaged resources
tracer.Dispose();
}
}
static void FirstOperation(bool isGood)
{
Trace.WriteLine("First operation");
Trace.Indent();
try
{
Trace.WriteLineIf(isGood, "isGood is true!");
Trace.WriteLine("Detail goes here.");
}
finally
{
Trace.Unindent();
}
}
static void SecondOperation(bool isGood)
{
Trace.WriteLine("Second operation");
Trace.Indent();
try
{
Trace.WriteLineIf(isGood, "isGood is true!");
Trace.WriteLine("Detail goes here.");
}
finally
{
Trace.Unindent();
}
}
}
}
The program starts by creating a trace listener and adding it to the Listeners collection. It then outputs a message and indents the output. The FirstOperation and SecondOperation methods each output a message and also indent the output. They use the WriteLineIf method to output a conditional message and then un-indent the output before continuing.
The indentation methods in the Trace class are very handy ways to organize your output. The default indentation level is four spaces, but you can change that by setting the IndentSize property. You can also set the indentation level directly by setting IndentLevel. I used a try..finally block to ensure that the indentation level gets reset correctly at the end of each method, even if an exception occurs somewhere in the method. The small performance overhead is well worth the price when it comes time to reading trace output. A sample of the program's output is shown here:
Trace output from the sample program
Starting program
First operation
Detail goes here
Second operation
isGood is true!
Detail goes here
Program complete
Controlling Trace Output with Trace Switches
One of the nicest things about .NET Trace is the ability to enable or disable tracing by modifying the application configuration file. Whereas it's always been possible to write applications that selectively enable tracing, that infrastructure had to be built custom for each program. In contrast, the .NET Framework has such support built in. It's much more convenient than the most common method used in the past, which was to recompile the program with trace disabled or set to a different level. The mechanism used to accomplish this in .NET is the trace switch.
There are two parts to using trace switches to control trace output: he configuration file and the code that uses the configuration file information to control trace output. I'll consider each separately.
Using Trace Switches in Code
The .NET Framework defined two different kinds of trace switches: BooleanSwitch, which has a simple on or off value; and TraceSwitch, which can take on values of Off, Error, Error, Warning, and Verbose.
If you want to conditionally enable tracing, you must create a TraceSwitch or BooleanSwitch in your code and test its value. The switch's constructor code reads the relevant information from the configuration file and sets the switch's value appropriately. From there, your code can test the value of the switch to determine whether or not to output a trace message. The code below creates a BooleanSwitch that enables or disables trace output, and then tests the value of that switch.
// Create switch that controls message tracing
BooleanSwitch MessageTrace = new BooleanSwitch("MessageTrace", "Messaging Module");
// output message only if MessageTrace is enabled
Trace.WriteLineIf(MessageTrace.Enabled, "Got a message");
// output message only if MessageTrace is enabled
if (MessageTrace.Enabled)
Trace.WriteLine("Got a message");
The constructor call initializes the MessageTrace switch value from the corresponding section in the configuration file which is described below. Note that there are two ways to use the value of the switch in controlling trace output. The first way uses the Trace.WriteLineIf method to test the value and output a message if the value is true. The other way is with a standard conditional statement. There are good reasons for using both methods, which will be described below.
The TraceSwitch class gives you much more flexibility, because you can set the level of information that you want. In normal program operation, for example, you might want only error and warning messages to be output to the trace log. If you're trying to diagnose a problem, you would also include information and possibly even verbose messages. Or you might want to disable all trace output for any one of a variety of reasons.
The Level property holds a value that indicates the current trace level setting. This property can take on one of the values of the TraceLevel enumeration: Off, Error, Warning, Info, and Verbose. Note that these settings are arranged in increasing order of verbosity. A higher Level setting automatically enables all lower settings. That is, if the Level property is set to TraceLevel.Info, then the TraceInfo, TraceWarning, and TraceError properties are automatically set to true, and TraceVerbose is set to false.
The code below shows how to use a TraceSwitch to selectively enable certain trace messages.

// Create switch that controls program flow tracing
TraceSwitch ProgramFlowTrace = new TraceSwitch("ProgramTrace", "Program flow");
// Output verbose message only if verbose enabled
Trace.WriteLineIf(ProgramFlowTrace.TraceVerbose, "Program complete");
// Output verbose message only if verbose enabled
if (ProgramFlowTrace.TraceVerbose)
Trace.WriteLine("Starting program");
Again, the constructor initializes the TraceSwitch's value from the program configuration file.
If you put the above code in a program and tried to run it, you will find that no trace information is output. The reason is that the trace switches were not defined in the application configuration file. If the BooleanSwitch constructor cannot locate the switch configuration, the Enabled switch is set to false. Similarly, if no configuration exists for a TraceSwitch, the Level property is set to TraceLevel.Off, and the TraceError, TraceWarning, TraceInfo, and TraceVerbose properties are all set to false.







Responses


No responses found. Be the first to respond and make money from revenue sharing program.

Feedbacks      
Popular Tags   What are tags ?   Search Tags  
(No tags found.)

Post Feedback


This is a strictly moderated forum. Only approved messages will appear in the site. Please use 'Spell Check' in Google toolbar before you submit.
You must Sign In to post a response.
Next Resource: .NET Security -1
Previous Resource: Windows Genuine Advantage Validation Tool
Return to Discussion Resource Index
Post New Resource
Category: .NET Framework


Post resources and earn money!
 
Related Resources



dotNet Slackers   BizTalk Adaptors    Web Design


Contact Us    Privacy Policy    Terms Of Use