log4net实现细节 - 自定义appender

时间:2014-11-25 22:46:12

标签: c# log4net

我已经实现了一个写入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,

克里斯

2 个答案:

答案 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