The siren song of the framework

time to read 4 min | 743 words

In a recent blog post, I talked about a problem we found in NLog with our usage scenario. I mentioned that we’ll probably have our own solution to fit our needs. Eric Smith replied with:

So I guess there is no chance of contributing to the NLog project to improve it instead of creating yet another logging framework?

And the short answer for that is that there is very little chance for that. Primarily because what we are doing is not really suitable for consumption elsewhere.

Let us consider something that we found to be very useful. The Metrics.NET is a great way to get various metrics, and we have been using it (and contributed to it) for several years. But when looking at our 4.0 work, we also looked at what it would take to support metrics, and we had to flat out reject Metrics.NET for our use. Why is that?

Primarily because it is doing too much. It is extremely flexible and can do quite a lot, but we don’t need it to do a lot, and we don’t want to pay for the stuff we don’t use. For example, Histograms. The problematic issue for us was here:

public void Update(long value, string userValue = null)
{
    this.last = new UserValueWrapper(value, userValue);
    this.reservoir.Update(value, userValue);
}

Which ends up calling:

public void Update(long value, string userValue = null)
{
    long c = this.count.Increment();
    if (c <= this.values.Length)
    {
        values[(int)c - 1] = new UserValueWrapper(value, userValue);
    }
    else
    {
        long r = NextLong(c);
        if (r < values.Length)
        {
            values[(int)r] = new UserValueWrapper(value, userValue);
        }
    }
}

So that means that we’ll have two allocations for each time we update the histogram, which can happen a lot.  We don’t want to pay that price.

Now, we can certainly modify Metrics.NET to meet our needs, in fact, we have done just that, and ended up about 6 files that we needed, after we cleaned them up according to our current requirements. Contributing them back wouldn’t make much sense, they are full of constraints that are meant to allow us to run a database server for months on end with predictable and reliable performance under very high load. They don’t make sense in many other scenarios, and it can be incredibly limiting.

For a logging framework, we can most certainly add another option to NLog to do what we consider the right thing, but at this point, that wouldn’t really make sense. We don’t use a lot of the features, and reduce the surface area would mean reducing complexities. We can target something very narrow and get very high performance (in both CPU utilization and memory costs) much more easily & cheaply than trying to convert an existing codebase.

This is not a new concept. There is a very real cost to making something reusable. And in our case, RavenDB doesn’t need frameworks internally, we have a very good grasp about what is going on, and we want to have full ownership of every bit that is executed.