记录框架和多线程兼容性

时间:2011-02-16 20:44:49

标签: .net multithreading logging log4net nlog

请注意,我在SO上看到了这些问题(讨论了log4net的线程安全性),我怀疑他们回答了我的问题,但我还是会问:

Multithread safe logging

Log4Net FileAppender not thread safe?

最近我写了一个用于日志记录的WCF服务。这个想法与Clog(或look for Clog under Calcium)非常相似。基本上,我已经实现了一个用于Silverlight客户端(Silverlight类库)的日志API。日志记录API或多或少是我们在应用程序中其他地方使用的Common.Logging for .NET API的克隆。 API的实现将所有日志消息转发到WCF日志服务,该服务本身是以Common.Logging实现的。

在看Clog时,我发现Log4NetStrategy类中的以下代码让我觉得有些奇怪:

/// <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(以及NLog和EnterpriseLibrary的策略)实现了一个具有Write(ILogEntry logEntry)方法的接口。 ILogEntry本质上是Clog日志服务从客户端收到的DTO。提取logEntry中的信息并用于创建log4net LoggingEvent。还将根据ILogEntry DTO中的记录器名称检索相应的log4net记录器。创建log4net LoggingEvent后,它和记录器将被发送到上面的WriteThreadSafe方法并通过log4net记录。 NLog和EnterpriesLibrary实现类似。

在伪代码中,Clog日志服务上的“Write”方法如下所示:

// 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);
}

所以这是我的问题...通常log4net(和NLog,我认为,EnterpriseLibrary)被认为是多线程兼容的。也就是说,公共API的用户可以简单地调用log.Info,log.Log等,而不用担心在多线程环境中运行。日志记录框架应该确保日志记录调用(以及日志记录调用中的任何处理)都是线程安全的。

如果日志框架是多线程兼容的,则使用

[MethodImpl(MethodImplOptions.Synchronized]

属性真的需要吗?看起来这会(或可能)通过强制同步处理所有日志消息来导致瓶颈,即使底层日志框架应该能够处理多线程环境中的日志记录。

对于我的日志记录服务(可能是多线程的),似乎不需要像这样同步调用。看起来我应该能够从服务调用中获取日志记录输入,构建适当的日志记录结构(基于底层日志记录框架),然后记录它。如果我的日志服务是多线程的,它应该“正常工作”,因为底层日志框架应该支持它(多线程)。

这有意义吗?是否真的需要显式同步日志记录调用(至少对于log4net和NLog)?

1 个答案:

答案 0 :(得分:5)