On Mar 19, 2006, at 1:40 AM, Jaroslaw Kowalski wrote:
Small hint from NLog developer:
Why don't you pass the raw message with parameter placeholders,
format arguments and IFormatProvider down to the logging engine and
defer calling the actual String.Format to as late as possible?
This way you can avoid the cost of String.Format() at all if there
are filters (or whatever) which cause the message to be ignored,
while IsXXXEnabled would return true.
Since ILog.Debug and similar take an object as the message parameter,
it should be fairly easy to construct an object from the
IFormatProvider and parameters and overload ToString() to call
IFormatProvider.Format. I didn't pursue that optimization with the
log4j sandbox effort, though I didn't preclude it either.
One thing that you need to be aware of is the possible reentrancy
problem, since format arguments may be objects which override
ToString() and which do the logging inside this method. Things can
get weird if you call logging code in the middle of logging (mostly
because of locking and thread-locality issues), but this is
something that can be quite easily sorted out.
I'm not sure if this can be easily done in log4net, though.
Those have been issues when passing non-String messages with log4j.
Ideally, ToString() would be called before acquiring any significant
locks and before handing the event off to another thread.
On Mar 19, 2006, at 11:12 AM, Nicko Cadell wrote:
It is also worth mentioning that, unlike log4j, in log4net the user
does
not interact with the Logger directly but with a wrapper. The Logger
(ILogger) has a Log method that is used to log all the messages. The
wrapper LogImpl (implements ILog) has all the Debug/Info/Warn/Error
methods which forward the log call to the Logger method. The LogImpl
contains the Format methods. If a use wants a different format
implementation they can write their own wrapper with user callable
methods.
Nicko
I've quickly reviewed the log4net source code. One of the design
concerns in the log4j sandbox effort was avoiding array creation or
boxing costs for requests that were below the threshold. The
ILog.DebugFormat and similar methods would appear to incur boxing and
array creation cost even if the message was below the threshold. In
performance testing on Java, those costs were non-trivial. Ideally,
you would like the cost of a below threshold log request to be only
the cost of logger.IsEnabledFor and to have that cost as small as
possible.
You do have that advantage of having a common interface in
IFormatProvider which isn't the case in case with
java.text.MessageFormat and java.util.Formatter. So you may be able
to avoid the cut-and-paste madness of the sandbox implementation if
you want to support multiple formatters.
The sandbox effort also tries to perform some optimizations that may
not be beneficial on .NET. For example, evaluating a simple pattern
with only plain substitutions is can be done faster than calling
MessageFormat.format. The optimizations should be transparent to the
user and do not need to be replicated in a .NET implementation if
they do not offer a benefit.
I do like the distinct static class approach, it separates the
logging function from the formatting function but still allows the
short-circuiting and other performance optimizations that motivated
combining them.