6.1. Easily Log Events
When something goes wrong in your application, the user is rarely in a position to fix the problem. Instead of showing a detailed message box, it's much more important to make sure all the details are recorded somewhere permanent, so you can examine them later to try to diagnose the problem. In previous versions of .NET, logging was straightforward but tedious. In VB 2005, life becomes much easier thanks to the My.Application.Log object.
6.1.1. How do I do that?
You can use the new My.Application.Log object to quickly write to an XML file, an ordinary text file, or the Windows event log.
To write a log message with My.Application.Log, you simply need to use the WriteEntry( ) method. You supply a string message as the first parameter, and (optionally) two more parameters. The second parameter is the event type, which indicates whether the message represents information, a warning, an error, and so on. The third parameter is an exception object, the details of which will also be copied into the log entry.
Note: When something bad happens in your application, you want an easy way to log it to a file or event log. Look no further than the My.Application.Log object.
To try this out, create and run the console application in Example 6-1, which writes a short string of text to the log.
Example 6-1. Simple logging
Module LogTest Sub Main( ) My.Application.Log.WriteEntry("This is a test!", _ TraceEventType.Information) End Sub End Module
Clearly, the logging code is extremely simplebut where are the log entries recorded? It all depends on the configuration of your application. .NET uses trace listeners, which are dedicated classes that listen to log messages and then copy them to another location (such as a file, event log, and so on). When you call the WriteEntry( ) method, the entry is written to the current set of trace listeners (which are exposed through the My.Application.TraceSource collection). By default, these listeners include the FileLogTraceListener, which writes to a user logfile. This file is stored under a user-specific directory (which is defined by the user's APPDATA environment variable) in a subdirectory of the form [CompanyName]\[ProductName]\[FileVersion], where CompanyName, ProductName, and FileVersion refer to the information defined in the application assembly. For example, if the Windows user JoeM runs the application LogTestApp, the logfile will be created in a directory such as c:\Documents and Settings\JoeM\Application Data\MyCompany\LogTestApp\22.214.171.124\LogTestApp.log.
Once you've found the right directory, you can open the logfile in Notepad to examine the text contents. You'll see the following information:
Note: To configure assembly information, double-click the My Project item in the Solution Explorer, select the Application tab, and then click the Assembly Information button.
Microsoft.VisualBasic.MyServices.Log.WindowsFormsSource Information 0 This is a test!
The number 0 represents the information log type. Subsequent entries append data to this logfile. Data is never removed (unless you delete the file by hand).
6.1.2. What about...
...logging to other locations? .NET includes a number of pre-built trace listeners that you can use. They include:
By default, every new Visual Basic application you create starts its life with two trace listeners: a DefaultTraceListener and a FileLogTraceListener. To add new trace listeners, you need to modify the application configuration file. In Visual Studio, you can double-click the app.config item in the Solution Explorer. Trace-listener information is specified in two subsections of the <system.diagnostics> section.
Warning: The logging configuration settings have changed with newer builds. For a version of the code that's updated to work with the latest build, download the samples from this book's web site.
In the <sharedListeners> subsection, you define the trace listeners you want to have the option of using, specify any related configuration properties, and assign a descriptive name. Here's an example that defines a new listener for writing XML data to a logfile:
Note: Remember, after the application is built, the app.config file is renamed to have the name of the application, plus the extension .config.
<sharedListeners> <add name="MyXmlLog" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\MyLog.xml" /> </sharedListeners>
In the <sources> subsection, you name the trace listeners you want to use, choosing from the <sharedListeners> list:
<source name="Microsoft.VisualBasic.MyServices.Log.WindowsFormsSource"> <listeners> <add name="Xml"/> </listeners> </source>
This separation between the <sharedListeners> section and the <sources> section allows you to quickly switch trace listeners on and off, without disturbing their configuration settings.
You can now re-run the application shown in Example 6-1. Now it will write the message to an XML file named MyLog.xml in the root C: directory. Here's what the contents look like (with the schema information removed for better readability):
<E2ETraceEvent> <System> <EventID>0</EventID> <Type>0</Type> <TimeCreated SystemTime="2004-07-26T16:14:04.7533392Z" /> <Source Name="Microsoft.VisualBasic.MyServices.Log.WindowsFormsSource" /> <Execution ProcessName="LogSample.vshost" Process Thread /> <Computer>FARIAMAT</Computer> </System> <ApplicationData> <System.Diagnostics> <Message>This is a test!</Message> <Severity>Information</Severity> </System.Diagnostics> </ApplicationData> </E2ETraceEvent>
Example 6-2 shows a complete configuration file example. It enables file tracing, event log tracing, and XML log tracing. Notice that the EventLogTraceListener is fine-tuned with a filter that ensures only error messages are logged.
Example 6-2. Logging data to three different trace listeners
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <!-- Enable all three trace listeners (from the <sharedListeners> section). --> <sources> <source name="Microsoft.VisualBasic.MyServices.Log.WindowsFormsSource" switchName="DefaultSwitch"> <listeners> <add name="FileLog"/> <add name="EventLog"/> <add name="Xml"/> </listeners> </source> </sources> <switches> <add name="DefaultSwitch" value="Information" /> </switches> <!-- Define three trace listeners that you might want to use. --> <sharedListeners> <add name="FileLog" type="System.Diagnostics.FileLogTraceListener" initializeData="FileLogWriter" delimiter=";" /> <add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="MyApplicationLog"> <filter type="System.Diagnostics.SeverityFilter" initializeData="Error" /> </add> <add name="Xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\SampleLog.xml" delimiter=";"/> </sharedListeners> </system.diagnostics> </configuration>
You can now use the same simple application to simultaneously write the ordinary logfile, an XML logfile, and an entry in the Windows event log named Application.
Unfortunately, there isn't any high-level .NET API for retrieving information from a log. If the log information is stored in a file, you can use the FileStream and StreamReader classes from the System.IO namespace to read the file one line at a time. If you've entered information in the Windows event log, you'll need to rely on the EventLog class, which you can find in the System.Diagnostics namespace.
Note: The event log is a list of messages stored by the operating system for a specific period of time. To view the event log, choose Event Viewer from the Administrative Tools section of the Control Panel.
6.1.3. Where can I learn more?
For more information, look up the following classes in the MSDN help: DefaultTraceListener, FileLogTraceListener, EventLogTraceListener, and XmlWriterTraceListener.