Sunday, January 30, 2011

The Incredible Lightness of ELMAH

I recently gave a lightning talk at the San Francisco Bay.NET User Group meeting on ELMAH (Error Logging Modules and Handlers). This was a great opportunity to learn about this tool, which was originally developed by Scott Mitchell and Atif Aziz as sample code for an MSDN article. Since the initial release in 2004, Atif Aziz has been continuing development and maintenance on ELMAH  as a community open source project.

I've been aware of ELMAH for some time, but I hadn't gotten around to really looking at it; I'm very glad that the Mathias Brandewinder, the Bay.NET Chapter Leader for San Francisco, asked me to give the lighting talk. It gave me a chance to roll up my sleeves and get to know this great resource for ASP.NET development.

ELMAH is a good topic for a quick demonstration, because the setup is so easy. All you need to set up an error log is to download ELMAH, put the ELMAH dll in the bin folder of your site, and make a few additions to your web config file. One line must be added to the httpHandlers section:

<httpHandlers>
    <add verb="POST,GET,HEAD"
    path="elmah.axd"
    type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>



and one to the httpModules section:


<httpModules>
    <add name="ErrorLog"
    type="Elmah.ErrorLogModule, Elmah" />
</httpModules>



If you're running IIS 7, you'll have to also make module and handler entries in the system.webServer section:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
    
    <add name="ErrorLog" 
            type="Elmah.ErrorLogModule, Elmah" />
    </modules>
    <handlers>
    
    <add name="Elmah" 
            preCondition="integratedMode" 
            verb="POST,GET,HEAD" 
            path="elmah.axd" 
            type="Elmah.ErrorLogPageFactory, Elmah"/>
    </handlers>
</system.webServer>


The amazing thing about ELMAH is that once you make these changes, you'll have a fully functional error log. You get to the error log by entering the path to your handler (I've just left the handler path at the default "elmah.axd" in the examples above). Here's what you see:


This example contains only a single error, but as you can see the display accommodates multiple errors with paging options. Clicking on the details tab shows a stack trace, error details, and a full dump of the HTTP request attributes.

The only other essential item in setting up a basic ELMAH installation is to set up a data store for errors. The display shown above is using the in-memory log, which means errors will be lost when the server is reset. Adding a data store means that error will persist after a reboot. ELMAH supports multiple database platforms; I set mine up with SQL server, which looks something like this:

<configSections>
    <sectionGroup name="elmah">
    
    <section name="errorLog" 
            requirePermission="false" 
            type="Elmah.ErrorLogSectionHandler, Elmah" />
    </sectionGroup>
</configSections>

<elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah"
    
    connectionString="Data Source=YourDatabaseServer;Initial Catalog=YourDatabase;Trusted_Connection=True" />
</elmah>


There are many more capabilities of ELMAH, including email notification and error filtering. You can learn about them at the official project site. It is a good idea to look at the security setup information on the project site to make sure your error handler is secure.

What I Learned

I have my own philosophy about error handling architectures which I've developed over many projects, but working with ELMAH showed me a new approach. Instead of requiring conformance to a particular error handling and reporting strategy in code, ELMAH treats error handling as a cross-cutting concern and handles errors transparently. This means there is no requirement to build error handling into your code at all, making the code more portable and eliminating any problems with inconsistent implementation. For more on this topic, I encourage you to read the original MSDN article for which ELMAH was created.