Enterprise Library vs. Log4Net
If there’s one thing that really irks me is allegiance for the sake of allegiance.
Don’t get me wrong, I have nothing against Microsoft Enterprise Library and in fact, in absense of any better alternatives, EL is indeed the best option for a whole slew of development tasks and better than rolling one’s own solution. But of course, the question is then: are there better alternatives.
Take logging for example. There has been a movement in our team to use EL instead of log4net. In all honesty, it’s not a battle that I want to wage…it’s simply not worth it for logging, but I think that for anyone considering one or the other, some serious evaluation is in order. EL logging simply cannot hold a candle to log4net.
As I commented on James Newton Kings’ blog:
About 2 years ago, I started to seriously integrate logging into my applications. During that time, I went through several rounds of testing both log4net and EL and I am currently in a discussion with other developers in my group on whether we should use the best available tool (log4net 1.2.11) or the do it the Microsoft way (EL 3.0/3.1).
In my opinion, the lack of hierarchical loggers is a significant weakness of EL as it requires much more thought and planning to make sure that you can isolate components down the line. While flexibility is good, I think that having the free form category, priority ID, and event ID make it far more confusing than it has to be…18 overloads? Do you expect people to remember or use the right category every time? What about misspellings? Of course, one could always write a layer to abstract these weaknesses of EL such as add a layer to translate Log.Debug() to some internal EL call, but then you have to ask if you’ve gained anything in the process.
Aside from this, I’m not sure if you are aware, but log4net utilizes buffered appenders for certain classes of appenders with the ADO.Net appender being one of those. What does this mean? I think you will see significant performance increases with buffered appenders (say buffer 250 messages in one flush versus making 250 individual inserts).
In addition, the procedures that are used by EL (although they can certainly be modified) add overhead out of the box. For example, if WriteLog is called it *always* makes a second call to AddCategory, regardless of whether the category exists). This is a round trip call from SQL Server to the calling client since there are no triggers on insert to the Log table and there is no call to AddCategory from WriteLog. In addition, in the scenario that you end up with a category name that isn’t in the log (yet another lookup), *another* lookup and insert is performed via InsertCategoryLog. Since there are FK constraints on the tables, each insert also incurs an additional lookup behind the scenes to validate the foreign key.
Aside from this, I’ve found that log4net tends to fail gracefully whereas EL…not so much. For example, if you try to use logging, but fail to include the correct configuration, the exception will bubble up to your application. On the other hand, log4net will always trap the exception and not let it bubble up to your application and thus not raising an error where you would not expect. Sure, you could put try-catch around all of your logging statements if you’re using EL…but then, you have to ask yourself WHY?
I also forgot to mention that log4net, out of the box, allows loading of configuration files from any XML string (in application code without recompile of the source code). This means that if one were so inclined, logging configuration would be stored on a central server, downloaded, and loaded on the fly. If one were so inclined, it could be stored as embedded content with the assembly. This flexibility allows for a great variety of design scenarios out of the box.
James also has two incorrect interpretations of the facts:
- log4net is not being developed actively. Indeed, there was a looong period of inactivity on the realease side while the log4net project was going through integration with the Apache Software Foundation, but during that whole time, the mailing lists were active and so were the developers in helping users, answering questions, and certainly making todo lists for the release after incubation. I would also offer the opinion that log4net should have less releases as it is the more mature, tested, and stable of the two libraries.
- EL is somehow more extensible than log4net. This simply insn’t true as both provide the source and both provide extensive SDK documentation, samples, and examples.
Commentor Smitha Mangalore also raises an interesting point: log4net supports logging across more platforms than does EL at this point (not to mention supporting more database targets out of the box than EL).
Just my take. I think both have their place. For application event logging and tracing, nothing beats log4net in terms of performance, ease of use, ease of configuration (yes, I find the configuration to be much more concise and understandable with log4net), and overall usability.
So my interest was piqued: this whole discussion made me want to check the performance difference for myself.
So here are the test conditions:
- CPU: E6400 Core 2 Duo (2.13GHz @ 3.2GHz),
- Memory 4 GB RAM,
- Disk 1: 36GB @ 10,000 RPM
- Disk 2: 36GB @ 10,000 RPM
- Disk 3: 250GB @ 7200 RPM
- Disk 4: 74GB @ 10,000 RPM
- Test Scenario:
- The database will be dropped each before each test run.
- For EL, the default procedures and tables will be used.
- For log4net, the sample configuration and table definition will be used.
- A Stopwatch instance is created and started before the code enters a loop with 100,000 iterations. The instance is stopped as soon as it exits the loop and the result is written to the console.
- For each pass, different sets of logging commands will be commented out (in retrospect, I should have used conditional compliation symbols).
- The only listener/appender is a database listener/appender.
- EL: 138s
- log4net w/buffer = 1: 116s
- log4net w/buffer = 100: 78s
- log4net w/buffer = 250: 76s
- log4net w/buffer = 500: 78s
- Constant Work Time: 18s
So there you have it: with buffering enabled, log4net is up to nearly 2x as fast as EL.
EL has another flaw that if you are writing an assembly in .NET but called by a Win32 application, it seems impossible to configure EL to enable logging. For log4net, I can add a line in code to find the configuration XML file.