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.




Reply via email to