2014-11-25 3 views
1

Я внедрил пользовательское приложение log4net, которое пишет в службу http ... хорошо работает, но у меня есть некоторая преждевременная оптимизация в моей голове. В частности, есть ли лучший способ сделать это? Наверное, я могу убедиться, что только критические классы имеют этот конкретный apprender, но похоже, что может быть много приложений и ответственности даже с консервативными вариантами ведения журнала.log4net подробности реализации - пользовательский appender

У кого-нибудь есть опыт, который они хотели бы поделиться? Я посмотрел на http://geekswithblogs.net/michaelstephenson/archive/2014/01/02/155044.aspx, который по сути является тем, что я делаю ... (см. Код). Насколько хорошо что-то похожее на этот масштаб? Мне нравится фабрика для singleton ... как насчет реализации параллельной очереди для буферизации записей?

Надеюсь, я не буду слишком сильно отрываться от администратора, чтобы задать вопрос о потенциальном мнении.

(добавление кода из статьи разъяснений)

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,

Chris

+0

Лучший способ сделать что конкретно? Не дайте нам ссылку на «в основном то, что вы делаете», поставьте блок кода в свой вопрос, показывая нам, что вы делаете. –

+0

хорошо, ради обсуждения используйте этот код. Я хочу знать, как он масштабируется ... log4net собирается развернуть еще одно приложение для каждого класса, настроенного для этого. Я не знаю, что имеет смысл иметь кучу http-клиентов (по одному на каждого приложения), похоже на ответственность. Помните, я сказал, что знаю, что это преждевременная оптимизация ... Мне интересно, как люди делятся своим опытом с подобными решениями. –

ответ

1

Лечение преждевременной оптимизации является тестирование и измерение, а затем испытания и измерения снова. Напишите тест интеграции, который регистрируется до тысячи регистраторов, и посмотрите, как это происходит.

Если это действительно показывает проблему, а не реализовать свою собственную очередь, наследовать от BufferingAppenderSkeleton вместо:

Этого базовый класс должен использоваться appenders, которые должны буфером количества событий перед входом их , Например, AdoNetAppender буферизует события, а затем передает все содержимое буфера в базовую базу данных за один раз.

Подклассы должны переопределять метод SendBuffer для доставки буферизированных событий .

BufferingAppenderSkeleton поддерживает циклический буфер событий фиксированного размера. Размер буфера устанавливается с использованием свойства BufferSize.

(Как и в сторону, то, что является с документацией log4net, кажется, есть более символов «½ï¿» каждый раз, когда я смотрю на это?)

+0

Я думал, что это только я видел это, и мой заблокированный браузер на работе ... java docs выглядят отлично, просто .net docs. Weird.Thx для подсказки о тестировании ... Я в основном хотел начать обсуждение и посмотреть, что встретили другие. Тем не менее, я пропустил класс BufferingAppenderSkeleton - спасибо. –

+0

@ChrisKeller Если вы не делаете что-то действительно странное, легко изменить курс в log4net, так как классы обычно изолированы; переход от отдельных клиентов-клиентов к общим не должен быть проблемой вообще, если вы когда-либо видите, что это вызывает проблемы масштабирования. В любом случае, измерьте все вещи! – samy

+0

@stuartd: странно, похоже, что цикл обратной связи пытается прочитать документ в unicode и выводит их в ascii – samy

0

Я вижу, что ваш код включает JSON сериализации. Если вы ищете log4net JSON, зачем повторять то, что уже сделано? См. log4net.ext.json. Я разработчик. wiki covers the first steps о том, как его запустить и запустить. Он используется вместо макета, поэтому он может быть подключен к любому приложению log4net, которое принимает макет.

Часть моего проекта Я также создал графический интерфейс нагрузки для log4net. Он не выпущен, но должен легко компилироваться из источника. Вы можете использовать это, чтобы узнать, как различные конфигурации масштабируются в ваших условиях.

Наконец, я бы посоветовал предоставить LOCALHOST UDP доставку, если производительность является приоритетной. Такие проекты, как nxlog или logstash, могут легко проглотить. Опять же, зачем писать новый код?

Сообщите мне, если вам нужно уточнение.С наилучшими пожеланиями и удачи, Rob

Смежные вопросы