Wednesday, May 16, 2007

I have been looking for a quick and easy way to implement logging into our application while writing tests. The problem is that logging is a cross cutting concern and I feel dirty adding logging code into every class.

I originally started looking at a number of Aspect Oriented Frameworks with grand plans to use them for other concerns, then I ran into this comment from Hammett on the Castle Project forums:

 "Honestly, the interception capabilities that Windsor provide is enough for me, that's why I havent searched for a full-fledged AOP tool yet."

It turns out that the interception capabilities of Windsor solve my logging problems as well.

Here is a simple example that demonstrates the Interceptor capabilities of Windsor.

I have a ICalculator interface with one method named Calc that takes the parameters x and y of type int.

public interface  ICalculator
{
int Calc(int x, int y);
}

I have a concrete class that implements that interface. Notice that my concrete class does one thing well (adding two numbers) it does not add two numbers and log well.

public class Calculator : ICalculator
{
public int Calc(int x, int y)
{
return x + y;
}
}
Our Windsor configuration looks like this:
<component id="calculator"
           service="MyAssembly.ICalculator, MyAssembly"
           type="MyAssembly.Calculator, MyAssembly" />

Now we can create a logging interceptor to log calculations:

public class LogInterceptor : IMethodInterceptor
{
public object Intercept(IMethodInvocation invocation, params object[] args)
{
Console.WriteLine("Invocaton Method: " + invocation.Method.Name);

foreach (object o in args)
{
Console.WriteLine("Args: " + o);
}

object retValue = invocation.Proceed(args);

return retValue;
}
}

This class will log the method name that was called and the arguments that were passed to it to the console and then proceed with the method that it intercepted (Calc in our case). Now using Windsor we can add logging to any class that needs it, all we need to do is add the InterceptorAttribute to the Calculator class that needs logging and to modify our Windsor configuration file:

<component id="log.interceptor"
             type="MyAssembly.LogInterceptor, MyAssembly" />
        
        <component id="calculator"
             service="MyAssembly.ICalculator, MyAssembly"
             type="MyAssembly.Calculator, MyAssembly">

            <interceptors>
                <interceptor>${log.interceptor}</interceptor>
            </interceptors>

        </component>

Anytime we call Calculator its values will get logged to the console without modifying the intent of the calc method. Very cool!

Wednesday, May 16, 2007 5:52:11 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
Friday, June 22, 2007 6:34:02 PM (GMT Standard Time, UTC+00:00)
Steven,
This was something that eluded me for a while. I had read how powerful AOP was but thought some elaborate framework was required to yield returns. I saw exactly the same comment from Hammett you quoted and I realized all the framework I already needed was right in the Windsor I have been using.
Thanks for your sample!
Mike
Comments are closed.

Theme design by Jelle Druyts

Pick a theme: