YOUR FEEDBACK
Three RIA Platforms Compared: Adobe Flex, Google Web Toolkit, and OpenLaszlo
NN wrote: Yeah you are right GWT is poor man's Flex. After using GWT on two...

SYS-CON.TV
TOP MICROSOFT .NET LINKS


Using Features of Visual Basic .NET to Trace Your Application
Tracing in Visual Basic 6

Digg This!

At one time or another, most applications have to determine when a certain subroutine or function is executed and inform the user when an important event or an error occurred. Over the years, clever developers created different methods for these kinds of notifications. At some point in time, just about every Visual Basic programmer has tried using a message box to show when a method or subroutine was called. While this technique might work well for debugging, it's highly error-prone. Because there are legitimate times when a message box should be shown to the user, the developer can't just comment out every call to MessageBox. Instead, he or she would comment out each call to MessageBox as the messages appear during a debugging or testing session. Leaving a message box in production code is almost too easy - it's very embarrassing to have your customer report a "bug" with a strange title and a message like "This code should never be called".

A similar method of tracing program execution involved calling the Stop statement to force the program to break into debug mode during development. Because the stop statement shouldn't appear in production code, it was easier to search for all instances of the statement and remove them. That is, as long as you remembered to perform the search-and-remove operation before releasing your code to production.

As developers struggled with the problems caused by forgetting to remove a message box or stop statement, they looked for methods to trace their program execution that were less error prone. Two of the most popular methods in Visual Basic 6 were to use the Debug object to write information to the Immediate Window in the debugger and to use the App object to write to either the Event Log or to a log file. For instance, if you were working with a record set named rstBooks and wanted to look at the value of a few of the cells, you may have put a call like the following into your code:

Debug.Print "ID: " & rstBooks![ID] & " Title: " & rstBooks![Title]

This caused a message with the ID and title to be displayed in the Immediate Window. While not as good as stepping through each line of code, it gave you as a developer a quick look into what your code was doing and when it would be necessary to slow down and step through each line of code.

When your application wasn't running in debug mode, all calls to Debug.Print were ignored, so you didn't need to worry about a user seeing one of your private debug messages. Unfortunately, this also meant that you couldn't use Debug.Print to capture additional information when an error occurred. To log information at runtime, you could use the application object to initiate logging and write to an application-specific file or the Event Log. The following code creates an entry in %SystemRoot%\VBEvents.log on Windows 95/98 or the Event Log on Windows NT, 2000, XP, or 2003:

App.LogEvent "Sample message in the Event Log"

To log the information to a file, you could use the App.StartLogging method to specify the file to write to and the mode. Typical code to write to an application-specific log file might look like:

App.StartLogging App.Path & "\MyLog.log", 2
App.LogEvent "Sample message in the log file"

While this works well for logging information at runtime, the calls to App.LogEvent are ignored when the user is running in debug mode. This restricts logging to the Event Log or a custom file to runtime only. In addition, all events in the Event Log have a source of "VBRuntime", making it difficult to determine which application created the log entry without opening and reading the details of the entry. In practice, most developers use a combination of the Debug and App objects to provide information while debugging and when an application was deployed into production.

Tracing in Visual Basic .NET
When you start to develop in Visual Basic .NET, you'll notice that App.LogEvent and Debug.Print are no longer supported. Instead, the equivalent functionality can be gained from calling methods on the Trace and Debug classes. Both the Trace and Debug classes provide shared methods for writing information. The methods are summarized in Table 1.

In addition to the methods summarized in Table 1, there are other methods on the Debug and Trace classes to control assertions, indenting, and error messages. A discussion of these methods is beyond the scope of this article. Using the default settings for Visual Studio .NET, the Debug class is only available in debug builds while the Trace class is available in both the debug and release builds of your application.

The descriptions in Table 1 state that information will be written to a trace listener. The System.Diagnostics namespace contains a class called Trace Listener. The TraceListener class is marked as MustInherit, so you can't create an instance of the class. The TraceListener class provides methods to store the message in a format defined by that trace listener. Because a call to Debug.Write or Trace.Write will send the message to all of the trace listeners that are active, you can register a trace listener for both the event log and an application-specific log file, and have the same message written to both places. This can reduce the complexity of the code when compared to similar code in Visual Basic 6.

Because the TraceListener class is marked as MustInherit, you must instantiate one of its derived classes to add it to the listeners collection. The .NET framework provides three different classes derived from TraceListener that handle the majority of debugging or tracing situations.

The DefaultTraceListener is automatically added to the listeners collection for both Debug and Trace. It will write any output to the OutputDebugStream and the Debug.Log method. If a debugger is attached to the process, the output from the DefaultTraceListener will show up in it, otherwise the output will be ignored.

There is also an EventLog TraceListener that provides a property for you to specify the event log in which to place the information (allowing you to create a different event log for each application) or an event source that can specify both a custom event log and the source name to use in that log, so you don't have long lists of events with the source name of "VBRuntime."

The final class derived from TraceListener is the TextWriter TraceListener class, which allows you to write to a file or a stream. The code in Listing 1 shows you how to create an instance of the TextWriterTraceListener class and write out a trace message to the console.

If one of the trace listener classes provided by the .NET framework doesn't meet your needs, you can create your own custom trace listener. The code in Listing 2 shows an example of how to do this. The class constructor uses reflection to determine the name of the executing assembly. It then appends .log to the file name and uses that to create a StreamWriter. If the file already exists, it will be appended to that, otherwise it will be created. Finally, the constructor writes an entry into the log file to show when the execution started.

The Write and WriteLine methods just pass the entry to the respective methods of the StreamWriter class. I chose to implement a Flush method to flush output to the file. The Close method first checks to see if we have already closed the file. If not, it will write an entry to show when tracing was stopped. The method then flushes the output to disk and closes the file. To include your custom trace listener in the listeners collection, you can add the following code to the Main method in Listing 1.

Dim customListener As New AppTracer
Trace.Listeners.Add(customListener)
Trace.WriteLine("Writes to console and file")
customListener.Close()

Of course, you could also write a trace listener that would log to other sources such as a database, message queue, XML file, or any other source that makes sense for your application.

Controlling Tracing
One of the major advantages that the Debug and Trace classes have over their Visual Basic 6 predecessors is that you can control whether or not messages are logged without having to recompile the code. One method of turning tracing on and off is to use a BooleanSwitch. BooleanSwitch is another class in the System.Diagnostics namespace. You can set the value using an entry in the application's configuration file (web.config for ASP .NET projects or app.config for other projects). To define a BooleanSwitch, add the following code to the application's configuration file:


<system.diagnostics>
   <switches>
      <add name="controlTracing" value="1" />
   </switches>
</system.diagnostics>

This will define a new switch named controlTracing to the switches collection. To use the BooleanSwitch you can create a shared variable of type BooleanSwitch as follows:

Private logToConsole As New BooleanSwitch _
("controlTracing", "Do trace messages go to the console")

The first parameter of the BooleanSwitch constructor must match the name in the configuration file. The second parameter is a description of the switch.

In your code, check the value of the BooleanSwitch to determine whether or not to create and add a trace listener to the listeners collection. The following code could be modified to only log entries to the console if the value of controlTracing is 1.


   If logToConsole.Enabled Then
      Dim consoleListener As New TextWriterTraceListener(Console.Out)
      Trace.Listeners.Add(consoleListener)
      Trace.WriteLine("Trace message")
   End If

If the value of controlTracing in TraceListeners.exe.config is changed to 0, neither message appears on the console.

Sometimes just turning on or off a trace listener is too granular. You'd like to have the ability to only log errors or to log everything. The .NET Framework supports this functionality through the use of an instance of the TraceSwitch class. To use a TraceSwitch, you need to define another switch in the configuration file. To create a new TraceSwitch named variableTracing, I would add the following code to the configuration file:

<add name="variableTracing" value="4" />

The possible values for the TraceSwitch are summarized in Table 2.

Each level includes all of the lower levels, so if you set the value to 2, all error and information messages will be sent to the listeners collection while information and verbose messages will be ignored. The code in Listing 3 shows the completed program with the modifications to use a trace switch to only verbose messages in the application log. By now, there should be a familiar pattern. The new code declares a private TraceSwitch variable named conditionalLogging. It then creates an instance of the EventLogTraceListener class and adds it to the Trace listeners collection. The events will have a source of "my EventLog." Then, use the WriteLineIf method and pass in the condition conditionalLogging.TraceVerbose to write out only the information if the value in the configuration file is set to 4. The entry that appears in the event log is shown in Figure 1.

Security
When dealing with application tracing in Visual Basic .NET, security can be a concern. The first kind of security of which you should be aware is Code Access Security (CAS) and the permissions that your application will need. To create a new event source, you have to be a member of the administrators group. This means that you need to either run your application as an administrator (bad idea) or create an installation program that will run as an administrator and add the event source. My code uses reflection to determine the name of the log file. When your code is running with partial trust, you'll need to make sure that you explicitly grant the assembly permission for reflection.

The other kind of security of which you need to be aware is application security. While you might be tempted to write out the value of your database connection string to a log file just to make sure that it's correct, you should also realize that this would provide a mischievous person easy access to it. In addition, any log has the potential to place sensitive information in a place that isn't under strict access control. You have to balance your need for information against the security concerns of your application and take appropriate steps such as setting the Access Control List (ACL) on your log file so that only trusted users can view it and only your application can write to it.

Conclusion
The built-in classes in the .NET Framework make it easier than ever to trace the execution of your program in a simple and standardized way. With a little work and imagination, you should be able to figure out how to trace information and store that information in a variety of locations.

About Scott Golightly
Scott Golightly is Microsoft regional director and senior principal consultant at Keane, Inc., in Salt Lake City. He has over 12 years of experience helping his clients design and build systems that meet their business needs. When Scott isn't working he enjoys fishing, camping, hiking, and spending time with his family.

MICROSOFT .NET LATEST STORIES
Peer Networking Series - A Closer Look at PNRP vs. Bonjour/ZeroConf
It seems as though whenever I bring up PNRP and its benefits, I am immediately inundated with a list of questions or comments indicating that Microsoft is re-inventing the wheel and that PNRP has already been implemented before in the form of ZeroConf and, more specifically, Apple's im
Microsoft, Unisys, Yahoo and Vista
Microsoft, which spent $6 billion on aQuantive and was chasing Yahoo for its ads before it came to a dead stop, has been supporting - as in helping write - legislation in New York and Connecticut that would regulate the data that companies like Yahoo and Google collect for targeted adv
AJAX World - Xceed Launches Microsoft Silverlight 2 Control
Xceed launched Xceed Upload for Silverlight, the commercial offering in support of Microsoft's promising new Silverlight technology. The product is available now for purchase or as a fully functional 45-day trial on Xceed's website. Xceed Upload for Silverlight lets developers add uplo
Microsoft To Keynote 4th International Virtualization Conference & Expo
Mike Neil is general manager for virtualization strategy in the Windows Server Division at Microsoft. Mike is focused on the delivery of the Windows virtualization technology, including Windows Server 2008 Hyper-V, Microsoft Hyper-V Server and Virtual PC 2007. Mike also directs the tec
Microsoft Virtualization Takes Management Cross-Platform
Microsoft is making System Center, its central management scheme, natively manage Linux, Unix and VMware virtual servers. The widgetry has always been a Windows-only affair, but now there are betas available showing off Microsoft's cross-platform prowess, important to Microsoft's place
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON FEATURED WHITEPAPERS

ADS BY GOOGLE
BREAKING NEWS FROM THE WIRES
Open-E Data Storage Server Solution Empowers Nor-Tech's Robust Voyageur(TM) Storage Server
Open-E, Inc., a leading developer of innovative storage management software, announced today