| Details | ![]() |
| QuickDocId | 275 |
| Written by | Imar Spaanjaars |
| Posted | 04/16/2004 01:33 |
| Modified | 12/07/2006 17:25 |
| Reviewed | 12/07/2006 17:25 |
| Page views | 80956 |
| Listened to | Summer's Gone by Placebo (Track 10 from the album: Without You I'm Nothing) |
Are you looking to hire an experienced software developer or .NET consultant? Then get in touch with me through my company's web site at devierkoeden.com
Found an interesting article on this site? Got inspired by something you read here? Then consider making a donation with PayPal.
Let's face it. We're not living in a perfect world. I am not a perfect programmer, and the same probably applies to you (otherwise you would be stinkin' rich, laying on the beach somewhere drinking a Bacardi and Coke, instead of reading this article).
Because we aren't perfect, we know we are going to run into errors in the
applications we write sooner or later. This article will explain how you
can catch these errors in your ASP.NET applications and log them to the
Windows Event log, so it's easy to review them later. The article focuses
on ASP.NET, but the principle applies to other .NET applications as well.
In this article, I am going to use Visual Studio .NET 2003, so it's handy if you have that to your availability. Visual Studio .NET 2002 will do as well, and you can even follow along if you program in Notepad and use the command line compilers.
I'll be using C# as the main language, but you could easily write the code in Visual Basic .NET.
With the arrival of IDEs like Visual Studio .NET and smart compilers, you can catch quite a lot of errors at design time. Syntax errors, undeclared variables, unsafe casts etc can all be caught by the compiler. So, some people believe that if they compile without getting an error or a warning from the compiler, their application is good and bug-free. Unfortunately, this is not true. Even though the program is free of syntax errors, you can still run into design mistakes or run-time errors. Important files could be missing, required fields are not filled in correctly, people break the interface of a public Web Service you were using and so on. These are all examples of errors that you cannot handle at design-time. You must handle them at run-time.
If these errors occur, you have to be sure that you get detailed information about them. Your user should never be bothered with detailed error information about call stacks and other scary technical jargon. Instead, you should present them with a friendly error message that explains in plain English what went wrong and that you were notified about the error and are now working very hard to fix it. You could also offer them an alternative to continue browsing your site, by providing them a link back to your home page for example. To find out how you can configure your application, be sure to read this article. It explains how to modify the Web.Config file and your Global class to catch errors and send an e-mail to the administrator of the site, informing him or her about the error, accompanied by a detailed error message.
Sending an e-mail is good because it will alert the right people right after the error occurred. However, e-mails tend to get lost, or popped at the wrong computer so you can't access them from your development machine, or the ones who received the e-mail aren't responsible for fixing the error.
So what would be another logical place to log the error? Right on the server where the error occurred, in the Windows Event log. Writing to the event log used to be problematic, but the .NET Framework has a few handy classes available that make writing to the log a breeze. In the remainder of this article I will demonstrate how you can catch your errors and log them to the Windows Event Log.
With early beta releases of the ASP.NET Framework, it was possible to create new Events Logs (besides Application, Security and System) and Event Sources at run-time. That was because ASP.NET was running under the System account which had full privileges, including writing to the registry, which is necessary to create Event Logs and Sources. However, with the final releases of the .NET Framework (1.0 and 1.1), this is no longer possible. One way to fix this problem is to give the required permissions to the ASPNET account. However, this is not very recommended. The ASPNET account is a least privileged account, and for security reasons, it's best to leave it that way. Besides, you do not really need to create the logs at run-time, as they are not likely to change that often. So, it's best to create the Event Log and Source at design or deployment time. The easiest way to do this is to use a Windows Forms application. It's easy to run such an application with administrative privileges (using Run As for example), so you can easily bypass the security restrictions.
Before I show you how to create this application, let's take a look first at what the Event Log and the Event Source are. If you know all about the Event Log and just want to know how to create your own, go ahead and skip to the section Creating Your Own Event Log.
The Event Logs on your computer are accessible through the Event Viewer which you can find under the Administrative Tools menu. On a normal installation, you have three default Event Logs: Application, Security and System. The Application log is used to record information from applications. If you take a look in the Application log, you'll see logs from applications you're probably familiar with, like Office installations, SQL Server, backup programs and so on.
The Security log is not used much by default; however you can enable thorough access logging so more details about user sign-ons, access checks etc are logged.
The System log is used to log events from Windows components, like driver or service failures.
If you look at these three logs, you probably think that the Application log is best for logging your custom errors. That's true, but there is even a better solution: the custom Event Log. I'll get to that in a bit.
The Event Source is usually the name of the application that logged the event, but this is not required. In this article, however, I'll stick to this recommendation and use the full address of my Web site as the name of the Event Source. This allows me to easily distinguish errors I am interested in from errors from other sources. Feel free to choose a different naming convention, though.
The following screen shot shows you the Event Viewer. You can see the custom Event Log, My Websites, in the right-hand pane and you can see that the events are logged under the source Imar.Spaanjaars.com, the name of the Web site that generated the event.

Figure 1 - The Event Viewer with the Custom Event Log visible
It's remarkably simple to create a new Event Log. All you need to do is call the static CreateEventSource method of the EventLog class that lives in the System.Diagnostics namespace. So, fire up Visual Studio .NET to create the application that will create the Event Log and Source. (The source code for this article includes the full source of the application, in case you want to try it out directly.)
| Control | (Name) | Text |
| Label 1 | lblEventLog | Event Log |
| Label 2 | lblEventSource | Event Source |
| Textbox 1 | txtEventLog | |
| Textbox 2 | txtEventSource | |
| Button 1 | btnCreateEventLog | Create Event Log |
private void btnCreateEventLog_Click(object sender, System.EventArgs e)
{
if (txtEventLog.Text.Length > 0 && txtEventSource.Text.Length > 0)
{
System.Diagnostics.EventLog.CreateEventSource(
txtEventSource.Text, txtEventLog.Text);
MessageBox.Show("Event Log and Source " +
"created successfully.");
}
else
{
MessageBox.Show("Please fill in both the " +
"Event Log and the Event Source.");
}
}
Creating a new Event Log and Source is easy, but writing to it is about as easy.
<customErrors mode="On"> <error statusCode="500" redirect="/InternalError.htm"/> </customErrors>
using System.Diagnostics;
protected void Application_Error(Object sender, EventArgs e)
{
// Log error to the Event Log
Exception myError = null;
if (HttpContext.Current.Server.GetLastError() != null)
{
string eventLog = "My Websites";
string eventSource = "www.MySite.Com";
string myErrorMessage = "";
myError = Server.GetLastError();
while (myError.InnerException != null)
{
myErrorMessage += "Message\r\n" +
myError.Message.ToString() + "\r\n\r\n";
myErrorMessage += "Source\r\n" +
myError.Source + "\r\n\r\n";
myErrorMessage += "Target site\r\n" +
myError.TargetSite.ToString() + "\r\n\r\n";
myErrorMessage += "Stack trace\r\n" +
myError.StackTrace + "\r\n\r\n";
myErrorMessage += "ToString()\r\n\r\n" +
myError.ToString();
// Assign the next InnerException
// to catch the details of that exception as well
myError = myError.InnerException;
}
// Make sure the Eventlog Exists
if(EventLog.SourceExists(eventSource))
{
// Create an EventLog instance and assign its source.
EventLog myLog = new EventLog(eventLog);
myLog.Source = eventSource;
// Write the error entry to the event log.
myLog.WriteEntry("An error occurred in the Web application "
+ eventSource + "\r\n\r\n" + myErrorMessage,
EventLogEntryType.Error);
}
}
}
private void Page_Load(object sender, System.EventArgs e)
{
throw new Exception("An error occurred in the " +
"Page_Load of the TestLogging page.");
}
For this little example, I explicitly threw a new error using the throw keyword. However, the logging mechanism I showed you will catch all errors that may occur in your code, including any unhandled exceptions. This will help tremendously in pinpointing and fixing the problem.
Notice that the code in the Application_Errorevent uses a loop to retrieve information about the InnerException. If you don't use the loop, you'll end up with a rather meaningless "System.Web.HttpUnhandledException" message, without all the nitty gritty details about your error.
Also, sometimes explicitly nested errors are created, by passing in a Exception (the Inner Exception) to the constructor of another Exception (the Outer Exception) before the Outer Exception is thrown. This allows programmers to add useful information about the error, while leaving the original error and message in tact.
Instead of looping through the exceptions, you can also call GetBaseException() to get at the inner most exception directly:
myError = Server.GetLastError().GetBaseException(); myErrorMessage += "Message\r\n" + myError.Message.ToString() + "\r\n\r\n"; myErrorMessage += "Source\r\n" + myError.Source + "\r\n\r\n"; myErrorMessage += "Target site\r\n" + myError.TargetSite.ToString() + "\r\n\r\n"; myErrorMessage += "Stack trace\r\n" + myError.StackTrace + "\r\n\r\n"; myErrorMessage += "ToString()\r\n\r\n" + myError.ToString();
The purpose of this article is to show you the general idea of logging to the Event Log. It's by no means a complete solution (although you can use the code directly to enable logging in relatively small applications). Here are some ideas to extend the concepts that were introduced in this article:
Much of what I have introduced in this article, has already been taken care of by Microsoft. In April 2002, Microsoft released the Exception Management Application Block for .NET, a complete solution including full source code for publishing your errors to different logs, including the Event Log, SQL Server and a custom log that you define (an XML / text file or a pager or mobile phone for example).
The Application Block may be a bit overwhelming at first, and difficult to install and configure if you don't read the documentation carefully. It's not always necessary or applicable to use the Exception Management Application Block. For smaller sites or applications, the logging I demonstrated in this article should be more than enough.
Additionally, you can take a look at ELMAH (Error Logging Modules & Handlers), an open source project that allows you to send exception messages by e-mail or store them in a database. It's easy to setup and can also be implemented in existing solutions without the need to recompile anything. You can check out the project on its GotDotNet workspace.
Wonder where to go next?
You can read existing comments below
or you can post a comment yourself on this article.
Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.
I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.
When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.
If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.
For more information about the Talk Back feature, check out this news item.
| QuickDocId | 275 |
| Full URL | http://imar.spaanjaars.com/275/logging-errors-to-the-event-log-in-aspnet-applications |
| Short cut | http://imar.spaanjaars.com/275/ |
| Written by | Imar Spaanjaars |
| Date Posted | 04/16/2004 01:33 |
| Date Last Updated | 12/07/2006 17:25 |
| Date Last Reviewed | 12/07/2006 17:25 |
| Listened to when writing | Summer's Gone by Placebo (Track 10 from the album: Without You I'm Nothing) |