Coding A AOP Logger

Look at the following points

  • Create a new project (I created a Console Application).
  • Add NuGet package Castle.Core, Castle.Windsor and Log4Net.
  • Castle.Core: Allow we to use Proxy 
Proxy objects can assist in building a flexible application architecture because it allows functionality to be transparently added to code without modifying it. For example, a class could be proxied to add logging or security checking without making the code aware this functionality has been added.

For example, NHibernate, an object/relational mapper uses DynamicProxy to provide lazy loading of data without the domain model classes being aware of this functionality.
  • Castle.Widsor: IoC (Inversion of control container).

  • Log4net: Lib to log our application.

    Castle

    log4net
  • Implementing a simple calculator to logger their operations:
    1. public interface ICalculator    
    2. {    
    3.     double Add(double x, double y);    
    4.     double Divide(double x, double y);    
    5. }    
    6. public class Calculator: ICalculator    
    7. {    
    8.     public double Add(double x, double y)    
    9.     {    
    10.         return x + y;    
    11.     }    
    12.     public double Divide(double x, double y)    
    13.     {    
    14.         return x / y;    
    15.     }    
    16. }  
  • Now we can proceed to coding our logger. We want to log every call function including their parameters and the return value.

  • Let’s create a simple Class Calculator to be logged as follows.

  • Now we need to configure log4net,

    Open the AssemblyInfo.cs and insert the follow line:

    [assembly: log4net.Config.XmlConfigurator(Watch = true)]

    Configure the application config (app.config) as follows:

    1. <?xml version="1.0" encoding="utf-8" ?>    
    2.     <configuration>    
    3.         <configSections>    
    4.             <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections>    
    5.         <startup>    
    6.             <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup>    
    7.         <log4net>    
    8.             <appender name="MyLogger" type="log4net.Appender.RollingFileAppender">    
    9.                 <file type="log4net.Util.PatternString" value="MyLog.txt" />    
    10.                 <appendToFile value="true" />    
    11.                 <rollingStyle value="Size" />    
    12.                 <maxSizeRollBackups value="20" />    
    13.                 <maximumFileSize value="1000KB" />    
    14.                 <layout type="log4net.Layout.PatternLayout">    
    15.                     <param name="ConversionPattern" value="%date [%thread] %-5level %logger [%ndc] - %message%newline" /> </layout>    
    16.             </appender>    
    17.             <root>    
    18.                 <level value="DEBUG" />    
    19.                 <appender-ref ref="MyLogger" /> </root>    
    20.         </log4net>    
    21.     </configuration>  
  • Now we need to create an Interceptor to be invoked in every method call to create our log.

    1. public class LogInterceptor: IInterceptor    
    2. {    
    3.     void IInterceptor.Intercept(IInvocation invocation)    
    4.     {    
    5.         var logger = LogManager.GetLogger(invocation.TargetType);    
    6.         try    
    7.         {    
    8.             StringBuilder sb = null;    
    9.             if (logger.IsDebugEnabled)    
    10.             {    
    11.                 sb = new StringBuilder(invocation.TargetType.FullName).Append(".").Append(invocation.Method).Append("("); //getting method name    
    12.                 //getting parameters    
    13.                 for (int i = 0; i < invocation.Arguments.Length; i++)    
    14.                 {    
    15.                     if (i > 0) sb.Append(", ");    
    16.                     sb.Append(invocation.Arguments[i]);    
    17.                 }    
    18.                 sb.Append(")");    
    19.                 logger.Debug(sb);    
    20.             }    
    21.             invocation.Proceed();    
    22.             if (logger.IsDebugEnabled)    
    23.             {    
    24.                 //getting return    
    25.                 logger.Debug("Return of " + sb + " is: " + invocation.ReturnValue);    
    26.             }    
    27.         }    
    28.         catch (Exception e)    
    29.         {    
    30.             logger.Error(e);    
    31.             throw;    
    32.         }    
    33.     }    
    34. }   
  • Now we need to test our Logger.

    At my console application main I have the following code:

    1. class Program    
    2. {    
    3.     static void Main(string[] args)    
    4.     {    
    5.         InitCalc();    
    6.     }    
    7.     private static void InitCalc()    
    8.     {    
    9.         //A little of IoC here    
    10.         //Here I put our LogInterceptor into my Calculator    
    11.         var container = new WindsorContainer().Register(Component.For < LogInterceptor > (), Component.For < ICalculator > ().ImplementedBy < Calculator > ().Interceptors(new InterceptorReference(typeof (LogInterceptor))).First);    
    12.         BasicConfigurator.Configure(); // configure log4net    
    13.         //Create my ICalculator Object to be able to log method calls    
    14.         var c = container.Resolve < ICalculator > ();    
    15.         try    
    16.         {    
    17.             c.Add(1, 2);    
    18.             c.Divide(1, 2);    
    19.             c.Divide(1, 0);    
    20.         }    
    21.         catch (Exception)    
    22.         {}    
    23.         Console.ReadKey();    
    24.     }    
    25. }  
  • Check the MyLog.txt at bin folder:

    1. 2015 - 10 - 28 16: 30: 07, 455[10] DEBUG LoggerAOP.Calculator[(null)] - LoggerAOP.Calculator.Double Add(Double, Double)(1, 2)    
    2. 2015 - 10 - 28 16: 30: 07, 529[10] DEBUG LoggerAOP.Calculator[(null)] - Return of LoggerAOP.Calculator.Double Add(Double, Double)(1, 2) is: 3    
    3. 2015 - 10 - 28 16: 30: 07, 530[10] DEBUG LoggerAOP.Calculator[(null)] - LoggerAOP.Calculator.Double Divide(Double, Double)(1, 2)    
    4. 2015 - 10 - 28 16: 30: 07, 530[10] DEBUG LoggerAOP.Calculator[(null)] - Return of LoggerAOP.Calculator.Double Divide(Double, Double)(1, 2) is: 0, 5    
    5. 2015 - 10 - 28 16: 30: 07, 531[10] DEBUG LoggerAOP.Calculator[(null)] - LoggerAOP.Calculator.Double Divide(Double, Double)(1, 0)    
    6. 2015 - 10 - 28 16: 30: 07, 531[10] DEBUG LoggerAOP.Calculator[(null)] - Return of LoggerAOP.Calculator.Double Divide(Double, Double)(1, 0) is: +Infinito   

References