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);
}
}
}
}
}