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!