Automate Exception Logging
You can automate exception logging with one line of client code, control it through an App.config file without recompiling, and use custom publishers to craft cool logging tools.
- By Craig Utley
- June 1, 2004
Technology Toolbox: C#, SQL Server 2000, XML
You probably perform the same development tasks repeatedlysome simple, some complex. Microsoft is creating a series of components called application blocks to help you implement best practices based on Microsoft's evaluation of a number of production applications. These best practices are often based on design patterns, something the Java world has been doing for quite a while.
Application blocks represent an interesting departure from the way Microsoft has distributed tools in the past. They come as Visual Studio .NET projects in both C# and VB.NET, so you get the full source code. They also come uncompiled, so you must open the project and compile it before you use them. Lastly, they tend to include thorough documentation.
A good example of a repetitive developer task is logging exceptions. You must catch exceptions when they're thrown, because you want your application to recover gracefully. However, you should log these exceptions also so you can examine them later and fix whatever is causing them.
Microsoft built the Exception Management Application Block (EMAB) to help you log exceptions with a single line of code. You can turn logging on or off in the config file, so you don't have to recompile your application. You can modify parameters of the logging in the config file, and you can write your own publishers that let you publish anywhere, including in text files, e-mail, and databases.
You can download EMAB from Microsoft. Install ExceptionManagementApplicationBlock.msi, creating a program group you can use to open the projects to compile them. Click on Start | All Programs, and you'll see Microsoft Application Blocks for .NET. Expand that and you'll see Exception Management, then a link to the source code in C# and VB.NET, plus a link for the documentation. Expanding the Source Code node for one of the languages provides a direct link to the Exception Management Application Block project. The project loads in Visual Studio .NET when you open this. You must convert the project if you have VS.NET 2003, but it's a simple process.
Open EMAB's source code, which contains two projects: an Exception Management class library and an Exception Management Interfaces class library. Compile both projects and begin using EMAB in your applications. Make sure you have administrative privileges on your computer so you can build and modify the project. If you don't, you need to change the security permissions in the directory in which you installed EMAB.
Start using EMAB by creating a new Windows application called csEMABClient. Add a button to the form and a reference to EMAB by right-clicking on the References node in Solution Explorer and choosing Add Reference. Select the Projects tab on the Add Reference dialog. Click on the Browse button and begin the long navigation to the location of the assemblies you compiled a few moments ago when you built the solution. They should be in C:\Program Files\Microsoft Application Blocks for .NET\Exception Management\Code\CS\Microsoft.ApplicationBlocks.ExceptionManagement\bin\Debug. Choose Microsoft.ApplicationBlocks.ExceptionManagement.dll.
Start Coding With EMAB
Set the reference to EMAB and add this line of C# code to the top of Form1.cs:
using Microsoft.
ApplicationBlocks.
ExceptionManagement;
Then add this code to the button's Click event handler:
private void button1
Click(object sender,
System.EventArgs e)
{
int x,y=0;
try
{
x=2/y;
}
catch (Exception ex)
{
ExceptionManager.Publish(ex);
}
}
Start with the variable y set to zero so you'll get an error if you try to divide two by zero. EMAB can catch the exception because you have this code in a try...catch construct. You didn't create an instance of the ExceptionManager class before calling the Publish function because the Publish function of the ExceptionManager class is static, like all the ExceptionManager class methods. Verify that EMAB can publish the exception for you by running the application and clicking on the Publish Exception button.
It might look as though nothing happened, so open the Event Viewer and look at the Application log. The first entry in the log will be an error from your application, containing a wealth of information, starting with identifying the exception and the procedure it occurred in (see Figure 1). You're running in Debug mode, so you can find the line number where the error occurred in the Stack Trace Information section.
EMAB publishes to the Application log in the event logs by default. You can modify the location or even turn off logging without recompiling the app. You can control EMAB by using App.config file settings. Simply modify the App.config file so you can send parameters to EMAB without modifying your application. See how this works by adding an App.config file to your project. Right-click on the project, choose Add | Add New Item, then scroll down to Application Configuration. This adds an App.config file to your project and opens it in the editor, showing you the basics of this XML file. App.config gets copied into the bin directory as the name of your executable plus .config. In this case, the file will be csEMABclient.exe.config.
The first thing you need to do is let App.config know about EMAB. You can do so in this XML code's <configSections> node:
<?xml version="1.0"
encoding="utf-8" ?>
<configuration>
<configSections>
<section name="exceptionManagement" type=
"Microsoft.
ApplicationBlocks.
ExceptionManagement.
ExceptionManagerSection
Handler,
Microsoft.ApplicationBlocks.
ExceptionManagement"
/>
</configSections>
<exceptionManagement
mode="off" />
</configuration>
The <section> node must be all on one line in your App.config. You then can turn logging on and off using the mode attribute on the <exceptionManagement> element.
You can stop EMAB from publishing by setting the mode attribute to "off." Now run the application and click on the Publish Exception button to your heart's content. You'll see that nothing new is being added to the Application log.
You also can change the log that receives messages. Simply add a <publisher> node and set some attributes (see Listing 1). EMAB still publishes to the Application log if the new log you specify doesn't exist. However, you could create the new log through VS.NET programmatically in your application. You need admin permissions to create a new log, so you might have to create an application that runs with administrative privileges if you want a custom log. The applicationname attribute lets you change the name of the application that's logged in the event logs.
The mode attribute is "on" in the <exceptionManagement> node of the previous example. You also can have a mode attribute for the <publisher> element. An <exceptionManagement> section can have multiple publishers defined for it; you can turn individual publishers on and off as needed.
Create a Custom Publisher
EMAB publishes to the event logs by default, but it includes an interface that lets you write your own custom publishers, enabling you to record exceptions any way you wish. You can publish to text files, send e-mails, send messages through MSMQ, or publish to a database. EMAB uses reflection to load custom publishers, so you can deliver a custom publisher and use it without having to recompile the application.
This example publishes to a SQL Server database named ExceptionLog. The database contains a table named AppException. You create the table in SQL:
CREATE TABLE [dbo]
[AppException] (
ExcID [int] IDENTITY (1, 1)
NOT NULL,
ExcMessage [nvarchar] (255),
ExcSource [nvarchar] (255),
ExcStackTrace [nvarchar]
(255),
ExcTargetSite [nvarchar]
(255),
ExcAddInfo [text]
) ON [PRIMARY] TEXTIMAGE_ON
[PRIMARY]
GO
The field size of 255 might be insufficient to hold all the data for some of your fields, but it works fine for this example. You can increase the metrics for the field size and number of fields in your own apps.
Next, create a new class library project called csEMABCustomPub. Rename the class file to csCustomPub.cs, and add a reference to the EMAB interface. Right-click on the References node in Project Explorer, and add a reference to Microsoft.ApplicationBlocks.ExceptionManagement.Interfaces.dll (found in the same path as the DLL mentioned earlier). This adds the reference to the EMAB Interface assembly.
Now add a few using statements to your project. You'll be using ADO.NET and the StringBuilder class, so your using statements in C# will look like this:
using System;
using
System.Collections.
Specialized;
using
Microsoft.
ApplicationBlocks.
ExceptionManagement;
using System.Text;
using System.Data.SqlClient;
Next, create a class that inherits from the IExceptionPublisher interface:
public class ExceptionPublisher
: IExceptionPublisher
Add some variables that you can override later, and create the Publish method, which accepts the exception and two NameValueCollections. The first NameValueCollection holds additional information you loop through and adds it to a StringBuilder. Now take various properties of the exception and add those to the database, along with the additional information. You've created your custom publisher (see Listing 2).
You can use this custom publisher in your original client by adding a reference to your csEMABCustomPub.dll assembly into your client application, then modifying App.config. The only thing you change in App.config is the <publisher> entity. Tell EMAB the name of the assembly and the type of publisher to use (see Listing 3). Make these changes to App.config, run the application again, and examine the output in SQL Server (see Figure 2).
You can modify custom publishers, again using the App.config file. One of the parameters passed into the Publish method is a NameValueCollection of configuration settings. You can use this parameter to change the name of the server, database, and table being used in the custom publisher you just created (see Listing 4). You add code to your custom publisher that checks the App.config file to see if certain default values have been overridden.
Next, you must modify the App.config file to include values for anything you want to change (see Listing 5). The final code for your custom publisher interacts with App.config (see Listing 6).
Strategize Exception Management
You can now log exceptions with EMABso it's time to integrate that logging into your overall exception management strategy. Start by deciding whether you want to log handled exceptions. You probably don't need to log the simple, common errors. For example, you might have code that opens an existing file or creates a new one if the file doesn't exist already. I wouldn't trap the "file not found" error.
A more serious issue arises if a database is unreachable, and you might want to log this error, even if your app handles it well. Put the Publish method in particular catch blocks so you can log serious errors while skipping routine problems. Alternatively, you can log everything and turn logging on and off in the App.config file.
Exceptions are passed to EMAB as .NET exceptions, giving you access to both their Message properties and InnerException properties. You can log both values in one line or in two separate onesEMAB doesn't care.
My sample code always uses EMAB in a catch block after you catch an exception. I recommend adding a generic catch in Main() for logging all unhandled exceptions. These represent errors you didn't anticipate and therefore didn't guard against with generic error handling in particular procedures.
EMAB handles exceptions in custom publishers intelligently. Say you create a custom publisher that later throws an exception. EMAB simply publishes the exception with the default publisher. EMAB also puts errors that crop up while creating and testing a custom publisher in the Application log, which aids debugging.
Finally, remember that EMAB and the other application blocks provide full source code, so you can study the code and modify it as needed. For example, you can change EMAB's default format this way.
The Exception Management Application Block helps you automate the task of logging exceptions in your code. The client can log exceptions with one line of code, and you can control the logging through the App.config file, which means you don't have to recompile your app to turn logging on and off or modify where exceptions are sent. You can create custom publishers, enhancing EMAB's usefulness and letting you create robust logging tools developers can use and control easily. Microsoft's push to provide tools that focus on automating repetitive tasks is a welcome addition to the .NET programming world.