Added the logger classes to new project (does not compile yet)
This commit is contained in:
parent
7eea30f4c2
commit
7279cc7a4f
128
SweetLib/Utils/Logger/Logger.cs
Normal file
128
SweetLib/Utils/Logger/Logger.cs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
using System;
|
||||||
|
using SweetLib.Utils.Logger.Memory;
|
||||||
|
using SweetLib.Utils.Logger.Message;
|
||||||
|
|
||||||
|
namespace SweetLib.Utils.Logger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enum which contains the several log levels.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Trace = 1 << 0,
|
||||||
|
Debug = 1 << 1,
|
||||||
|
Info = 1 << 2,
|
||||||
|
Warn = 1 << 3,
|
||||||
|
Error = 1 << 4,
|
||||||
|
|
||||||
|
All = Int32.MaxValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Global logger class providing several methods to log events by the application.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// As <see cref="DefaultLogMemory"/> a <see cref="ArchivableConsoleLogMemory"/> will be used. You can change this to any other implementation at any time while runtime.
|
||||||
|
/// Default log levels are set as bitflags in <see cref="GlobalLogLevel"/>.
|
||||||
|
/// </remarks>
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The global log level. Only messages with the set <see cref="LogLevel"/> will be procedered.
|
||||||
|
/// </summary>
|
||||||
|
public static LogLevel GlobalLogLevel { get; set; } = LogLevel.Info | LogLevel.Warn | LogLevel.Error;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default <see cref="ILogMemory"/> which will be used for any logging action, if no custom <see cref="ILogMemory"/> is set as parameter.
|
||||||
|
/// </summary>
|
||||||
|
public static ILogMemory DefaultLogMemory = new ArchivableConsoleLogMemory();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message into the global <see cref="DefaultLogMemory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logLevel">The log level of this message.</param>
|
||||||
|
/// <param name="message">The message to log.</param>
|
||||||
|
public static void Log(LogLevel logLevel, string message)
|
||||||
|
{
|
||||||
|
Log(logLevel, message, DefaultLogMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message into the provided <see cref="logMemory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logLevel">The log level of this message.</param>
|
||||||
|
/// /// <param name="message">The message to log.</param>
|
||||||
|
/// <param name="logMemory">The <see cref="ILogMemory"/> to store the <see cref="message"/> into.</param>
|
||||||
|
public static void Log(LogLevel logLevel, string message, ILogMemory logMemory)
|
||||||
|
{
|
||||||
|
Log(new LogMessage(logLevel, message), logMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message into the provided <see cref="logMemory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="LogMessage"/> object to store.</param>
|
||||||
|
/// <param name="logMemory">The <see cref="ILogMemory"/> to store the <see cref="message"/> into.</param>
|
||||||
|
/// <remarks>In general use cases you should either use one of the <see cref="Log(SweetLib.Utils.Logger.LogLevel,string)"/> or <see cref="Log(SweetLib.Utils.Logger.LogLevel,string)"/> methods which will generate a call to this method.</remarks>
|
||||||
|
public static void Log(LogMessage message, ILogMemory logMemory)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
|
||||||
|
if (logMemory == null)
|
||||||
|
throw new ArgumentNullException(nameof(logMemory));
|
||||||
|
|
||||||
|
if ((GlobalLogLevel & message.LogLevel) == LogLevel.None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
logMemory.Remember(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message with the <see cref="LogLevel.Trace"/> log level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message to log.</param>
|
||||||
|
public static void Trace(string message)
|
||||||
|
{
|
||||||
|
Log(LogLevel.Trace, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message with the <see cref="LogLevel.Debug"/> log level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message to log.</param>
|
||||||
|
public static void Debug(string message)
|
||||||
|
{
|
||||||
|
Log(LogLevel.Debug, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message with the <see cref="LogLevel.Info"/> log level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message to log.</param>
|
||||||
|
public static void Info(string message)
|
||||||
|
{
|
||||||
|
Log(LogLevel.Info, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message with the <see cref="LogLevel.Warn"/> log level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message to log.</param>
|
||||||
|
public static void Warn(string message)
|
||||||
|
{
|
||||||
|
Log(LogLevel.Warn, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will log a message with the <see cref="LogLevel.Error"/> log level.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message to log.</param>
|
||||||
|
public static void Error(string message)
|
||||||
|
{
|
||||||
|
Log(LogLevel.Error, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
163
SweetLib/Utils/Logger/Memory/ArchivableConsoleLogMemory.cs
Normal file
163
SweetLib/Utils/Logger/Memory/ArchivableConsoleLogMemory.cs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using SweetLib.Utils.Logger.Message;
|
||||||
|
|
||||||
|
namespace SweetLib.Utils.Logger.Memory
|
||||||
|
{
|
||||||
|
public class ArchivableConsoleLogMemory : ILogMemory
|
||||||
|
{
|
||||||
|
private string TempFile { get; } = Path.GetTempFileName();
|
||||||
|
|
||||||
|
private Timer QueueTimer { get; }
|
||||||
|
|
||||||
|
private ConcurrentQueue<LogMessage> LogQueue { get; } = new ConcurrentQueue<LogMessage>();
|
||||||
|
|
||||||
|
public string ArchiveFile { get; set; } = null;
|
||||||
|
|
||||||
|
public bool AutoArchiveOnDispose { get; set; } = true;
|
||||||
|
|
||||||
|
public ArchivableConsoleLogMemory() : this(null) { }
|
||||||
|
|
||||||
|
public ArchivableConsoleLogMemory(string archiveFile)
|
||||||
|
{
|
||||||
|
ArchiveFile = archiveFile;
|
||||||
|
|
||||||
|
QueueTimer = new Timer(e => ProcessQueue(), null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
~ArchivableConsoleLogMemory()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessQueue(bool isDisposing = false)
|
||||||
|
{
|
||||||
|
if (LogQueue.IsEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if we are disposing no need to lock. This might cause issues!
|
||||||
|
if (!isDisposing)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (LogQueue.IsEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LogMessage message;
|
||||||
|
if (LogQueue.TryDequeue(out message))
|
||||||
|
File.AppendAllText(TempFile, message.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (LogQueue.IsEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LogMessage message;
|
||||||
|
if (LogQueue.TryDequeue(out message))
|
||||||
|
File.AppendAllText(TempFile, message.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remember(LogMessage message)
|
||||||
|
{
|
||||||
|
var consoleColor = Console.ForegroundColor;
|
||||||
|
|
||||||
|
switch (message.LogLevel)
|
||||||
|
{
|
||||||
|
case LogLevel.Trace:
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
break;
|
||||||
|
case LogLevel.Debug:
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
break;
|
||||||
|
case LogLevel.Info:
|
||||||
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||||
|
break;
|
||||||
|
case LogLevel.Warn:
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
break;
|
||||||
|
case LogLevel.Error:
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(message.ToString());
|
||||||
|
LogQueue.Enqueue(message);
|
||||||
|
|
||||||
|
Console.ForegroundColor = consoleColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void Forget(LogMessage message)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(TempFile).ToList();
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
if (line == message.ToString())
|
||||||
|
lines.Remove(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllLines(TempFile, lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Archive(string fullFileName = null)
|
||||||
|
{
|
||||||
|
if (fullFileName == null)
|
||||||
|
fullFileName = ArchiveFile;
|
||||||
|
|
||||||
|
if (fullFileName == null)
|
||||||
|
throw new FileNotFoundException("target file not found");
|
||||||
|
|
||||||
|
using (var tmpFileStream = new FileInfo(TempFile).OpenRead())
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.GetDirectoryName(fullFileName)))
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(fullFileName));
|
||||||
|
|
||||||
|
using (var compressedFileStream = File.Create(fullFileName))
|
||||||
|
{
|
||||||
|
using (var compressionsStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
|
||||||
|
{
|
||||||
|
tmpFileStream.CopyTo(compressionsStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
QueueTimer.Dispose();
|
||||||
|
|
||||||
|
ProcessQueue(true);
|
||||||
|
|
||||||
|
if (AutoArchiveOnDispose)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Archive();
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Delete(TempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
SweetLib/Utils/Logger/Memory/ILogMemory.cs
Normal file
29
SweetLib/Utils/Logger/Memory/ILogMemory.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using SweetLib.Utils.Logger.Message;
|
||||||
|
|
||||||
|
namespace SweetLib.Utils.Logger.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for a class to store and proceed <see cref="LogMessage"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogMemory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a <see cref="message"/> into the <see cref="ILogMemory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"><see cref="LogMessage"/> to be stored.</param>
|
||||||
|
void Remember(LogMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a <see cref="message"/> from the <see cref="ILogMemory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"><see cref="LogMessage"/> to be removed.</param>
|
||||||
|
/// <remarks>This might not have any effect depending on the <see cref="ILogMemory"/> implementation.</remarks>
|
||||||
|
void Forget(LogMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves all remembered <see cref="LogMessage"/> objects into a persistent file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fullFileName">File name to store the <see cref="LogMessage"/> objects.</param>
|
||||||
|
void Archive(string fullFileName);
|
||||||
|
}
|
||||||
|
}
|
72
SweetLib/Utils/Logger/Mesage/LogMessage.cs
Normal file
72
SweetLib/Utils/Logger/Mesage/LogMessage.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace SweetLib.Utils.Logger.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="LogMessage"/> contains all event log data which should be logged in as a single log message.
|
||||||
|
/// </summary>
|
||||||
|
public class LogMessage : IFormattable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="LogLevel"/> of this event log.
|
||||||
|
/// </summary>
|
||||||
|
public LogLevel LogLevel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message of this event log.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The date and time of this event log.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime LogDateTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="LogMessage"/> instance. <see cref="DateTime.Now"/> will be the <see cref="LogDateTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logLevel">The log level of this event log.</param>
|
||||||
|
/// <param name="message">The message of this event log.</param>
|
||||||
|
public LogMessage(LogLevel logLevel, string message) : this(logLevel, message, DateTime.Now) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="LogMessage"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logLevel">The log level of this event log.</param>
|
||||||
|
/// <param name="message">The message of this event log.</param>
|
||||||
|
/// <param name="logDateTime">The <see cref="DateTime"/> of this event log.</param>
|
||||||
|
public LogMessage(LogLevel logLevel, string message, DateTime logDateTime)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
|
||||||
|
if (logDateTime == null)
|
||||||
|
throw new ArgumentNullException(nameof(logDateTime));
|
||||||
|
|
||||||
|
LogLevel = logLevel;
|
||||||
|
Message = message;
|
||||||
|
LogDateTime = logDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a formatted <see cref="string"/> of this event log. <see cref="LogMessageFormatter.DefaultFormatString"/> will be used to format this event log.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A formated <see cref="string"/> of this event log.</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(LogMessageFormatter.DefaultFormatString, CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a formatted <see cref="string"/> of this event log with a given format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format to be used. See <see cref="LogMessageFormatter"/> for more format information.</param>
|
||||||
|
/// <param name="formatProvider">Optional, an <see cref="IFormatProvider"/> interface to be used while formatting if needed.</param>
|
||||||
|
/// <returns>A formated <see cref="string"/> of this event log.</returns>
|
||||||
|
public string ToString(string format, IFormatProvider formatProvider = null)
|
||||||
|
{
|
||||||
|
return LogMessageFormatter.Instance.Format(format, this, formatProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
SweetLib/Utils/Logger/Mesage/LogMessageFormatter.cs
Normal file
79
SweetLib/Utils/Logger/Mesage/LogMessageFormatter.cs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace SweetLib.Utils.Logger.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="ICustomFormatter"/> which is used to format <see cref="LogMessage"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This class implements a singleton pattern.</remarks>
|
||||||
|
public class LogMessageFormatter : ICustomFormatter
|
||||||
|
{
|
||||||
|
|
||||||
|
private LogMessageFormatter() { }
|
||||||
|
|
||||||
|
private static object Locker { get; } = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accesses the global instance of the <see cref="LogMessageFormatter"/>.
|
||||||
|
/// </summary>
|
||||||
|
private static LogMessageFormatter FormatterInstance { get; set; }
|
||||||
|
|
||||||
|
public static string DefaultFormatString { get; set; } = $"[{CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern} - {CultureInfo.CurrentCulture.DateTimeFormat.LongTimePattern}] (LL): V";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default format string which is used to format <see cref="LogMessage"/> objects, if no custom format string is provided.
|
||||||
|
/// </summary>
|
||||||
|
public static LogMessageFormatter Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (FormatterInstance != null)
|
||||||
|
return FormatterInstance;
|
||||||
|
|
||||||
|
lock (Locker)
|
||||||
|
{
|
||||||
|
if (FormatterInstance != null)
|
||||||
|
return FormatterInstance;
|
||||||
|
|
||||||
|
FormatterInstance = new LogMessageFormatter();
|
||||||
|
}
|
||||||
|
return FormatterInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats a <see cref="LogMessage"/> object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format string. If <see cref="null"/>, <see cref="DefaultFormatString"/> will be used.</param>
|
||||||
|
/// <param name="arg">The <see cref="LogMessage"/> object to be formatted.</param>
|
||||||
|
/// <param name="formatProvider">Optional, an <see cref="IFormatProvider"/> interface to be used while formatting if needed.</param>
|
||||||
|
/// <returns>A formatted <see cref="string"/> of the <see cref="LogMessage"/>.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// If <see cref="arg"/> is not a <see cref="LogMessage"/> object, it will either be returned the formatted string implemented by the type of <see cref="arg"/>, if <see cref="IFormattable"/> is implemented by it, or the <see cref="arg.ToString()"/> result."
|
||||||
|
/// </remarks>
|
||||||
|
public string Format(string format, object arg, IFormatProvider formatProvider)
|
||||||
|
{
|
||||||
|
if (format == null)
|
||||||
|
format = DefaultFormatString;
|
||||||
|
|
||||||
|
if (arg == null)
|
||||||
|
throw new ArgumentNullException(nameof(arg));
|
||||||
|
|
||||||
|
if (arg.GetType() != typeof(LogMessage))
|
||||||
|
{
|
||||||
|
var formattable = arg as IFormattable;
|
||||||
|
return formattable?.ToString(format, formatProvider) ?? arg.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = (LogMessage)arg;
|
||||||
|
|
||||||
|
var result = message.LogDateTime.ToString(format, formatProvider);
|
||||||
|
|
||||||
|
result = result.Replace("LL", message.LogLevel.ToString());
|
||||||
|
result = result.Replace("V", message.Message);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue