我的自定义 Log4net 异步故障转移附加程序跳过消息
My Custom Log4net Asynch Failover Appender Skips Messages
我正在尝试为 Log4net
编写异步 Failover Appender
。我快到了,但有一些小问题。
appender 需要尝试登录到我们的内部 Web 服务,然后,如果失败,则写入文件。
- Web 服务工作得很好......每次都是。
- 故障转移到文件丢失消息
这是我需要帮助的地方...
症状:
- 我的测试控制台应用程序显示了所有消息(请参阅下面的附件照片)
- 但是当故障转移激活时,一些或许多消息不会附加到文件中
我的附加程序代码如下所示:
最终,我将动态解析客户端,但现在...
namespace Testing.Appenders
{
using log4net.Appender;
using log4net.Core;
using System;
using System.IO;
using System.ServiceModel;
using System.Threading.Tasks;
using wsEventManager;
public class AsynchWebServiceFailoverAppender : AppenderSkeleton
{
#region <Properties>
public string ServiceUrl { get; set; }
public string File { get; set; }
#endregion
#region <Methods>
#region protected
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("LoggingEvent");
if (string.IsNullOrEmpty(File))
throw new ArgumentNullException("File");
if (string.IsNullOrEmpty(ServiceUrl))
throw new ArgumentNullException("ServiceUrl");
Task.Factory.StartNew(() =>
{
var uri = new Uri(ServiceUrl);
var myBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var endpoint = new EndpointAddress(uri);
var client = new EventManagerSoapClient(myBinding, endpoint);
var eventType = GetEventType(loggingEvent);
var log = GetEvent(eventType);
client.Log(log);
client.Close();
client = null;
})
.ContinueWith(task =>
{
using (var streamWriter = new StreamWriter(File, true))
{
using (var textWriter = TextWriter.Synchronized(streamWriter))
{
textWriter.WriteLine(base.RenderLoggingEvent(loggingEvent));
textWriter.FlushAsync();
}
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
#endregion
#endregion
}
}
我的配置有效,但这里是:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="WebServiceFailoverAppender" type="Testing.Appenders.AsynchWebServiceFailoverAppender , Testing">
<ServiceUrl value="http://localhost/DiagnosticsWeb/BadUrl.asmx" />
<file value="C:\Logs\Support\Diagnostics.Appender\log4net.log" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="<%level date="%date{MM-dd-yyyy}" time="%date{h:mm:ss tt}" file="%class" thread="%thread">%message</%level>%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="WebServiceFailoverAppender" />
</root>
</log4net>
</configuration>
结果:
- 5 条消息被发送到控制台进行记录
- 只记录了 2 条消息
如果您正在使用 asynchronous
调用,您应该等待它们,否则,当您离开 scope
时,它可能无法完成。
我的猜测是 flush
确实会对您遇到的这种竞争状况产生任何影响。
要解决此问题,您应该 await
flush
。在您的 task
延续中,我将介绍 await async
架构:
ContinueWith(async task =>
{
using (var streamWriter = new StreamWriter(File, true))
{
using (var textWriter = TextWriter.Synchronized(streamWriter))
{
textWriter.WriteLine(base.RenderLoggingEvent(loggingEvent));
await textWriter.FlushAsync();
}
}
}, TaskContinuationOptions.OnlyOnFaulted);
如果有效,请告诉我。
写入文件时存在竞争条件。您的 TextWriter.Synchronized
没有效果,因为您每次都创建新的编写器,并且创建此构造是为了将写入同步到 TextWriter
的单个实例。要验证尝试锁定整个文件写入块。如果您想以即发即弃的异步方式从多个线程写入单个日志文件 - 请参阅我的其他答案 .
我正在尝试为 Log4net
编写异步 Failover Appender
。我快到了,但有一些小问题。
appender 需要尝试登录到我们的内部 Web 服务,然后,如果失败,则写入文件。
- Web 服务工作得很好......每次都是。
- 故障转移到文件丢失消息
这是我需要帮助的地方...
症状:
- 我的测试控制台应用程序显示了所有消息(请参阅下面的附件照片)
- 但是当故障转移激活时,一些或许多消息不会附加到文件中
我的附加程序代码如下所示:
最终,我将动态解析客户端,但现在...
namespace Testing.Appenders
{
using log4net.Appender;
using log4net.Core;
using System;
using System.IO;
using System.ServiceModel;
using System.Threading.Tasks;
using wsEventManager;
public class AsynchWebServiceFailoverAppender : AppenderSkeleton
{
#region <Properties>
public string ServiceUrl { get; set; }
public string File { get; set; }
#endregion
#region <Methods>
#region protected
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("LoggingEvent");
if (string.IsNullOrEmpty(File))
throw new ArgumentNullException("File");
if (string.IsNullOrEmpty(ServiceUrl))
throw new ArgumentNullException("ServiceUrl");
Task.Factory.StartNew(() =>
{
var uri = new Uri(ServiceUrl);
var myBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var endpoint = new EndpointAddress(uri);
var client = new EventManagerSoapClient(myBinding, endpoint);
var eventType = GetEventType(loggingEvent);
var log = GetEvent(eventType);
client.Log(log);
client.Close();
client = null;
})
.ContinueWith(task =>
{
using (var streamWriter = new StreamWriter(File, true))
{
using (var textWriter = TextWriter.Synchronized(streamWriter))
{
textWriter.WriteLine(base.RenderLoggingEvent(loggingEvent));
textWriter.FlushAsync();
}
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
#endregion
#endregion
}
}
我的配置有效,但这里是:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="WebServiceFailoverAppender" type="Testing.Appenders.AsynchWebServiceFailoverAppender , Testing">
<ServiceUrl value="http://localhost/DiagnosticsWeb/BadUrl.asmx" />
<file value="C:\Logs\Support\Diagnostics.Appender\log4net.log" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="<%level date="%date{MM-dd-yyyy}" time="%date{h:mm:ss tt}" file="%class" thread="%thread">%message</%level>%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="WebServiceFailoverAppender" />
</root>
</log4net>
</configuration>
结果:
- 5 条消息被发送到控制台进行记录
- 只记录了 2 条消息
如果您正在使用 asynchronous
调用,您应该等待它们,否则,当您离开 scope
时,它可能无法完成。
我的猜测是 flush
确实会对您遇到的这种竞争状况产生任何影响。
要解决此问题,您应该 await
flush
。在您的 task
延续中,我将介绍 await async
架构:
ContinueWith(async task =>
{
using (var streamWriter = new StreamWriter(File, true))
{
using (var textWriter = TextWriter.Synchronized(streamWriter))
{
textWriter.WriteLine(base.RenderLoggingEvent(loggingEvent));
await textWriter.FlushAsync();
}
}
}, TaskContinuationOptions.OnlyOnFaulted);
如果有效,请告诉我。
写入文件时存在竞争条件。您的 TextWriter.Synchronized
没有效果,因为您每次都创建新的编写器,并且创建此构造是为了将写入同步到 TextWriter
的单个实例。要验证尝试锁定整个文件写入块。如果您想以即发即弃的异步方式从多个线程写入单个日志文件 - 请参阅我的其他答案