#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 удастся очистить буфер в конце?