AOP and Logging in .net

I researched the idea of using AOP paradigm with a logging. Results are very interesting for me …

I will show an example which I created in an AOP sample.

Simple Class is our guinea pig:

class SimpleClass
{
    private readonly string _name;
    private string _index;

    public SimpleClass(string name, string index)
    {
        _name = name;
        _index = index;
    }

    [NLogTrace(NLogLevel.Debug)]
    public void Invoke()
    {
        FirstInnerMethod();
        SecondInnerMethod();
    }

    [NLogTrace(NLogLevel.Debug)]
    private void FirstInnerMethod()
    {
        Console.WriteLine("Dummy: {0}", _name);
    }

    [NLogTrace(NLogLevel.Debug)]
    private void SecondInnerMethod()
    {
        Console.WriteLine("Dummmy2: {0}", _index);
    }

    [NLogTrace(NLogLevel.Debug)]
    public void Increment(int <span class="hiddenGrammarError" pre=""><span class="hiddenGrammarError" pre="">index)
    {
        _index</span></span> += index;
    }
}

Definition of a NLogTrace attribute will be shown below. Our class has only two public methods, two private fields and two private methods.

Next, you can see main program code which is using our Sample Class:

class Program
{
    static void Main()
    {
        var dummyObj = new SimpleClass("aop sample", "3");

        dummyObj.Invoke();

        dummyObj.Increment(33);
    }
}

Constants which are used with our main attribute, NLogLevel:

[Serializable]
public static class NLogLevel
{
    public const string Trace = "Trace";
    public const string Debug = "Debug";
    public const string Info = "Info";
    public const string Warn = "Warn";
    public const string Error = "Error";
    public const string Fatal = "Fatal";
}

Method arguments builder (helper class) :

public static class ArgumentsBuilder
{
    public static string GetArgumentsInfo(this MethodExecutionArgs args)
    {
        var argumentsBuilder = new StringBuilder();
        argumentsBuilder.Append("(");

        for (int i = 0; i < args.Arguments.Count; i++)         {             if (i > 0)
                argumentsBuilder.Append(", ");

            argumentsBuilder.Append(GetArgumentFrom(args.Arguments[i]));
        }

        argumentsBuilder.Append(")");

        return argumentsBuilder.ToString();
    }

    private static string GetArgumentFrom(object argument)
    {
        return string.Format("{0}: {1}", argument.GetType(), argument);
    }
}

… and finally, our main class (attribute):

[Serializable]
public class NLogTraceAttribute : OnMethodBoundaryAspect
{
    private readonly string _logLevel;

    public NLogTraceAttribute(string logLevel)
    {
        _logLevel = logLevel;
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        LogAction("Enter", args);
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        LogAction("Leave", args);
    }

    public override void OnException(MethodExecutionArgs args)
    {
        var logger = LogManager.GetLogger(args.Method.DeclaringType.FullName);

        logger.Error("Exception in method: {0}.{1}", args.Method.DeclaringType.Name, args.Method.Name);
        logger.ErrorException("Exception {0}", args.Exception);
    }

    private void LogAction(string action, MethodExecutionArgs args)
    {
        var logger = LogManager.GetLogger(args.Method.DeclaringType.FullName);

        var argumentsInfo = args.GetArgumentsInfo();

        logger.Log(LogLevel.FromString(_logLevel), "{0}: {1}.{2}{3}", action, args.Method.DeclaringType.Name, args.Method.Name, argumentsInfo);
    }
}

Of course we should have create the NLog.config file in the solution. You should remember about setting a Copy To Output Directory property to a Copy Always value.

<?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">

  <variable name="logDirectory" value="C:\Temp" />
  <variable name="defaultLayout" value="================================${newline}${longdate}|${level:uppercase=true}|${newline}>>>   ${message}" />

  <targets>
    <target xsi:type="File" name="logfile_Debug" fileName="${logDirectory}\AopTest_Debug.log" layout="${defaultLayout}" />
  </targets>

  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile_Debug" />
  </rules>
</nlog>

Log Output:

================================
2011-03-06 19:50:34.5231|DEBUG|
>>>   Enter: SimpleClass.Invoke()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Enter: SimpleClass.FirstInnerMethod()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Leave: SimpleClass.FirstInnerMethod()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Enter: SimpleClass.SecondInnerMethod()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Leave: SimpleClass.SecondInnerMethod()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Leave: SimpleClass.Invoke()
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Enter: SimpleClass.Increment(System.Int32: 33)
================================
2011-03-06 19:50:34.5993|DEBUG|
>>>   Leave: SimpleClass.Increment(System.Int32: 33)

Related links:

Advertisements

One thought on “AOP and Logging in .net

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s