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
Logging of nearly all unhandled exceptions.
Email notification of each error at the time error occurs.
View the error log from a web page.
RSS feed .
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>,
- <!--add this-->
- < httpHandlers >
- < add verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >
- < /httpHandlers>
- <!--add this-->
Also, add the following code inside <system.webServer></system.webServer>,
- <!--add this-->
- < handlers >
- < add name = "Elmah"verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >
- < /handlers>
- <!--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
- CREATE TABLE[dbo].[ELMAH_Error]
- (
-
- [ErrorId][uniqueidentifier] NOT NULL,
-
- [Application][nvarchar](60) NOT NULL,
-
- [Host][nvarchar](50) NOT NULL,
-
- [Type][nvarchar](100) NOT NULL,
-
- [Source][nvarchar](60) NOT NULL,
-
- [Message][nvarchar](500) NOT NULL,
-
- [User][nvarchar](50) NOT NULL,
-
- [StatusCode][int] NOT NULL,
-
- [TimeUtc][datetime] NOT NULL,
-
- [Sequence][int] IDENTITY(1, 1) NOT NULL,
-
- [AllXml][ntext] NOT NULL
-
- )
Stored procedure
- Create PROCEDURE[dbo].[ELMAH_GetErrorsXml]
-
- (
- @Application NVARCHAR(60),
- @PageIndex INT = 0,
- @PageSize INT = 15,
- @TotalCount INT OUTPUT
-
- )
-
- AS
-
- SET NOCOUNT ON
-
- DECLARE @FirstTimeUTC DATETIME
- DECLARE @FirstSequence INT
- DECLARE @StartRow INT
- DECLARE @StartRowIndex INT
- SELECT
-
- @TotalCount = COUNT(1)
-
- FROM
-
- [ELMAH_Error]
-
- WHERE
-
- [Application] = @Application
- SET @StartRowIndex = @PageIndex * @PageSize + 1
- IF @StartRowIndex <= @TotalCount
-
- BEGIN
-
- SET ROWCOUNT @StartRowIndex
-
- SELECT
-
- @FirstTimeUTC = [TimeUtc],
-
- @FirstSequence = [Sequence]
-
- FROM
-
- [ELMAH_Error]
-
- WHERE
-
- [Application] = @Application
-
- ORDER BY
-
- [TimeUtc] DESC,
- [Sequence] DESC
-
- END
-
- ELSE
-
- BEGIN
-
- SET @PageSize = 0
-
- END
-
- SET ROWCOUNT @PageSize
-
- SELECT
-
- errorId = [ErrorId],
-
- application = [Application],
- host = [Host],
- type = [Type],
- source = [Source],
- message = [Message],
- [user] = [User],
- statusCode = [StatusCode],
- time = CONVERT(VARCHAR(50), [TimeUtc], 126) + 'Z'
-
- FROM
-
- [ELMAH_Error] error
-
- WHERE
-
- [Application] = @Application
-
- AND
-
- [TimeUtc] <= @FirstTimeUTC
-
- AND
-
- [Sequence] <= @FirstSequence
-
- ORDER BY
-
- [TimeUtc] DESC,
-
- [Sequence] DESC
-
- FOR
-
- XML AUTO
- Create PROCEDURE[dbo].[ELMAH_GetErrorXml]
-
- (
-
- @Application NVARCHAR(60),
- @ErrorId UNIQUEIDENTIFIER
-
- )
-
- AS
-
- SET NOCOUNT ON
- SELECT
-
- [AllXml]
- FROM
-
- [ELMAH_Error]
- WHERE
-
- [ErrorId] = @ErrorId
- AND
- [Application] = @Application
- Create PROCEDURE[dbo].[ELMAH_LogError]
-
- (
-
- @ErrorId UNIQUEIDENTIFIER,
- @Application NVARCHAR(60),
- @Host NVARCHAR(30),
- @Type NVARCHAR(100),
- @Source NVARCHAR(60),
- @Message NVARCHAR(500),
- @User NVARCHAR(50),
- @AllXml NTEXT,
- @StatusCode INT,
- @TimeUtc DATETIME
-
- )
-
- AS
-
- SET NOCOUNT ON
-
- INSERT
-
- INTO
-
- [ELMAH_Error]
- (
-
- [ErrorId],
- [Application],
- [Host],
- [Type],
- [Source],
- [Message],
- [User],
- [AllXml],
- [StatusCode],
- [TimeUtc]
-
- )
-
- VALUES
-
- (
-
- @ErrorId,
- @Application,
- @Host,
- @Type,
- @Source,
- @Message,
- @User,
- @AllXml,
- @StatusCode,
- @TimeUtc
-
- )
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>,
- </configuration>
- <elmah>
- <!--. 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.-->
- <!--add this-->
- <security allowRemoteAccess="0" />
- <!-- DefaultConnection is the name of database connection string -->
- <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />
- <!--add this-->
- </elmah>
Now my final webconfig file look like the following,
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- For more information on how to configure your ASP.NET application, please visit
- http://go.microsoft.com/fwlink/?LinkId=301880
- -->
- <configuration>
- <configSections>
-
- <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
- <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>
- </configSections>
- <connectionStrings>
- <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=ExceptionLog;Integrated Security=True" providerName="System.Data.SqlClient" />
- </connectionStrings>
- <appSettings>
- <add key="webpages:Version" value="3.0.0.0" />
- <add key="webpages:Enabled" value="false" />
- <add key="ClientValidationEnabled" value="true" />
- <add key="UnobtrusiveJavaScriptEnabled" value="true" />
- <add key="elmah.mvc.disableHandler" value="false" />
- <add key="elmah.mvc.disableHandleErrorFilter" value="false" />
- <add key="elmah.mvc.requiresAuthentication" value="false" />
- <add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
- <add key="elmah.mvc.allowedRoles" value="*" />
- <add key="elmah.mvc.allowedUsers" value="*" />
- <add key="elmah.mvc.route" value="elmah" />
- <add key="elmah.mvc.UserAuthCaseSensitive" value="true" />
- </appSettings>
- <system.web>
- <authentication mode="None" />
- <compilation debug="true" targetFramework="4.5.1" />
- <httpRuntime targetFramework="4.5.1" />
-
-
- <httpHandlers>
- <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
- </httpHandlers>
-
-
- <httpModules>
- <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
- <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
- <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
- </httpModules>
- </system.web>
- <system.webServer>
-
- <handlers>
- <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
- </handlers>
-
- <modules>
- <remove name="FormsAuthentication" />
- <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
- <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
- <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
- </modules>
- <validation validateIntegratedModeConfiguration="false" />
-
- </system.webServer>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
- <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
- <entityFramework>
- <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
- <parameters>
- <parameter value="mssqllocaldb" />
- </parameters>
- </defaultConnectionFactory>
- <providers>
- <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
- </providers>
- </entityFramework>
- <elmah>
-
-
-
- <security allowRemoteAccess="0" />
- <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />
-
- </elmah>
-
- </configuration>
Step 5: Let us create some exception
- Suppose I want to open a page that are not in our application. Let us say About2 page: localhost:55776/Home/About2
- Create divide by zero exception in contact page
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- namespace MVCExceptionLog.Controllers
- {
- public class HomeController: Controller
- {
- public ActionResult Index()
- {
- return View();
- }
- public ActionResult About()
- {
- ViewBag.Message = "Your application description page.";
- return View();
- }
- public ActionResult Contact()
- {
- int a = 0;
- int b;
- b = 1 / a;
- ViewBag.Message = "Your contact page.";
- return View();
- }
- }
- }
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.