Log4net visualiser

When we are implementing an EPiServer web site (or any other software solution) it is imperative to have good error handling. EPiServer uses log4net for its error handling so it is natural to use it as the logging framework for your application.

If your website is not behaving properly, you want to know about it and act accordingly. This is a good habit to have and it is a best practice in software development.

By default, EPiServer catches all unhandled exceptions in it’s EPiServer.Global error handler, but in standard .NET applications, this will not happen and you will not be able to see your unhandled exceptions in your log file. That’s where elmah kicks inn.

In this post we are going to look at how we can use log4net to track the exceptions you catch, elmah to track the exceptions you are not catching (and probably should) and and how we can aggregate and query this information in one central repository. This is done by appending exceptions caught by Elmah in our log4net repository and use log4net dashboard to analyse the errors.

We start by configuring the standard logging facility to write the errors in XML format. We have to edit [EPiServerLog|log4net].config and change the layout formatter. The file should look like this:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="..\logs\mywebsite.xml" />
    <appendToFile value="true" />
    <maximumFileSize value="10MB" />
    <maxSizeRollBackups value="20" />
 
    <layout type="log4net.Layout.XmlLayout">
      <param name="Prefix" value="" />
    </layout>
  </appender>
 
  <root>
    <level value="ERROR" />
    <appender-ref ref="RollingFile" />
  </root>
</log4net>

We are instructing log4net to log the errors in XML format into files, rotating it every 10MB, up to 20 files.

We modify the pages that we want to log exceptions by getting an instance of the logger and writing the exception to it.

You declare a member in your class/page:

private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

And use it when catching an exception:

catch (SmtpException smtpException)
            {
                Log.Error(smtpException);
                (...)
            }

We are now going to plug Elmah in in order to track the exceptions that are not handled in our code (non EPiServer sites only).

First we modify our web.config to configure its settings:

<configSections>
        <sectionGroup name="elmah">
            <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
            <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
        </sectionGroup>
    </configSections>
 
    <elmah>
        <errorLog type="MyWebsite.Log4NetErrorLog, MyWebsite" logPath="c:\logs" />
        <security allowRemoteAccess="0"></security>
    </elmah>
 
    <modules>
            <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
            <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah"/>
    </modules>

And add a class to our project with the following code. This class extends Elmah’s XmlFileErrorLog and overrides its logging behaviour. It will get the unhandled exception in your website and log it as a “Fatal” error in log4net, under the “Elmah” section.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Elmah;
using log4net;
 
namespace MyWebsite
{
    public class Log4NetErrorLog : XmlFileErrorLog
    {
        public Log4NetErrorLog(IDictionary config) : base(config)
        {
        }
 
        public Log4NetErrorLog(string logPath) : base(logPath)
        {
        }
 
        readonly ILog _log = LogManager.GetLogger("Elmah");
        public override string Log(Error error)
        {
            _log.Fatal("Exception logged through ELMAH: " + error.Message, error.Exception);
            return string.Empty;
        }
    }
}

The next step would be to install L4ndash. You can get it here: http://www.l4ndash.com/Download.aspx. The developer edition is free to use as long as you have only one instance per machine and access it via localhost.

Finally, we need to create a plugin that serves as a view over the l4ndash dashboard:

namespace EPiServer.Templates.Private
{
    using EPiServer.PlugIn;
 
    /// <summary>
    /// This plugin will display the errors in your error log
    /// </summary>
    [GuiPlugIn(DisplayName = "Error Report", Area = PlugInArea.AdminMenu, Url = "~/templates/private/errors.aspx")]
    public partial class Errors : System.Web.UI.Page
    {
    }
}

Assuming you install landash as a virtual directory under your default web site:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Errors.aspx.cs" Inherits="EPiServer.Templates.Private.Errors" %>
<iframe src="http://localhost/landash/PageLoggerSummary/LoggerSummary.aspx" width="100%" height="100%"></iframe>

And you’re good to go! The following is a sample screen shot from an EPiServer CMS6 + Composer 4 development box:

We can see the overview of all exceptions and drill down into specific errors to get more information.

We can also apply filters to get errors thrown by a specific method or to get the latest recorder errors.

Hopefully this will help you in diagnosing and debugging your EPiServer (and in general, web) applications.

post3-1

post3-2

post3-3

post3-4