Последовательное логирование в отдельном потоке

Последовательное логирование в отдельном потоке
Atom
17.02.2013
VassilSanych


Ещё одна доработка исходников: Разгрузка основного потока от логирования. Возможность изоляции от системных ресурсов, связанных с логированием.

public abstract class BaseLogReceiver<TParent> : BaseLogSource<TParent>, ILogReceiver
	{
		/// <summary>
		/// Инициализировать <see cref="BaseLogReceiver{TParent}"/>.
		/// </summary>
		protected BaseLogReceiver()
		{
		}

		void ILogReceiver.AddLog(LogMessage message)
		{
			LoggingQueue.AddLogAction(()=>RaiseLog(message));
		}
	}


	/// <summary>
	///  Логирование в отдельном параллельном потоке
	/// </summary>
	public class LoggingQueue
	{
		//если понадобится подменять реализацию
		public static LoggingQueue Instance { get; set; }


		static LoggingQueue()
		{
			Instance = new LoggingQueue();
		}


		public LoggingQueue()
		{
			StartThread();
		}


		/// <summary>
		///  Запуск отдельного параллельного потока логирования
		/// </summary>
		protected virtual void StartThread()
		{
			_loggingQueue = new ConcurrentQueue<Action>();
			_waitLog = new AutoResetEvent(false);
			Task.Run(() => DoLoggingListen());
		}


		private ConcurrentQueue<Action> _loggingQueue;
		private AutoResetEvent _waitLog;


		/// <summary>
		///		Добавление записи в лог
		/// </summary>
		/// <param name="action"></param>
		public static void AddLogAction(Action action)
		{
			Instance.AddAction(action);
		}


		/// <summary>
		///  Добавление действия записи в лог в очередь потока логирования
		/// </summary>
		/// <param name="action"></param>
		public virtual void AddAction(Action action)
		{
			_loggingQueue.Enqueue(action);
			_waitLog.Set();
		}


		/// <summary>
		///  Чтение очереди действий логирования
		/// </summary>
		protected virtual void DoLoggingListen()
		{
			do
			{
				Action logAction;
				if (_loggingQueue.TryDequeue(out logAction))
					logAction.Invoke();
				else
					_waitLog.WaitOne();
			} while (!_stopped);
		}

		private bool _stopped;
		/// <summary>
		///  Создание условий окончания работы прослушивания очереди
		/// </summary>
		public virtual void Stop()
		{
			_stopped = true;
			_waitLog.Set();
		}

	}


	/// <summary>
	///  Затычка логирования (может понадобиться для тестирования)
	/// </summary>
	public class LoggingQueueMock: LoggingQueue
	{
		//protected override void DoLoggingListen()
		//{
		//}

		public override void AddAction(Action action)
		{
		}

		protected override void StartThread()
		{
		}
	}

Кстати, можно что-то придумать и для затыкания LoggingHelper.Now. Потому что привязка кода к ресурсам системного времени - это совсем не TDD.

Критика просто жизненно необходима :)

PS Беда какая-то с описанием темы. Ломается.


Теги:


Спасибо:


1 2  >
Mikhail Sukhov

Фотография
Дата: 17.02.2013
Ответить


VassilSanych: Критика просто жизненно необходима :)

Начнем с того, что обычно формулируют проблему (типа как перед чтением стихов произносят название произведения и автора). Как решалась проблема?

Для примера. Я выделял логирование в отдельный поток, чтобы разгрузить основной поток торговли. Была проблема с перформансом логирования в файл, была решена с помощью параллельного потока.

Спасибо:

VassilSanych

Фотография
Дата: 17.02.2013
Ответить


Логирование включает файловые и другие системные операции. Это в любом случае замедляет выполнение основных алгоритмов. При том, что логирование - операция как раз совершенно не критичная к времени запуска, в отличие от торговых операций. Это не решение проблемы, это - архитектурная плюшка (о чём и сказано в комментарии темы). PS Должно было быть указано, но почему-то не было. Исправил :)

Спасибо:

ra81

Фотография
Дата: 17.02.2013
Ответить


Да и вообще была проблема того что блокирование потока логов приводило к блокированию всей системы. :). С такой плюшкой думаю сего не повторится.

Спасибо:

Mikhail Sukhov

Фотография
Дата: 17.02.2013
Ответить


VassilSanych: Логирование включает файловые и другие системные операции. Это в любом случае замедляет выполнение основных алгоритмов. При том, что логирование - операция как раз совершенно не критичная к времени запуска, в отличие от торговых операций. Это не решение проблемы, это - архитектурная плюшка (о чём и сказано в комментарии темы). PS Должно было быть указано, но почему-то не было. Исправил :)

Так ведь сейчас уже в 4.1 логирование отделено от основного потока.

Спасибо:

VassilSanych

Фотография
Дата: 17.02.2013
Ответить


Mikhail Sukhov: Так ведь сейчас уже в 4.1 логирование отделено от основного потока. Где? Я не нашёл.

Спасибо:

Mikhail Sukhov

Фотография
Дата: 17.02.2013
Ответить


VassilSanych:

Mikhail Sukhov: Так ведь сейчас уже в 4.1 логирование отделено от основного потока. Где? Я не нашёл.

LogManager.cs Это к слову о важности взаимодействия.

Спасибо:

VassilSanych

Фотография
Дата: 17.02.2013
Ответить


Ага. Понял. Пишет пачками по таймеру (вспомнил, почему у меня пропадало сообщение о завершении работы). И всё-таки лочит основной поток при добавлении сообщения в список. Очередь была бы производительнее.

Спасибо:

VassilSanych

Фотография
Дата: 18.02.2013
Ответить


Кстати. У LogManager есть такой косяк: когда количество сообщений превышает заданный максимум (т.е. как раз когда система очень сильно нагружена), логирование запускается в потоке вызова.

LogManager.cs 5 KB (549)
Спасибо:

VassilSanych

Фотография
Дата: 18.02.2013
Ответить


Изменил буфер сообщений на конкурентную очередь, убрал все локи, принудительный запуск логирования заменил перещёлкиванием таймера. Последнее исправление не тестировал.

Спасибо:

pyhta4og

Фотография
Дата: 18.02.2013
Ответить


VassilSanych: Кстати. У LogManager есть такой косяк: когда количество сообщений превышает заданный максимум (т.е. как раз когда система очень сильно нагружена), логирование запускается в потоке вызова.

Это было сделано для того, чтобы очередь не отжирала всю память.

Помимо этого есть режим MaxMessages=-1 когда логирование идет синхронно. Это сделано для того чтобы производить отладку. Иначе получится что вы уже на бреакпойнт в коде робота встали, а логи еще в файл не записались.

Спасибо:
1 2  >

Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy