using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Tango.Logging { /// /// Represents a helper class for logging information and errors. /// public class LogManager { private List _loggers; private ConcurrentQueue _logs; private Thread _loggingThread; private bool _isStarted; private static LogManager _default; public static LogManager Default { get { if (_default == null) { _default = new LogManager(); } return _default; } } /// /// Gets or sets a value indicating whether to propagate logs instantly (Warning - not thread safe). /// public bool OverrideQueue { get; set; } /// /// Initializes the class. /// public LogManager() { _loggers = new List(); _logs = new ConcurrentQueue(); Categories = new List(); Categories.Add(LogCategory.Critical); Categories.Add(LogCategory.Debug); Categories.Add(LogCategory.Error); Categories.Add(LogCategory.Info); Categories.Add(LogCategory.Warning); } /// /// Gets or sets the logging categories filter. /// public List Categories { get; private set; } /// /// Registers a logger. /// /// The logger. public void RegisterLogger(ILogger logger) { if (logger != null && !_loggers.Contains(logger)) { _loggers.Add(logger); } } /// /// Unregisters a logger. /// /// The logger. public void UnregisterLogger(ILogger logger) { if (logger != null && _loggers.Contains(logger)) { _loggers.Remove(logger); } } /// /// Add new exception log item. /// /// Exception. /// Error description. public Exception Log(Exception e, String description = null, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { return Log(e, LogCategory.Error, description, caller, file, lineNumber); } /// /// Add new exception log item. /// /// Exception. /// Error description. public Exception Log(Exception e, LogCategory category, String description = null, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { if (!Categories.Contains(category)) return e; ExceptionLogItem log = new ExceptionLogItem(); log.CallerMethodName = caller; log.CallerFile = file; log.CallerLineNumber = lineNumber; log.TimeStamp = DateTime.Now; log.Exception = e; log.Category = category; log.Description = description != null ? description : e.ToString(); if (!OverrideQueue) { AppendLog(log); } else { AppendLogInstantly(log); } return e; } /// /// Add new exception log item. /// /// Exception. /// Error description. public Exception LogFormat(Exception e, String description, object argument, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { return Log(e, LogCategory.Error, String.Format(description, argument), caller, file, lineNumber); } /// /// Add new message log item. /// /// Message. public String LogFormat(String message, object argument, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { return Log(String.Format(message, argument), LogCategory.Info, caller, file, lineNumber); } /// /// Add new message log item. /// /// Message. public String Log(String message, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { return Log(message, LogCategory.Info, caller, file, lineNumber); } /// /// Add new message log item. /// /// Message. public String Log(String message, LogCategory category, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0) { if (!Categories.Contains(category)) return message; MessageLogItem log = new MessageLogItem(); log.CallerMethodName = caller; log.CallerFile = file; log.CallerLineNumber = lineNumber; log.TimeStamp = DateTime.Now; log.Category = category; log.Message = message; if (!OverrideQueue) { AppendLog(log); } else { AppendLogInstantly(log); } return message; } /// /// Add new message log item. /// /// Message. public void Log(MessageLogItem log) { log.TimeStamp = DateTime.Now; AppendLog(log); } /// /// Appends the log. /// /// The log. private void AppendLog(LogItemBase log) { if (log != null) { _loggers.Where(x => x.Enabled && x.Immediate).ToList().ForEach(x => x.OnLog(log)); } _logs.Enqueue(log); StartLoggingThread(); } /// /// Starts the logging thread. /// private void StartLoggingThread() { if (!_isStarted) { _isStarted = true; _loggingThread = new Thread(LoggingThreadMethod); _loggingThread.IsBackground = true; _loggingThread.Start(); } } /// /// Loggings thread method. /// //[DebuggerStepThrough] //[DebuggerHidden] private void LoggingThreadMethod() { while (_isStarted) { while (_logs.Count > 0) { LogItemBase log; if (_logs.TryDequeue(out log)) { if (log != null) { _loggers.Where(x => x.Enabled && !x.Immediate).ToList().ForEach(x => x.OnLog(log)); } } } Thread.Sleep(10); } } /// /// Appends the log instantly. /// /// The log. [DebuggerStepThrough] [DebuggerHidden] private void AppendLogInstantly(LogItemBase log) { bool wroteLog = false; while (!wroteLog) { try { _loggers.Where(x => x.Enabled).ToList().ForEach(x => x.OnLog(log)); wroteLog = true; } catch { Thread.Sleep(5); } } } } }