如何为 log4net 创建异步包装器?

发布于 2024-11-29 17:25:37 字数 59 浏览 1 评论 0原文

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

By default, log4net is a synchronous logging mechanism, and I was wondering if there was a way to have asynchronous logging with log4net?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

度的依靠╰つ 2024-12-06 17:25:37

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

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

请注意,我没有使用过这些示例中的任何一个,因此我无法以某种方式为它们提供保证。

以下是代码存储库中 log4net 示例区域中实际异步附加程序的链接:

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 列表。

If you go to the log4net website, you can find some examples, at least one of which is an asynchronous Appender.

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

Note that I have not used any of these examples, so I cannot vouch for them one way or the other.

Here is a link to the actual asynchronous appender from the log4net Examples area in their code repository:

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

I looked at it briefly, and it apparently acts as a wrapper around one or more "conventional" Appenders. On each logging request (containing one or more LoggingEvent objects), a ThreadPool thread is used to forward the LoggingEvents to the list of wrapped Appenders.

假扮的天使 2024-12-06 17:25:37

只是想提供我的完整解决方案供参考。有几个重要的项目,FixFlags 可让您捕获实际执行日志记录的线程。阻塞集合位于 ReactiveExtensions 中。这里的要点是,您的转发附加器处理异步内容,然后将 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);
            }
        }
    }
}

然后,在 log4net.xml 中设置附加程序

<!-- 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>

更新:

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

那么您需要更新上面的代码,例如

loggingEvent.Fix = FixFlags.All;

Just wanted to provide my complete solution for reference. Couple of important items, the FixFlags let you capture the thread that's actually doing the logging. The Blocking Collection is in the ReactiveExtensions. The jist here is that your forwarding appender handles the Asynchronous stuff and then just forwards on the LoggingEvent to a standard Log4Net appender, which lets Log4Net do all of the things that it's good at. No re-inventing the wheel.

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

Then, in your log4net.xml you setup the appenders thusly

<!-- 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>

Update:

If you want to use context in log4net like "log4net.ThreadContext.Properties["CustomColumn"]"

Then you need to update above code like

loggingEvent.Fix = FixFlags.All;
风吹雪碎 2024-12-06 17:25:37

我就是这样做的:

Task.Factory.StartNew(() => log.Info("My Info"));

这样 log4net 在单独的线程上异步执行日志记录...

顺便说一句,Task 类位于 System.Threading.Tasks 命名空间中。

This is how I do it:

Task.Factory.StartNew(() => log.Info("My Info"));

That way log4net performs logging on a separate thread, asynchronously...

BTW, Task class is in System.Threading.Tasks namespace.

清浅ˋ旧时光 2024-12-06 17:25:37

这里的一些想法是不正确的,会导致无效/过时的数据、无序的日志记录或非常糟糕的性能。例如,接受的答案建议使用 log4net AsyncAppender ,它使用 ThreadPool 导致无序条目,这对某些人来说可能不是问题,但我当然希望我的日志事件如果一个接一个地执行,它也会产生糟糕的性能,并对线程池造成太大压力,而且它不会批量处理日志条目。乔纳森提出的答案当然是一个更好的解决方案,但仍然缺乏最佳性能。

关于如何实现这一点的一个很好的例子可以在这里找到,以及基准测试结果和解释< a href="http://www.nimaara.com/2016/01/01/high-performance-logging-log4net/" rel="noreferrer">此处。

该解决方案的另一个好特性是,它已实现为 Forwarder 而不是 Appender,允许用户包含多个 Appender 并记录同时向他们每个人发送。

Some of the ideas here are incorrect and result in invalid/stale data, out of order logging or very bad performance. For instance the accepted answer suggests using the log4net AsyncAppender which uses the ThreadPool resulting in out of order entries which might not be a problem for some but I certainly want my log events to be one after another it also can have terrible performance and put too much strain on the ThreadPool also it does not batch the log entries. The answer suggested by Jonathan is certainly a much better solution but still lacks optimal performance.

A good example of how this should be implemented can be found HERE and the benchmarking results and the explanation HERE.

Another good feature of this solution is that it has been implemented as a Forwarder not an Appender allowing the user to include more than one Appender and log to each of them at the same time.

吃→可爱长大的 2024-12-06 17:25:37

我本周遇到了这个问题,但是我不想继续向线程池发出请求,因为它最终可能会导致线程应用程序的其余部分挨饿,因此我想出了一个异步附加程序,它运行一个专用线程来附加通过缓冲器馈送。在这里查看:https://github.com/cjbhaines/Log4Net.Async

I came across this problem this week however I did not want to keep firing requests off to the thread pool because it could end up starving the rest of the application of threads so I came up with an Asyncronous appender that runs a dedicated thread for appending which is fed through a buffer. Check it out here: https://github.com/cjbhaines/Log4Net.Async

可爱咩 2024-12-06 17:25:37

https://github.com/cjbhaines/Log4Net.Async

我们现在提供异步 log4net 方法。对于正在寻找更新答案的人。

https://www.nuget.org/packages/Log4Net.Async/

https://github.com/cjbhaines/Log4Net.Async

We have asynchronous log4net methods available now. For the people who are looking for updated answers.

https://www.nuget.org/packages/Log4Net.Async/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文