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