One solution to the last 5 of those bottle necks would be to write a
RoutingTable:ILoggerRepository. The Hierarchy:ILoggerRepository is the
default implementation that comes with log4net. The hierarchy
implementation most likely came from log4j.
When you started writing NLog, did you investigate the possibility of
writing a routing table based ILoggerRepository and re-using the
existing Appender, Filter, etc. code?
Assuming there was a RoutingTable Repository for log4net, here's what
the two system's config files might look like:
I don't know how useful this would be...but I think its possible to
write a NLogRepository:ILoggerRepository to replace log4net's Hierarchy
implementation. Similiar to how MySql allows for interchangable storage
engines: InnoDB, MyISAM, etc. I think such a class would be a solution
for a problem that doesn't really exist. Either choose a logging
package and build your project against that or use some abstract
factory to instanciate your logger at run-time.
> I suspect that the remaining cost of log4net call is the cost of
> things that
> make up ILog.IsDebugEnabled
> - interface method dispatch from ILog to LogImpl
> - virtual method call from LogImpl.Debug to IsDebugEnabled()
> - virtual method call to get LoggerWrapperImpl.Logger
> - interface method call to Repository.Hierarchy.Logger.IsEnabledFor()
> - a call to Repository.Hierarchy.IsDisabled which isn't inlined
> - a comparison in Repository.Hierarchy.IsDisabled ((object)level ==
> which fails in 99% cases
> - a comparison which succeeds in 99% cases (if (Configured))
> - a virtual method call to Repository.Hierarchy.Logger.EffectiveLevel
> - a loop in Logger.EffectiveLevel - why don't you cache the result?
> So log4net has:
> - 2 interface method dispatches
> - 3 virtual method calls,
> - some code which is unneeded in 99% cases
> - a loop(!)
> Compare this to (more or less) a simple boolean comparison that's
> used in
> When you started writing NLog, did you investigate the possibility of
> writing a routing table based ILoggerRepository and re-using the
> existing Appender, Filter, etc. code?
I started NLog because I was totally frustrated with the way log4net
configuration was done and I didn't even bother studying the code, because
at the first glance it was too abstract for me. I only wanted to to the
logging. The idea of ultimate extensibility at the cost of high code
complexity is something I don't buy.
I never reused any appender code because I had totally different ideas of
what should be default behaviour (like locking the files vs enabling
multiple processes to simultaneously write to them) + because of the
almost-everything-is-a-layout approach that NLog is taking.
Logger hierarchy may be good to programmers and enterprise management tools,
but it's not well understood by untrained support people/lazy developers who
are not willing to learn. Most people I know only want to have one or three
rules which are directly expressible in NLog but which are quite difficult
to express in log4net (because you have to use filters and stuff...). I
believe that in such scenarios, routing table is easier to read and
> I don't know how useful this would be...but I think its possible to
> write a NLogRepository:ILoggerRepository to replace log4net's Hierarchy
> implementation. Similiar to how MySql allows for interchangable storage
> engines: InnoDB, MyISAM, etc. I think such a class would be a solution
> for a problem that doesn't really exist. Either choose a logging
> package and build your project against that or use some abstract
> factory to instanciate your logger at run-time.
I don't believe that over-abstracting things is good.
Every time I hear another "abstract factory", I direct people to this: