Проблема с пользовательским буфером AdoNetAppender в Log4Net

#c# #log4net

#c# #log4net

Вопрос:

Я использую log4net и я создал свое собственное приложение из AdoNetAppender . Мое приложение просто реализует своего рода буфер, который позволяет группировать идентичные события в одном журнале (для тысяч идентичных ошибок у меня будет только одна строка в базе данных).

Вот код для упрощения понимания (у моего приложения buffersize = 1):

 class CustomAdoNetAppender : AdoNetAppender
{
    //My Custom Buffer
    private static List<LoggingEvent> unSendEvents = new List<LoggingEvent>();
    private int customBufferSize = 5;
    private double interval = 100;
    private static DateTime lastSendTime = DateTime.Now;

    protected override void SendBuffer(log4net.Core.LoggingEvent[] events)
    {
        LoggingEvent loggingEvent = events[0];
        LoggingEvent l = unSendEvents.Find(delegate(LoggingEvent logg) { return GetKey(logg).Equals(GetKey(loggingEvent), StringComparison.OrdinalIgnoreCase); });
        //If the events already exist in the custom buffer (unSendEvents) containing the 5 last events
        if (l != null)
        {
            //Iterate the count property
            try
            {
                l.Properties["Count"] = (int)l.Properties["Count"]   1;
            }
            catch
            {
                l.Properties["Count"] = 1;
            }
        }

        //Else
        else
        {
            //If the custom buffer (unSendEvents) contains 5 events
            if (unSendEvents.Count() == customBufferSize)
            {
                //Persist the older event
                base.SendBuffer(new LoggingEvent[] { unSendEvents.ElementAt(0) });
                //Delete it from the buffer
                unSendEvents.RemoveAt(0);
            }
            //Set count properties to 1
            loggingEvent.Properties["Count"] = 1;
            //Add the event to the pre-buffer 
            unSendEvents.Add(loggingEvent);
        }

        //If timer is over
        TimeSpan timeElapsed = loggingEvent.TimeStamp - lastSendTime;
        if (timeElapsed.TotalSeconds > interval)
        {
            //Persist all events contained in the unSendEvents buffer
            base.SendBuffer(unSendEvents.ToArray());
            //Update send time
            lastSendTime = unSendEvents.ElementAt(unSendEvents.Count() - 1).TimeStamp;
            //Flush the buffer
            unSendEvents.Clear();
        }
    }

    /// <summary>
    /// Function to build a key (aggregation of important properties of a logging event) to facilitate comparison.
    /// </summary>
    /// <param name="logg">The loggign event to get the key.</param>
    /// <returns>Formatted string representing the log event key.</returns>
    private string GetKey(LoggingEvent logg)
    {
        return string.Format("{0}|{1}|{2}|{3}", logg.Properties["ErrorCode"] == null ? string.Empty : logg.Properties["ErrorCode"].ToString()
                                , logg.Level.ToString()
                                , logg.LoggerName
                                , logg.MessageObject.ToString()
                                );
    }
}
  

Часть с буфером и подсчетом идет хорошо. Моя проблема в том, что я теряю 5 последних журналов, потому что буфер не очищается в конце программы. Буфер без отправки заполнен, но никогда не сбрасывается в базу данных, потому что новые журналы больше не будут «вставляться» в старые журналы db.

Есть ли какое-либо решение для меня? Я пытался использовать метод Flush (), но безуспешно.

Комментарии:

1. У меня нет этой проблемы, хотя я использую буферизацию с ado net appender во многих случаях: на сайте MVC, веб-api, сайте webform и службах NT. Единственный способ, которым я могу это воспроизвести, — это завершить процесс. Возможно, вам следует проверить, как завершается ваше приложение. И дайте более подробную информацию о том, что это за приложение. (Но, возможно, ваша проблема исчезла с 2011 года ^^.)

Ответ №1:

У приложения Smtp есть параметр с потерями. Если значение не равно false, вы не гарантированно получите все сообщения журнала. Похоже, это может быть вашей проблемой, возможно? Я использую файл конфигурации, поэтому эта строка есть в моем определении приложения.

 <lossy value="false" />
  

Комментарии:

1. Я использую adonetappender, а не smtp, но да, я установил значение с потерями в false. Может быть, это потому, что мой список LoggingEvent не обнаружен как буфер?

2. Пока нет. Возможен ли доступ к событию в буфере AdoNetAppender?

Ответ №2:

Я могу придумать пару способов справиться с этим. Первое — изменить размер вашего буфера на единицу (сейчас он равен 5). Это гарантировало бы, что все записи будут записаны сразу. Однако это может быть не идеально. Если это так, я могу придумать один обходной путь — поместить пять фиктивных сообщений журнала в ваш буфер. Это удалит реальные события, и ваши фиктивные события будут удалены.

Комментарии:

1. Размер моего буфера на самом деле равен единице. Проблема здесь в том, что я сам управляю буферизацией. Проблема при регистрации поддельного события 5 заключается в том, что нет «реальной конечной точки» приложения

2. Хммм. Я никогда раньше не управлял буфером вручную. По-прежнему звучит так, будто буфер не настраивается на значение только 1. В верхней части вы устанавливаете буфер равным 5 (private int bufferSize = 5;). Может ли быть так, что после этого он не настраивается на 1?

3. Размер буфера моего приложения равен 1. И я вручную управляю буфером размером 5 (частное значение int bufferSize = 5 теперь имеет значение manualBufferSize = 5 для большей ясности). Теперь мой вопрос: возможно ли получить доступ к буферу пользовательского приложения AdoNetAppender и изменить свойство events? Идея заключается в том, чтобы получить доступ к буферу приложения (больше не к моему пользовательскому буферу) и проверить события в буфере, а также изменить свойство «Count» так, как я хочу. При этом, возможно, log4net удастся очистить буфер в конце?