【问题标题】:Is it necessary to implement async logging for ASP.NET MVC with log4net?是否有必要使用 log4net 为 ASP.NET MVC 实现异步日志记录?
【发布时间】:2016-06-23 16:18:35
【问题描述】:

我看到了一个消息队列,类似于使用 log4net 实现的日志类。

它用于 ASP.NET MVC Web 应用程序,所以我觉得线程已经被隔离了。这种实现有什么好处?

public class Logger
{
    private ILog _logger;
    private static Logger _instance;
    private Queue<Action> _logQueue = new Queue<Action>();
    private ManualResetEvent _newItemsExist = new ManualResetEvent(false);
    private ManualResetEvent _terminate = new ManualResetEvent(false);
    private ManualResetEvent _waiter = new ManualResetEvent(false);
    private static object _syncLock = new object();

    private Thread _logThread;

    public enum LoggingType { Debug, Info, Warn, Error, Fatal };
    public Logger()
    {
        _logger = LogManager.GetLogger(
            System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        _logThread = new Thread(new ThreadStart(ProcessQueue));
        _logThread.IsBackground = true;
        _logThread.Start();
    }

    public static Logger Instance
    {
        get
        {
            if (_instance == null)
                lock (_syncLock)
                    if (_instance == null)
                        _instance = new Logger();

            return _instance;
        }
    }

    private void ProcessQueue()
    {
        while (true)
        {
            _waiter.Set();

            int i = ManualResetEvent.WaitAny(new WaitHandle[] { _newItemsExist, _terminate });
            if (i == 1) return;

            _newItemsExist.Reset();
            _waiter.Reset();

            Queue<Action> queueCopy;
            lock (_logQueue)
            {
                queueCopy = new Queue<Action>(_logQueue);
                _logQueue.Clear();
            }

            foreach (Action logAction in queueCopy)
                logAction();
        }
    }
    public void _LogMessage(string msg_, Exception inEx_, LoggingType type_)
    {
        lock (_logQueue)
            _logQueue.Enqueue(() => AsyncLogMessage(msg_, inEx_, type_));

        _newItemsExist.Set();
    }
    private void AsyncLogMessage(string msg_, Exception inEx_, LoggingType type_)
    {
        switch (type_)
        {
            case LoggingType.Debug:
                _logger.Debug(msg_, inEx_);
                break;

            case LoggingType.Info:
                _logger.Info(msg_, inEx_);
                break;

            case LoggingType.Warn:
                _logger.Warn(msg_, inEx_);
                break;

            case LoggingType.Error:
                _logger.Error(msg_, inEx_);
                break;

            case LoggingType.Fatal:
                _logger.Fatal(msg_, inEx_);
                break;
        }
    }
}

【问题讨论】:

  • 这与隔离无关。写这篇文章的人不想等待 log4net 处理消息。虽然,缓冲会减少任何延迟。不过,这段代码不是好,因为它迫使您使用硬编码的记录器(并且同样是单例!)而不是使用 log4net 的抽象。这个单例实际上打破了隔离,因为它必须在所有线程之间共享
  • 另外,.NET 4.5 有非常好的并发集合。当您可以使用 ConcurrentQueue 时,无需使用队列和锁定。该代码有一些严重的问题

标签: c# asp.net-mvc asynchronous log4net


【解决方案1】:

您不需要为log4net 实现任何异步记录器,这是一个非常好的实现,附带一个包含基准和解释必要细节的博客条目。

总而言之,异步只是问题的一半,您还需要提供批量日志记录以提高吞吐量,否则一个接一个地刷新每条日志消息会导致线程主线程出现瓶颈或其他情况。

您可以在GitHubNuGet 和博客条目HERE 上找到该库。

【讨论】:

  • 不是那个意思。我在问题中看到了单例,一个手动线程,一个带锁的队列而不是 ConcurrentQueue,我认为这个实现相当可怕。 Easy Logger 似乎创建了一个适当的异步追加器
  • 是的,我同意,OP 发布的课程有很多问题,看起来像是 hack,而不是 appender 或 forwarder 的正确实现。
  • @PanagiotisKanavos 非常感谢你们俩!博客非常直观。从这个问题中学到了很多:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-23
相关资源
最近更新 更多