using System; using System.Collections.Generic; using System.Threading; using ZeroLevel.Services.Logging; namespace ZeroLevel.Logging { internal sealed class LogRouter : ILogger, ILogComposer { #region Fields private long _backlog = -1; private volatile bool _stopped; private readonly object LogsCacheeLocker = new object(); private readonly Dictionary> LogWriters = new Dictionary>(); private volatile ILogMessageBuffer _messageQueue; #endregion Fields #region Ctor public LogRouter() { _messageQueue = new NoLimitedLogMessageBuffer(); AppDomain.CurrentDomain.ProcessExit += (sender, e) => { Dispose(); }; _stopped = false; var thread = new Thread(ProcessMessageQueueMethod) { IsBackground = true }; thread.Start(); } #endregion Ctor #region Routing public void SetupBacklog(long backlog) { if (backlog != _backlog) { var currentQueue = _messageQueue; if (backlog > 0) // Fix { _messageQueue = new FixSizeLogMessageBuffer(backlog); } else // Unlimited { _messageQueue = new NoLimitedLogMessageBuffer(); } while (currentQueue.Count > 0) { var t = currentQueue.Take(); _messageQueue.Push(t.Item1, t.Item2); } currentQueue.Dispose(); currentQueue = null!; GC.Collect(); GC.WaitForFullGCComplete(); } } private void ProcessMessageQueueMethod(object state) { while (false == _stopped || _messageQueue.Count > 0) { var message = _messageQueue.Take(); if (message != null!) { lock (LogsCacheeLocker) { foreach (var lv in LogWriters.Keys) { if ((lv & ((int)message.Item1)) != 0) { foreach (var logger in LogWriters[lv]) { logger.Write(message.Item1, message.Item2); } } } } message = null!; } } } public void AddLogger(ILogger logger, LogLevel level = LogLevel.All) { if (false == _stopped) { lock (LogsCacheeLocker) { var lv = (int)level; if (false == LogWriters.ContainsKey(lv)) { LogWriters.Add(lv, new List()); } LogWriters[lv].Add(logger); } } } #endregion Routing #region ILogger public void Write(LogLevel level, string message) { if (false == _stopped) { _messageQueue.Push(level, message); } } #endregion ILogger #region IDisposable public void Dispose() { if (false == _stopped) { _stopped = true; while (_messageQueue.Count > 0) { Thread.Sleep(100); } _messageQueue.Dispose(); lock (LogsCacheeLocker) { foreach (var logCollection in LogWriters.Values) { foreach (var logger in logCollection) { try { logger.Dispose(); } catch { } } } LogWriters.Clear(); } GC.Collect(); GC.WaitForPendingFinalizers(); } } #endregion IDisposable } }