Logging From Day One (and Exception Handling)

by MikeHogg9. May 2012 09:50

NLog is so easy to use, it really is like plug and play. Or drag and drop. Add dll to your References. Add this to your web.config, use either file, or db table(what I use). Then, in any class you want to use Logger, just add a line for the static instance:

public class HomeController : MH.Controllers.AController
    {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); 

 

 

And then to use it:

 

    logger.Info("Some mess");

 

No reason not to have logging available in every web app from the start. I usually use a Log table described like my web.config shows here

<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>...</configSections>
...<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<targets>
<target name="db" xsi:type="Database" connectionStringName="CONN"
 commandText="insert into Log(Level, Source, Message, Audit_Date) values(@level, @logger, @message, @time_stamp);">
<parameter name="@time_stamp" layout="${date}"/>
<parameter name="@level" layout="${level}"/>
<parameter name="@logger" layout="${logger}"/>
<parameter name="@message" layout="${message}"/>
</target>
</targets>
<rules>
<logger name="*"writeTo="db"></logger>
</rules>
</nlog>

If you can't get it to start working, try using a log file first, or you can add atts like this example:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
internalLogFile="c:\mike.log" internalLogToConsole="true" throwExceptions="true">
<targets>
<target xsi:type="File" name="file" fileName="${basedir}/n.log" />

Oh and while we're here, ELMAH is always in my projects even before NLog.  It's just as easy, and actually comes with more features.  I use it with teh DB Table, and automatic emails.  This is all you need to get up and running...

<configuration>
<configSections>
<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>...
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
...<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<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>
</system.webServer>... and
<elmah>
<!--
        See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for
        more information on remote access and securing ELMAH.   -->
<security allowRemoteAccess="true" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="CONN">
</errorLog>
<errorMail
to="mike.hogg@havasdiscovery.com"
subject="[ELMAH] ACMT_Web Exception">
</errorMail>
</elmah>
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<!--
        See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for
        more information on using ASP.NET authorization securing ELMAH.      -->
<authorization>
<allow roles="Admin" />
<deny users="*" />
</authorization>
</system.web>
<system.webServer>
<handlers>
<add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
</handlers>
</system.webServer>
</location>
</configuration>

There's a db script to create the necessaries. I think that's it.  Comes with an Admin Area automatically and a dashboard app, if you set up authorization in your web then you should be able to see it with the Admin role and no further configuration.  ELMAH is good for catching all uncaught exceptions.  It has replaced my standard libraries and error handling methods in global.asax.

 

I also set up my own ErrorController, and some views, for my handled (known) errors.

public class ErrorController : AController
    {
public ActionResult Index()
        { 
            Models.Error e = GetError();
            e.Title = "Error!";
            e.Message = "We are sorry.  An error has occurred.  Please try again or contact support";
 return View(e);
        }
public ActionResult NotFound()
        {
            Models.Error e = GetError();
            e.Title = "Page Could Not Be Found";
            e.Message = "Sorry, that page could not be found";
 return View(e);
        }
private Models.Error GetError()
        {
            Models.Error result = new Models.Error();
            Exception ex = null;
 try
            {
                ex = (Exception)HttpContext.Application[Request.UserHostAddress.ToString()];
            }
 catch { }
 if (ex != null) result.Exception = ex;
 
 return result;
        }

If you want to manually log errors in your app using ELMAH, just do this (wrapped in my lib/logger library):

 

 

public static void LogWebException(Exception ex)
        {
 try
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex, System.Web.HttpContext.Current);

 

Or... add a filter to Exception handling and in that hook tell ELMAH to log handled. Now all of your handled exceptions will be logged also.

namespace MH.Web.Mvc3.Controllers
{
public class ElmahHandledErrorLoggerFilter : IExceptionFilter
    {
public void OnException(ExceptionContext context)
        {
 // Log only handled exceptions, because all other will be caught by ELMAH anyway.
 if (context.ExceptionHandled)
                Elmah.ErrorSignal.FromCurrentContext().Raise(context.Exception);
        }
// ADD THIS TO GLOBAL ASAX
///public static void RegisterGlobalFilters (GlobalFilterCollection filters)
//{
//    filters.Add(new ElmahHandledErrorLoggerFilter());
//    filters.Add(new HandleErrorAttribute());
//}
    }
}

 

 

 

ELMAH has a habit of becoming bothersome with all the 404s for robot.txt.   Put this in  your web.config to stop them..

 

 

<errorFilter>
<test>
<or>
<and>
 <equal binding="HttpStatusCode" value="404" type="Int32" />
 <equal binding="Context.Request.Path" value="/favicon.ico" type="string" />
</and>
<and>
 <equal binding="HttpStatusCode" value="404" type="Int32" />
 <equal binding="Context.Request.Path" value="/robots.txt" type="string" />
</and>
</or>
</test>
</errorFilter>
</elmah>

Add comment

biuquote
  • Comment
  • Preview
Loading

About Mike Hogg

Mike Hogg is a c# developer in Brooklyn.

More Here

Favorite Books

This book had the most influence on my coding style. It drastically changed the way I write code and turned me on to test driven development even if I don't always use it. It made me write clearer, functional-style code using more principles such as DRY, encapsulation, single responsibility, and more.amazon.com

This book opened my eyes to a methodical and systematic approach to upgrading legacy codebases step by step. Incrementally transforming code blocks into testable code before making improvements. amazon.com

More Here