What is Elmah

According to Scott Mitchell, Error Logging Modules And Handlers (ELMAH) offers another approach to log runtime errors in a production environment. ELMAH is a free, open source error logging library that includes features like error filtering and the ability to view the error log from a web page, as an RSS feed, or to download it as a comma-delimited file.

What we will achieve through Elmah

Step 1: Create a MVC web Application

Open Visual Studio create new project or press CTRL +SHIFT +N. Go to Web tab, select ASP.NET Web Application template. Give name as MVCExceptionLog as in the following screenshot,



Step 2: Add Elmah Package from Nuget,

Right click on project solution go to Manage NuGetPackages for Solution, click on it and search elmah and install it,

Step 3: Now open web config file and add the following code inside <system.web> </system.web>,

  1. <!--add this-->
  2. < httpHandlers >
  3. < add verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >
  4. < /httpHandlers>
  5. <!--add this-->

Also, add the following code inside <system.webServer></system.webServer>,

  1. <!--add this-->
  2. < handlers >
  3. < add name = "Elmah"verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >
  4. < /handlers>
  5. <!--add this-->

Step 4: Create table and Stored Procedure,

Here I am using SQL Server database to log the exception. I have already created database SQL Server named ExceptionLog. Open SQL Server Management Studio, run the following code in ExceptionLog database one by one.

For Table

  1. CREATE TABLE[dbo].[ELMAH_Error]
  2. (
  3. [ErrorId][uniqueidentifier] NOT NULL,
  4. [Application][nvarchar](60) NOT NULL,
  5. [Host][nvarchar](50) NOT NULL,
  6. [Type][nvarchar](100) NOT NULL,
  7. [Source][nvarchar](60) NOT NULL,
  8. [Message][nvarchar](500) NOT NULL,
  9. [User][nvarchar](50) NOT NULL,
  10. [StatusCode][int] NOT NULL,
  11. [TimeUtc][datetime] NOT NULL,
  12. [Sequence][int] IDENTITY(1, 1) NOT NULL,
  13. [AllXml][ntext] NOT NULL
  14. )

Stored procedure

    1. Create PROCEDURE[dbo].[ELMAH_GetErrorsXml]
    2. (
    3. @Application NVARCHAR(60),
    4. @PageIndex INT = 0,
    5. @PageSize INT = 15,
    6. @TotalCount INT OUTPUT
    7. )
    8. AS
    9. SET NOCOUNT ON
    10. DECLARE @FirstTimeUTC DATETIME
    11. DECLARE @FirstSequence INT
    12. DECLARE @StartRow INT
    13. DECLARE @StartRowIndex INT
    14. SELECT
    15. @TotalCount = COUNT(1)
    16. FROM
    17. [ELMAH_Error]
    18. WHERE
    19. [Application] = @Application
    20. SET @StartRowIndex = @PageIndex * @PageSize + 1
    21. IF @StartRowIndex <= @TotalCount
    22. BEGIN
    23. SET ROWCOUNT @StartRowIndex
    24. SELECT
    25. @FirstTimeUTC = [TimeUtc],
    26. @FirstSequence = [Sequence]
    27. FROM
    28. [ELMAH_Error]
    29. WHERE
    30. [Application] = @Application
    31. ORDER BY
    32. [TimeUtc] DESC,
    33. [Sequence] DESC
    34. END
    35. ELSE
    36. BEGIN
    37. SET @PageSize = 0
    38. END
    39. SET ROWCOUNT @PageSize
    40. SELECT
    41. errorId = [ErrorId],
    42. application = [Application],
    43. host = [Host],
    44. type = [Type],
    45. source = [Source],
    46. message = [Message],
    47. [user] = [User],
    48. statusCode = [StatusCode],
    49. time = CONVERT(VARCHAR(50), [TimeUtc], 126) + 'Z'
    50. FROM
    51. [ELMAH_Error] error
    52. WHERE
    53. [Application] = @Application
    54. AND
    55. [TimeUtc] <= @FirstTimeUTC
    56. AND
    57. [Sequence] <= @FirstSequence
    58. ORDER BY
    59. [TimeUtc] DESC,
    60. [Sequence] DESC
    61. FOR
    62. XML AUTO

    1. Create PROCEDURE[dbo].[ELMAH_GetErrorXml]
    2. (
    3. @Application NVARCHAR(60),
    4. @ErrorId UNIQUEIDENTIFIER
    5. )
    6. AS
    7. SET NOCOUNT ON
    8. SELECT
    9. [AllXml]
    10. FROM
    11. [ELMAH_Error]
    12. WHERE
    13. [ErrorId] = @ErrorId
    14. AND
    15. [Application] = @Application

    1. Create PROCEDURE[dbo].[ELMAH_LogError]
    2. (
    3. @ErrorId UNIQUEIDENTIFIER,
    4. @Application NVARCHAR(60),
    5. @Host NVARCHAR(30),
    6. @Type NVARCHAR(100),
    7. @Source NVARCHAR(60),
    8. @Message NVARCHAR(500),
    9. @User NVARCHAR(50),
    10. @AllXml NTEXT,
    11. @StatusCode INT,
    12. @TimeUtc DATETIME
    13. )
    14. AS
    15. SET NOCOUNT ON
    16. INSERT
    17. INTO
    18. [ELMAH_Error]
    19. (
    20. [ErrorId],
    21. [Application],
    22. [Host],
    23. [Type],
    24. [Source],
    25. [Message],
    26. [User],
    27. [AllXml],
    28. [StatusCode],
    29. [TimeUtc]
    30. )
    31. VALUES
    32. (
    33. @ErrorId,
    34. @Application,
    35. @Host,
    36. @Type,
    37. @Source,
    38. @Message,
    39. @User,
    40. @AllXml,
    41. @StatusCode,
    42. @TimeUtc
    43. )

After creating the database table and stored procedure. The schema will look like the following:


Now again open web config file, add the following code inside in <configuration>,
  1. </configuration>
  2. <elmah>
  3. <!--. If allowRemoteAccess value is set to 0, then the error log web page can only be viewed locally. If allowRemoteAccess attribute is set to 1 then the error log web page is enabled for both remote and local visitors.-->
  4. <!--add this-->
  5. <security allowRemoteAccess="0" />
  6. <!-- DefaultConnection is the name of database connection string -->
  7. <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />
  8. <!--add this-->
  9. </elmah>
Now my final webconfig file look like the following,
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!--
  3. For more information on how to configure your ASP.NET application, please visit
  4. http://go.microsoft.com/fwlink/?LinkId=301880
  5. -->
  6. <configuration>
  7. <configSections>
  8. <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  9. <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  10. <sectionGroup name="elmah">
  11. <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
  12. <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
  13. <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
  14. <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
  15. </sectionGroup>
  16. </configSections>
  17. <connectionStrings>
  18. <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=ExceptionLog;Integrated Security=True" providerName="System.Data.SqlClient" />
  19. </connectionStrings>
  20. <appSettings>
  21. <add key="webpages:Version" value="3.0.0.0" />
  22. <add key="webpages:Enabled" value="false" />
  23. <add key="ClientValidationEnabled" value="true" />
  24. <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  25. <add key="elmah.mvc.disableHandler" value="false" />
  26. <add key="elmah.mvc.disableHandleErrorFilter" value="false" />
  27. <add key="elmah.mvc.requiresAuthentication" value="false" />
  28. <add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
  29. <add key="elmah.mvc.allowedRoles" value="*" />
  30. <add key="elmah.mvc.allowedUsers" value="*" />
  31. <add key="elmah.mvc.route" value="elmah" />
  32. <add key="elmah.mvc.UserAuthCaseSensitive" value="true" />
  33. </appSettings>
  34. <system.web>
  35. <authentication mode="None" />
  36. <compilation debug="true" targetFramework="4.5.1" />
  37. <httpRuntime targetFramework="4.5.1" />
  38. <!--add this-->
  39. <httpHandlers>
  40. <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
  41. </httpHandlers>
  42. <!--add this-->
  43. <httpModules>
  44. <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
  45. <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
  46. <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
  47. </httpModules>
  48. </system.web>
  49. <system.webServer>
  50. <!--add this-->
  51. <handlers>
  52. <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
  53. </handlers>
  54. <!--add this-->
  55. <modules>
  56. <remove name="FormsAuthentication" />
  57. <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
  58. <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
  59. <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
  60. </modules>
  61. <validation validateIntegratedModeConfiguration="false" />
  62. </system.webServer>
  63. <runtime>
  64. <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  65. <dependentAssembly>
  66. <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
  67. <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  68. </dependentAssembly>
  69. <dependentAssembly>
  70. <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
  71. <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  72. </dependentAssembly>
  73. <dependentAssembly>
  74. <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
  75. <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  76. </dependentAssembly>
  77. <dependentAssembly>
  78. <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
  79. <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  80. </dependentAssembly>
  81. <dependentAssembly>
  82. <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
  83. <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
  84. </dependentAssembly>
  85. <dependentAssembly>
  86. <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
  87. <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  88. </dependentAssembly>
  89. <dependentAssembly>
  90. <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
  91. <bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" />
  92. </dependentAssembly>
  93. <dependentAssembly>
  94. <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
  95. <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
  96. </dependentAssembly>
  97. <dependentAssembly>
  98. <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
  99. <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
  100. </dependentAssembly>
  101. <dependentAssembly>
  102. <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
  103. <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
  104. </dependentAssembly>
  105. </assemblyBinding>
  106. </runtime>
  107. <entityFramework>
  108. <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
  109. <parameters>
  110. <parameter value="mssqllocaldb" />
  111. </parameters>
  112. </defaultConnectionFactory>
  113. <providers>
  114. <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  115. </providers>
  116. </entityFramework>
  117. <elmah>
  118. <!--add this-->
  119. <!--. If allowRemoteAccess value is set to 0, then the error log web page can only be viewed locally. If this attribute is set to 1 then the error log web page is enabled for both remote and local visitors.-->
  120. <security allowRemoteAccess="0" />
  121. <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />
  122. <!--add this-->
  123. </elmah>
  124. </configuration>
Step 5: Let us create some exception
  1. Suppose I want to open a page that are not in our application. Let us say About2 page: localhost:55776/Home/About2
  2. Create divide by zero exception in contact page
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. namespace MVCExceptionLog.Controllers
  7. {
  8. public class HomeController: Controller
  9. {
  10. public ActionResult Index()
  11. {
  12. return View();
  13. }
  14. public ActionResult About()
  15. {
  16. ViewBag.Message = "Your application description page.";
  17. return View();
  18. }
  19. public ActionResult Contact()
  20. {
  21. int a = 0;
  22. int b;
  23. b = 1 / a;
  24. ViewBag.Message = "Your contact page.";
  25. return View();
  26. }
  27. }
  28. }

Step 5: Run the application,

Click on F5 and register a user.


Step 6: View the Error Log from a Web Page,

You can view the error log web page through the url localhost:portno/elmah.axd like, localhost:55776/elmah.axd.

Check the error log in database.
Point of Interest

In this article we learned how to log Exception in SQL Server and view error log details from web page.