If you aren’t using ELMAH (Error Logging Modules and Handlers) you should be – http://code.google.com/p/elmah/ It’s the best thing since sliced bread for logging ASP.NET errors with practically zero effort. It basically plugs into the ASP.NET pipeline and logs all unhandled exceptions thrown and HTTP error codes together with all sorts of other useful information such as request url, stacktrace, current user username, cookies and more. You can say it makes a snapshot of the Yellow Screen of Death with extra information. It then gives you a simple web access to the recent errors logged (by default at http//mysite.com/elmah.axd), exposing a RSS feed as well. It’s fully configurable (error filters, multiple backend log storage systems support, etc) and also can be set up to send emails on error.
Some screenshots:
You can pull ELMAH through nuget via the “Elmah” package., which will download it and add a reference. The steps to get it all set up for ASP.NET MVC are as follows.
- Register Elmah configuration sections in the Web.config
<sectionGroup name="elmah"> <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" /> <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" /> <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" /> <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" /> </sectionGroup>
- Add the root level ELMAH section in Web.config to tell it where to store the logs and how. Easiest to set up is to have a directory where it stores xml file for each error, but make sure the IIS process/AppPool has write access to that directory! Also I have added a filter to ignore all HTTP 404 errors. Note that this filter won’t work for ASP.NET MVC and I will come back to that later.
<elmah> <security allowRemoteAccess="1" /> <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/ElmahLogs" /> <errorFilter> <test> <equal binding="HttpStatusCode" value="404" type="Int32" /> </test> </errorFilter> </elmah>
- Register ELMAH with the ASP.NET pipeline both in the system.web **section (when running locally) and the system.webServer** section when deployed to IIS. Just copy paste the below snippet in both sections. Notice how the default configuration says that ELMAH will be available at mysite.com/elmah.axd . You can change that if you want (in both places!)
<httpModules> <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" /> </httpModules> <httpHandlers> <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" /> </httpHandlers>
You are done and elmah will be available at http://mysite.com/elmah.axd , but it won’t work quite right with ASP.NET MVC, because of the way errors are handled there, so there are those additional things that need to be set up:
- Log exceptions before ASP.NET MVC swallows them if using customErrors or some other code handles and swallows the error. To do this I’ve implemented the below exception filter that logs all handled exceptions. It’s a good example also of how to programatically log errors with ELMAH:
using System; using System.Web.Mvc; using Elmah; namespace Triply.Extensions { public class ElmahHandledErrorLoggerFilter : IExceptionFilter { public void OnException (ExceptionContext context) { // Long only handled exceptions, because all other will be caught by ELMAH anyway. if (context.ExceptionHandled) ErrorSignal.FromCurrentContext().Raise(context.Exception); } } }
To register it add it in Global.asax.cs. The ordering is important – add it before the HandleErrorAttribute is registered.
public static void RegisterGlobalFilters (GlobalFilterCollection filters) { filters.Add(new ElmahHandledErrorLoggerFilter()); filters.Add(new HandleErrorAttribute()); }
- One final note regarding filtering out HTTP 404 errors. In ASP.NET MVC they are raised as exceptions so if you want to ignore them unfortunately you can’t do that declaratively in the Web.config. Instead you have to add the following elmah hooks to your Global.asax.cs to do it programatically:
// ELMAH Filtering protected void ErrorLog_Filtering (object sender, ExceptionFilterEventArgs e) { FilterError404(e); } protected void ErrorMail_Filtering (object sender, ExceptionFilterEventArgs e) { FilterError404(e); } // Dismiss 404 errors for ELMAH private void FilterError404 (ExceptionFilterEventArgs e) { if (e.Exception.GetBaseException() is HttpException) { HttpException ex = (HttpException)e.Exception.GetBaseException(); if (ex.GetHttpCode() == 404) e.Dismiss(); } }
That’s it. Now you get super cool logging (and remember – RSS feed!)