using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
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 ProducerConsumerQueue _logs;
private Thread _loggingThread;
private bool _isStarted;
///
/// Occurs when a new log as been received.
///
public event EventHandler NewLog;
///
/// Gets the registered loggers.
///
public List RegisteredLoggers
{
get { return _loggers.ToList(); }
}
private static LogManager _default;
///
/// Gets the default log manager instance.
///
public static LogManager Default
{
get
{
if (_default == null)
{
_default = new LogManager();
}
return _default;
}
}
///
/// Initializes the class.
///
public LogManager()
{
_loggers = new List();
_logs = new ProducerConsumerQueue();
Categories = new List();
Categories.Add(LogCategory.Critical);
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;
log.Message = log.Description + Environment.NewLine + log.Exception.FlattenException();
AppendLog(log);
return e;
}
///
/// 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, null, 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)
{
return Log(message, category, null, caller, file, lineNumber);
}
///
/// Add new message log item.
///
/// Message.
public String Log(String message, LogCategory category, Object logObject, [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;
log.LogObject = logObject;
AppendLog(log);
return message;
}
///
/// Appends the specified log item.
///
/// The log item.
public void Log(LogItemBase logItem)
{
AppendLog(logItem);
}
///
/// Logs the current referenced assemblies in the app domain.
///
public void LogReferencedAssemblies()
{
String log = "--------------------- Referenced Assemblies --------------------------" + Environment.NewLine + Environment.NewLine;
try
{
string codeBase = typeof(LogManager).Assembly.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
String folder = Path.GetDirectoryName(path);
foreach (var file in Directory.GetFiles(folder, "*.dll"))
{
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(file);
string version = fvi.ProductVersion;
log += Path.GetFileNameWithoutExtension(file) + ", v" + version + Environment.NewLine;
}
log += Environment.NewLine + "--------------------- --------------------- --------------------------";
}
catch { }
Log(log);
}
///
/// 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)
{
_logs.BlockEnqueue(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)
{
LogItemBase log = _logs.BlockDequeue();
_loggers.Where(x => x.Enabled).ToList().ForEach(x => x.OnLog(log));
NewLog?.Invoke(this, log);
}
}
///
/// Creates a new log safe which can be used to keep logs and then be disposed.
///
///
public LogSafe CreateLogSafe()
{
return new LogSafe(this);
}
}
}