Note that I have seen these questions here on SO (which discuss the thread safety of log4net) and I suspect that they answer my question, but I am going to ask anyway:
Log4Net FileAppender not thread safe?
Recently I have written a WCF service for logging. The idea is very similar to Clog (or look for Clog under Calcium). Basically, I have implemented a logging API for use in a Silverlight client (a Silverlight class library). The logging API is, more or less, a clone of the Common.Logging for .NET API which we are using elsewhere in our application. The implementation of the API forwards all logging messages to a WCF logging service that, itself, is implemented in terms of Common.Logging.
While looking at Clog I found the following code in the Log4NetStrategy
class that struck me as a little bit odd:
/// <summary>
/// All Write log calls are done asynchronously because the DanielVaughan.Logging.Log
/// uses the AppPool to dispatch calls to this method. Therefore we need to ensure
/// that the call to Log is threadsafe. That is, if an appender such as FileAppender is used,
/// then we need to ensure it is called from no more than one thread at a time.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="loggingEvent">The logging event.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
static void WriteThreadSafe(ILogger logger, LoggingEvent loggingEvent)
{
logger.Log(loggingEvent);
}
Log4NetStrategy
(and the strategies for NLog and EnterpriseLibrary as well) implements an interface that has a method like Write(ILogEntry logEntry). ILogEntry is essentially the DTO that the Clog logging service received from the client. The information from the logEntry is extracted and used to create a log4net LoggingEvent. The appropriate log4net logger is also retrieved based on the logger name in the ILogEntry DTO. After the log4net LoggingEvent is created, it and the logger are sent to the WriteThreadSafe method above and logged via log4net. The NLog and EnterpriesLibrary implementations are similar.
In pseudocode, the "Write" method on the Clog logging service looks something like this:
// Write on the logging service
// Send the input log entry to each configured strategy.
public void Write(ILogEntry logEntry)
{
foreach (ILoggingStrategy ls in loggingStrategies)
{
ls.Write(logEntry);
}
}
// Write on the Log4NetStrategy
// Convert the logEntry to log4net form and log with log4net
public void Write(ILogEntry logEntry)
{
log4net.LoggingEvent le = ConvertToLoggingEvent(logEntry);
ILog logger = log4net.GetLogger(logEntry.Logger);
WriteThreadSafe(logger, le);
}
So here is my question... Generally log4net (and NLog and, I assume, EnterpriseLibrary) are considered to be multithread compatible. That is, the user of the public API can simply call log.Info, log.Log, etc and not be concerned about running in a multithreaded environment. The logging framework should take care of ensuring that the logging calls (and any processing within the logging calls) are threadsafe.
If the logging frameworks are multithread compatible, then is the use of the
[MethodImpl(MethodImplOptions.Synchronized]
attribute really needed? It seems like this would (or could) just cause a bottleneck by forcing all logging messages to be handled synchronously, even though the underlying logging framework should be able to handle logging in a multhithreaded environment.
In the case of my logging service (which could be multithreaded), it doesn't seem like it would be necessary to synchronize the calls like this. It seems like I should be able to take my logging input from the service call, construct the appropriate logging structure (based on the underlying logging framework), and just log it. If my logging service is multithreaded, it should "just work" because the underlying logging framework should support it (multithreading).
Does this make sense? Is the explicit synchronization of logging calls (at least for log4net and NLog) really necessary?