我已经实现了一个写入http服务的自定义log4net appender ......效果很好,但我脑子里有一些过早的优化。具体来说,有更好的方法吗?我想我可以确保只有关键类具有特定的投射,但感觉即使使用保守的日志记录选项,也可能存在大量的追加者和责任。
有没有人有他们想分享的经验?我看过http://geekswithblogs.net/michaelstephenson/archive/2014/01/02/155044.aspx这本质上就是我在做什么......(见代码)这样的规模有多好?我喜欢单身人士的工厂......如何实现并发队列来缓冲写入?
希望管理员因为询问(可能是意见)最佳实践问题而不会打得太猛烈。
(从文章中添加代码以便澄清)
public class ServiceBusAppender : AppenderSkeleton
{
public string ConnectionStringKey { get; set; }
public string MessagingEntity { get; set; }
public string ApplicationName { get; set; }
public string EventType { get; set; }
public bool Synchronous { get; set; }
public string CorrelationIdPropertyName { get; set; }
protected override void Append(log4net.Core.LoggingEvent loggingEvent)
{
var myLogEvent = new AzureLoggingEvent(loggingEvent);
myLogEvent.ApplicationName = ApplicationName;
myLogEvent.EventType = EventType;
myLogEvent.CorrelationId = loggingEvent.LookupProperty(CorrelationIdPropertyName) as string;
if (Synchronous)
AppendInternal(myLogEvent, 0);
else
{
Task.Run(() => AppendInternal(myLogEvent, 0));
}
}
protected void AppendInternal(AzureLoggingEvent myLogEvent, int attemptNo)
{
try
{
//Convert event to JSON
var stream = new MemoryStream();
var json = Newtonsoft.Json.JsonConvert.SerializeObject(myLogEvent);
var writer = new StreamWriter(stream);
writer.Write(json);
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
//Setup service bus message
var message = new BrokeredMessage(stream, true);
message.ContentType = "application/json";
message.Label = myLogEvent.MessageType;
message.Properties.Add(new KeyValuePair<string, object>("ApplicationName", myLogEvent.ApplicationName));
message.Properties.Add(new KeyValuePair<string, object>("UserName", myLogEvent.UserName));
message.Properties.Add(new KeyValuePair<string, object>("MachineName", myLogEvent.MachineName));
message.Properties.Add(new KeyValuePair<string, object>("MessageType", myLogEvent.MessageType));
message.Properties.Add(new KeyValuePair<string, object>("Level", myLogEvent.Level));
message.Properties.Add(new KeyValuePair<string, object>("EventType", myLogEvent.EventType));
//Setup Service Bus Connection
var connection = ConfigurationManager.ConnectionStrings[ConnectionStringKey];
if (connection == null || string.IsNullOrEmpty(connection.ConnectionString))
{
ErrorHandler.Error("Cant publish the error, the connection string does not exist");
return;
}
var factory = MessagingFactoryManager.Instance.GetMessagingFactory(connection.ConnectionString);
var sender = factory.CreateMessageSender(MessagingEntity);
//Publish
sender.Send(message);
}
catch (Exception ex)
{
if (ex.Message.Contains("The operation cannot be performed because the entity has been closed or aborted"))
{
if (attemptNo < 3)
AppendInternal(myLogEvent, attemptNo++);
else
ErrorHandler.Error("Error occured while publishing error", ex);
}
else
ErrorHandler.Error("Error occured while publishing error", ex);
}
}
protected override void Append(log4net.Core.LoggingEvent[] loggingEvents)
{
foreach(var loggingEvent in loggingEvents)
{
Append(loggingEvent);
}
}
THX,
克里斯
答案 0 :(得分:1)
过早优化的方法是测试和测量,然后再次测试和测量。编写一个集成测试,记录到一千个记录器,看看情况如何。
如果确实显示问题,那么不是实现自己的队列,而是继承BufferingAppenderSkeleton:
这个基类应该由需要缓冲a的appender使用 记录之前的事件数。例如AdoNetAppender 缓冲事件然后提交缓冲区的全部内容 一次性使用底层数据库。
子类应覆盖SendBuffer方法以提供 缓冲事件。
BufferingAppenderSkeleton维护固定大小的事件循环缓冲区。使用BufferSize属性设置缓冲区的大小。
(顺便说一下, >使用log4net文档时,每次看到它时,似乎都会有更多'½ï¿'字符?)
答案 1 :(得分:0)
我看到你的代码涉及JSON序列化。如果您正在寻找log4net JSON,为什么要重做已经完成的工作?见log4net.ext.json。 我是开发者。关于如何启动和运行的wiki covers the first steps。它用于代替布局,因此可以插入任何采用布局的log4net appender。
我的项目的一部分我还为log4net创建了一个负载测试GUI。它没有发布,但它应该很容易从源代码编译。您可以使用它来发现不同配置在您的条件下如何缩放。
最后,如果性能优先,我建议给LOCALHOST UDP发送一次。像nxlog或logstash这样的项目可以很容易地吞下它。再次,为什么要编写新代码?
如果您需要澄清,请告诉我。亲切的问候和好运,Rob