默认情况下,log4net是一种同步日志记录机制,我想知道是否有办法使用log4net进行异步日志记录?
答案 0 :(得分:13)
如果你去log4net网站,你可以找到一些例子,其中至少有一个是异步Appender。
http://logging.apache.org/log4net/release/example-apps.html
请注意,我没有使用过任何这些例子,所以我不能以某种方式担保。
以下是代码库中log4net Examples区域的实际异步appender的链接:
我简单地看了一眼,它显然是一个或多个“常规”Appender的包装器。在每个日志记录请求(包含一个或多个LoggingEvent对象)上,ThreadPool线程用于将LoggingEvents转发到包装的Appender列表。
答案 1 :(得分:13)
只是想提供我的完整解决方案供参考。一些重要的项目,FixFlags让你捕获实际进行日志记录的线程。阻止集合位于ReactiveExtensions中。这里的要点是你的转发appender处理异步的东西,然后只是将LoggingEvent转发到标准的Log4Net appender,这让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中你设置了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>
<强>更新强>
如果您想在log4net中使用上下文,例如“log4net.ThreadContext.Properties["CustomColumn"]
”
然后你需要更新上面的代码,如
loggingEvent.Fix = FixFlags.All;
答案 2 :(得分:11)
我就是这样做的:
Task.Factory.StartNew(() => log.Info("My Info"));
这样log4net就可以异步执行单独的线程...
BTW,Task
类位于System.Threading.Tasks
名称空间中。
答案 3 :(得分:7)
此处的一些想法不正确,导致无效/陈旧数据,乱序记录或性能非常差。例如,接受的答案建议使用log4net AsyncAppender
使用ThreadPool
导致无序条目,这可能不是一些问题,但我当然希望我的日志事件是一个接一个,它也可能会有糟糕的表现,并对ThreadPool
施加太多压力,也不会批量记录日志条目。乔纳森提出的答案肯定是一个更好的解决方案,但仍缺乏最佳表现。
此解决方案的另一个优点是它已被实现为Forwarder
而不是Appender
,允许用户包含多个Appender
并在其中记录每个.not()
同一时间。
答案 4 :(得分:5)
本周我遇到了这个问题,但是我不想继续向线程池发送请求,因为它最终会使线程应用程序的其余部分挨饿,所以我想出了一个运行专用线程的Asyncronous appender用于追加通过缓冲区馈送的。请在此处查看:https://github.com/cjbhaines/Log4Net.Async
答案 5 :(得分:0)
https://github.com/cjbhaines/Log4Net.Async
我们现在有异步log4net方法可用。对于正在寻找最新答案的人。