Amptools.Net

simplify your life.

Archive for November 3rd, 2008

Simple Log in Amplify

No Gravatar

As many people know rails has a simple logger inside the framework which really only outputs to the console. This comes in handy to see SQL output of your models, benchmarks and other cool little things inside the rails framework. 

Of course people in the .Net realm tend to want things that scale and yet simplified for them.  So output only to the console won’t fly in larger projects.  There is log4net, but you don’t want to have it tightly coupled to the system, this caused an issue to one project that I worked on while still working for Vivus Software before I came OSC. Where the framework and project both expected a certain version of Log4Net and there was no wrapper to put something else in place if need be. 

 

So the solution was to Build small static Log class, that takes a list of an interface ILog (different than log4net’s) and then use that interface to build a wrapper around using the root Logger for log4net. This way people can still build their own loggers for amplify or build their own Appenders for Log4Net and amplify will still be able to leverage this. Of course there is also conditional symbol LOG4NET in amplify if you wish to build the amplify framework without any dependency on the log4net library.  

To me this is more like the Console.WriteLine that is needed for a class library vs what log4net is typically used for in an application where it also spits out the type information of a class. To help with the testing using mock object is the which uses the Lambda expression and gets rid of all that crazy record/playback junk to which I loathe. 

public void Test()
{
	Log.Sql("SELECT * FROM test");
	Log.Debug("The id is  {0} ", id);
}
 

[It(Order = 2), Should("have a debug method that logs debug statements")]
public void Debug()
{
	var calls = new List();
	var log = CreateMockLog();

	log.Expect(o => o.Debug(Moq.It.IsAny(), null))
		.Callback((string s, object[] args) => { calls.Add(s); });

	calls.Count.ShouldBe(0);

	// simple and easily called from anywhere... and lets you
	// format messages like
	// Log.Debug("item id: {0} could not be saved", id);
	Log.Debug("debug", null);
	calls.Count.ShouldBe(1);
	calls.Contains("debug").ShouldBeTrue();

	Log.IsDebug = false;

	// its turned off so it won't output anything
	Log.Debug("debug", null);
	calls.Count.ShouldBe(1);

	Log.IsDebug = true;
}

private static Mock CreateMockLog()
{
	var log = new Mock();
	Log.Loggers.Clear();
	Log.Loggers.Add(log.Object);
	return log;
}

Though keep in mind, one of the more trickier things to mock is the use of a method with the “params” keyword. I had to used a callback that you pass in an object array (object[] args) and I passed in null, otherwise the callback would not fire, and Lambdas don’t allow the “params” keyword. Once that was figured out, I was able to use moq successfully to test the Log class successfully.