如何为log4net创建异步包装?

Jon*_*ter 30 c# log4net

默认情况下,log4net是一种同步日志记录机制,我想知道是否有办法使用log4net进行异步日志记录?

wag*_*ghe 13

如果你去log4net网站,你可以找到一些例子,其中至少有一个是异步Appender.

http://logging.apache.org/log4net/release/example-apps.html

请注意,我没有使用这些示例中的任何一个,所以我不能以某种方式保证它们.

以下是来自其代码存储库中log4net Examples区域的实际异步appender的链接:

http://svn.apache.org/viewvc/logging/log4net/trunk/examples/net/2.0/Appenders/SampleAppendersApp/cs/src/Appender/AsyncAppender.cs?view=markup

我简单地看了一下,它显然是一个或多个"常规"Appender的包装器.在每个日志记录请求(包含一个或多个LoggingEvent对象)上,ThreadPool线程用于将LoggingEvents转发到包装的Appender列表.


Jon*_*ter 13

只是想提供我的完整解决方案供参考.一些重要的项目,FixFlags让你捕获实际进行日志记录的线程.阻止集合位于ReactiveExtensions中.在这里JIST是你转发的appender处理异步的东西,然后就转发在LoggingEvent所为标准log4net的附加器,它可以让log4net的做所有的事情,它的擅长.没有重新发明轮子.

/// <summary>
/// Provides an extension for the log4net libraries to provide ansynchronous logging capabilities to the log4net architecture
/// </summary>
public class AsyncLogFileAppender : log4net.Appender.ForwardingAppender
{
    private static int _asyncLogFileAppenderCount = 0;
    private readonly Thread _loggingThread;
    private readonly BlockingCollection<log4net.Core.LoggingEvent> _logEvents = new BlockingCollection<log4net.Core.LoggingEvent>();

    protected override void Append(log4net.Core.LoggingEvent loggingEvent)
    {
        loggingEvent.Fix = FixFlags.ThreadName;
        _logEvents.Add(loggingEvent);
    }

    public AsyncLogFileAppender()
    {

        _loggingThread = new Thread(LogThreadMethod) { IsBackground = true, Name = "AsyncLogFileAppender-" + Interlocked.Increment(ref _asyncLogFileAppenderCount), };
        _loggingThread.Start();
    }

    private void LogThreadMethod()
    {
        while (true)
        {
            LoggingEvent le = _logEvents.Take();
            foreach (var appender in Appenders)
            {
                appender.DoAppend(le);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在log4net.xml中,您可以设置appender

<!-- Standard form output target location and form -->
<appender name="StandardAppender" type="TSUIC.Logging.AsyncLogFileAppender">
<appender-ref ref="StandardAppenderSync" />
</appender>

<appender name="StandardAppenderSync" type="log4net.Appender.RollingFileAppender">
    <!-- The standard pattern layout to use -->
    <file value="log\Log_" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="-1" />
    <maximumFileSize value="5GB" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <staticLogFileName value="false" />
    <datePattern value="yyyyMMdd'.txt'" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
</appender>
Run Code Online (Sandbox Code Playgroud)

更新:

如果你想在log4net中使用上下文,如" log4net.ThreadContext.Properties["CustomColumn"]"

然后你需要更新上面的代码

loggingEvent.Fix = FixFlags.All;
Run Code Online (Sandbox Code Playgroud)


Dea*_*uga 11

我是这样做的:

Task.Factory.StartNew(() => log.Info("My Info"));
Run Code Online (Sandbox Code Playgroud)

这样log4net就可以异步执行单独线程的日志记录......

BTW,Task类在System.Threading.Tasks命名空间中.

  • 这是*危险的*特别是在ASP.net应用程序中http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html (4认同)
  • 这是一个非常糟糕的主意,不仅需要"修复"线程名称,消息和异常,而且日志条目将不按顺序保留. (3认同)
  • @Dean不幸的是,由于使用了"ThreadPool",该解决方案也不正确导致无序条目再次出现.吞吐量也很糟糕. (3认同)
  • 这比使用AsyncAppender效率低得多. (2认同)

MaY*_*YaN 7

这里的一些想法是不正确的,导致无效/陈旧数据,乱序记录或非常糟糕的性能.例如,接受的答案建议使用log4net AsyncAppender,它使用ThreadPool导致无序的条目,这可能不是一些问题,但我当然希望我的日志事件是一个接一个,它也可能有可怕的性能,并施加太大的压力该ThreadPool还它不批日志条目.Jonathan建议的答案肯定是一个更好的解决方案,但仍然缺乏最佳性能.

的这个应该怎么实现一个很好的例子可以发现这里和基准测试结果和解释这里.

该解决方案的另一个很好的功能是,它已经被实现为Forwarder不是Appender允许用户包括不止一个Appender,并登录到他们每个人在同一时间.


Chr*_*nes 5

我本周遇到了这个问题,但是我不想继续向线程池发送请求,因为它最终会使线程应用程序的其余部分挨饿,所以我想出了一个Asyncronous appender,它运行一个专用线程来追加哪个通过缓冲区喂养.在这里查看:https://github.com/cjbhaines/Log4Net.Async