Logging Errors to the Event Log in ASP.NET Applications
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.
Prerequisites
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.
Errors? What Errors? I compiled the application and it looks fine!
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.
We Want More!
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.
First Things First
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 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
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
Creating Your Own Event Log
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.)
- Once you started Visual Studio, create a new Visual C# Windows Application. Name the application CreateEventLog.
- Drag two labels, two textboxes and a button from the Toolbox to the form and set their properties as follows:
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
Arrange the controls so they end up as in the following screen shot:
Figure 2 - The Sample Application - Double click the button, and add the following code for the btnCreateEventLog_Click handler:
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.");
}}
- Press F5 to start the application, type My Websites for the Event Log name and the URL of your site, like www.MySite.com as the Event Source and click the Create Event Log button.
- Open up the Event Viewer (close it first if you had it still open to refresh its contents) and you'll see your new Event Log as in the first screen shot of this article.
That was easy, wasn't it?
Writing to the Event Log
Creating a new Event Log and Source is easy, but writing to it is about as easy.
- First of all, make sure you followed the steps from the article How do I Handle Errors and Send an Error Notification from ASP.NET Applications? Make sure you changed at least the Web.Config file so it includes the customErrors node with its mode set to On:
<customErrors mode="On"> <error statusCode="500" redirect="/InternalError.htm"/> </customErrors>
- Next, open the Web application that you want to log errors for and open the Code Behind page for the Global class (Global.asax.cs, or Global.asax.vb if you're using VB.NET).
- Add the following using statement to the top of the Code Behind page:
using System.Diagnostics;
- Add the following code to the Application_Error event. (If you followed along with the previous article, and added code that e-mailed you the detailed error information, add the following code below the code already present for the event):
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);
} }}
Don't forget to replace the parts in bold with the names you have chosen for your Event Log and Source. - To test out the new logging feature of your site, add a new Web Form to your application and call it TestLogging.aspx.
- Open the Code Behind for the page, and add the following code that will explicitly generate an error to the Page_Load event:
private void Page_Load(object sender, System.EventArgs e) {
throw new Exception("An error occurred in the " +
"Page_Load of the TestLogging page.");}
- Save the page, compile your application and then open TestLogging.aspx in your browser. Instead of the usual error page, you should see your custom error page you defined in step 1.
- Start the Event Viewer and open your custom Event Log. You should see a new event log entry with the details of the error that occurred. Double-click the event log entry to see the dirty details of your error:
Figure 3 - The Event Properties Dialog Displays the Detailed Error Nessage.
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();
What's Next
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:
- Create a class ExceptionLogger with a few overloaded methods like LogError. Have the methods accept various flavors of exceptions, exception messages and EventLogEntryTypes (Error, Warning, Information and so on) and log the errors to the Event log. This allows you to log errors or other events to the Event log from within a Catch block, without interrupting the page flow and relying on the global exception handler.
- Add backup code that logs the errors to a text file or sends out an e-mail in case the Event Log or Source does not exist. This shouldn't happen because you created the Logs and Source yourself at installation time, but, hey, it's not a perfect world.
- Create different Event Sources for your application. This allows you to make a distinction between different kind of event log entries so it's easier to locate the important ones.
There is Even More
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 project site.
References
- Exception Management Application Block for .NET
- System.Diagnostics Namespace
- EventLog Class
- EventLogEntryTypes Enumeration
- How do I Handle Errors and Send an Error Notification from ASP.NET Applications?
- Error Logging Modules & Handlers
Download Files
Source Code for this Article (Includes the Windows Application and two test web sites voor ASP.NET 1.x and ASP.NET 2.0)Where to Next?
Wonder where to go next? You can post a comment on this article.
Links in this Document
Doc ID | 275 |
Full URL | https://imar.spaanjaars.com/275/logging-errors-to-the-event-log-in-aspnet-applications |
Short cut | https://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) |
Comments
Talk Back! Comment on Imar.Spaanjaars.Com
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 Doc ID of the document.