3

I use Common.Logging as a wrapper around NLog 2.0. I've done this so that I can replace NLog with another logging provider in the future.

I also use PostSharp to not write a try catch block everytime I need one. I have a class that inherits the OnMethodBoundaryAspect:

[Serializable]
public class LogMethodAttribute : OnMethodBoundaryAspect
{
    private ILog logger;

    public LogMethodAttribute()
    {
        this.logger = LogManager.GetCurrentClassLogger();
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        logger.Debug(string.Format("Entering {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        logger.Debug(string.Format("Leaving {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
    }

    public override void OnException(MethodExecutionArgs args)
    {
        logger.Error(args.Exception.Message,args.Exception);
    }
}

I have configured Common.Logging as follows in my web.config:

<configSections>
<sectionGroup name="common">
  <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
</configSections>
<common>
<logging>
  <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20">
    <arg key="configType" value="FILE" />
    <arg key="configFile" value="~/NLog.config" />
  </factoryAdapter>
</logging>
</common>

NLog.Config looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  throwExceptions="true"
  internalLogLevel="Debug"
  internalLogToConsoleError="true"
  internalLogFile="c:\new projects/nlog-app.txt"
>

<!-- 
See http://nlog-project.org/wiki/Configuration_file 
for information on customizing logging rules and outputs.
 -->
<targets>
<target name="database"
        xsi:type="Database"
        commandText="INSERT INTO LogEvent(EventDateTime, EventLevel, UserName, MachineName, EventMessage, ErrorSource, ErrorClass, ErrorMethod, ErrorMessage, InnerErrorMessage) VALUES(@EventDateTime, @EventLevel, @UserName, @MachineName, @EventMessage, @ErrorSource, @ErrorClass, @ErrorMethod, @ErrorMessage, @InnerErrorMessage)"

        dbProvider="System.Data.SqlClient">
  <connectionString>
    Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;
  </connectionString>
  <installConnectionString>
     Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;
  </installConnectionString>

    <!-- parameters for the command -->
  <parameter name="@EventDateTime" layout="${date:s}" />
  <parameter name="@EventLevel" layout="${level}" />
  <parameter name="@UserName" layout="${identity}" />
  <parameter name="@MachineName" layout="${machinename}" />
  <parameter name="@EventMessage" layout="${message}" />
  <parameter name="@ErrorSource" layout="${event-context:item=error-source}" />
  <parameter name="@ErrorClass" layout="${event-context:item=error-class}" />
  <parameter name="@ErrorMethod" layout="${event-context:item=error-method}" />
  <parameter name="@ErrorMessage" layout="${event-context:item=error-message}" />
  <parameter name="@InnerErrorMessage" layout="${event-context:item=inner-error-message}" />
  <!-- commands to install database -->
  <install-command>
    <text>CREATE DATABASE myDB</text>
    <connectionString> Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;</connectionString>
    <ignoreFailures>true</ignoreFailures>
  </install-command>

  <install-command>
    <text>
      CREATE TABLE LogEvent(
      EventId int primary key not null identity(1,1),
      EventDateTime datetime,
      EventLevel nvarchar(50),
      UserName nvarchar(50),
      MachineName nvarchar(1024),
      EventMessage nvarchar(MAX),
      ErrorSource nvarchar(1024),
      ErrorClass nvarchar(1024),
      ErrorMethod nvarchar(1024),
      ErrorMessage nvarchar(MAX),
      InnerErrorMessage nvarchar(MAX));
    </text>
  </install-command>

  <!-- commands to uninstall database -->
  <uninstall-command>
    <text>DROP DATABASE myDB</text>
    <connectionString> Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;</connectionString>
    <ignoreFailures>true</ignoreFailures>
  </uninstall-command>

</target>
</targets>

<rules>
<logger name="*" levels="Error" writeTo="database" />
</rules>
</nlog>

The problem is that nothing is inserted in my table. When I put a logger in for example my HomeController on the index page and I call my logger.Error("an error") it adds a record to my table.

Can somebody help me?

Jurgen Vandw
  • 631
  • 8
  • 27
  • I don't know anything about NLog, but this line looks suspicious; `this.logger = LogManager.GetCurrentClassLogger();`. In this case, won't that get a 'logger' related to the aspect class, NOT the decorated class? – RJ Lohan Jan 22 '13 at 03:33
  • 1
    The 'logger' will be fine, it will just be named with the current class name. – Chris Jan 30 '13 at 07:35

2 Answers2

0

Are you decorating your controller methods with the LogMethodAttribute that you created?

Also, you'll want to adjust your logger rule to include more levels outside of just "Error", otherwise that's all you'll log.

Give this a try:

<rules>
<logger name="*" minLevel="Trace" writeTo="database" />
</rules>

Edit:

Have you tried moving your logger initialization into your method?

public override void OnEntry(MethodExecutionArgs args)
{
     this.logger = LogManager.GetCurrentClassLogger();
     logger.Debug(string.Format("Entering {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
}

Per Donald Belcham's Pluralsight course, aspect constructors are not executed at runtime, so perhaps your logger is not getting set properly.

Chris
  • 1,533
  • 2
  • 17
  • 33
  • Yes I've decorated my methods with the LogMethodAttribute. I only have to log my errors in this particular case so it is fine to just log at the error level. – Jurgen Vandw Jan 30 '13 at 14:32
  • @JurgenVandw: Sorry, I guess I'm still trying to understand your question then...you're saying it works if you manually put logger.Error() in your controller method, but the OnEntry/OnExit is not working? You're OnEntry/OnExit log to the debug level and you haven't specified where to write debug messages. Does it work if you manually use logger.Debug() in your controller method? It should not unless you've left out some code here... – Chris Jan 30 '13 at 15:01
0

add a static property logger in your class Aspect

public class LogAspect : OnMethodBoundaryAspect
{
    /// <summary>
    /// Gets or sets the logger.
    /// </summary>
    public static ILogger logger { get; set; }

set logger variable in your application init method with your ILogger class and exclude all methods before this initialization with AttributeExclude.

    [LogAspect(AttributeExclude = true)]
    protected void Application_Start()
    {
        _windsorContainer = new WindsorContainer();
        ApplicationDependencyInstaller.RegisterLoggingFacility(_windsorContainer);
        LogAspect.logger = _windsorContainer.Resolve<ILogger>();
nick2paris
  • 21
  • 3
  • Please don't post exactly the same answer to several questions. If the same answer applies to more than one question it's a good sign the questions are duplicate. You should be flagging (or closing if you have enough reputation), not answering. – ChrisF Mar 13 '13 at 22:45