diff --git a/Logger.cs b/Logger.cs
new file mode 100644
index 0000000..176bd53
--- /dev/null
+++ b/Logger.cs
@@ -0,0 +1,300 @@
+using System.Text;
+
+namespace Xorog.Logger;
+
+public class Logger
+{
+ private static bool loggerStarted = false;
+ private static LoggerObjects.LogLevel maxLogLevel = LoggerObjects.LogLevel.DEBUG;
+
+ private static string FileName = "";
+ private static FileStream? OpenedFile { get; set; }
+
+ private readonly static LoggerObjects _loggerObjects = new();
+
+ private static Task? RunningLogger = null;
+
+
+
+ ///
+ /// Starts the logger with specified settings
+ ///
+ /// Where the current logs should be saved to, leave blank if logs shouldnt be saved
+ /// The loglevel that should be displayed in the console, does not affect whats written to file
+ /// Clean up old logs before a datetime
+ /// A bool stating if the logger was started
+ public static void StartLogger(string filePath = "", LoggerObjects.LogLevel level = LoggerObjects.LogLevel.DEBUG, DateTime cleanUpBefore = new DateTime(), bool ThrowOnFailedDeletion = false)
+ {
+ if (loggerStarted)
+ throw new Exception($"The logger is already started");
+
+ if (filePath is not "")
+ {
+ FileName = filePath;
+ OpenedFile = File.Open(FileName, FileMode.Append);
+ }
+
+ loggerStarted = true;
+ maxLogLevel = level;
+
+ if (cleanUpBefore != new DateTime())
+ {
+ foreach (var b in Directory.GetFiles("logs"))
+ {
+ try
+ {
+ FileInfo fi = new(b);
+ if (fi.CreationTimeUtc < cleanUpBefore)
+ {
+ fi.Delete();
+ LogDebug(null, $"{fi.Name} deleted");
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!ThrowOnFailedDeletion)
+ LogError(null, $"Couldn't delete log file {b}: {ex}");
+ else
+ throw new Exception($"Failed to delete {b}: {ex}");
+ }
+ }
+ }
+
+ RunningLogger = Task.Run(async () =>
+ {
+ while (loggerStarted)
+ {
+ try
+ {
+ if (_loggerObjects.LogsToPost.Count == 0)
+ {
+ Thread.Sleep(10);
+ continue;
+ }
+
+ foreach (var b in _loggerObjects.LogsToPost.ToList())
+ {
+ string LogLevelText = b.LogLevel.ToString();
+ ConsoleColor LogLevelColor = ConsoleColor.Gray;
+
+ LogLevelColor = b.LogLevel switch
+ {
+ LoggerObjects.LogLevel.DEBUG => ConsoleColor.Gray,
+ LoggerObjects.LogLevel.INFO => ConsoleColor.Green,
+ LoggerObjects.LogLevel.WARN => ConsoleColor.Yellow,
+ LoggerObjects.LogLevel.ERROR => ConsoleColor.Red,
+ LoggerObjects.LogLevel.FATAL => ConsoleColor.DarkRed,
+ _ => ConsoleColor.Gray
+ };
+
+ if (b.LogLevel == LoggerObjects.LogLevel.DEBUG && maxLogLevel >= LoggerObjects.LogLevel.DEBUG)
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+ else if (b.LogLevel == LoggerObjects.LogLevel.INFO && maxLogLevel >= LoggerObjects.LogLevel.INFO)
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+ else if (b.LogLevel == LoggerObjects.LogLevel.WARN && maxLogLevel >= LoggerObjects.LogLevel.WARN)
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+ else if (b.LogLevel == LoggerObjects.LogLevel.ERROR && maxLogLevel >= LoggerObjects.LogLevel.ERROR)
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+ else if (b.LogLevel == LoggerObjects.LogLevel.FATAL && maxLogLevel >= LoggerObjects.LogLevel.FATAL)
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+ else
+ {
+ Console.ResetColor(); Console.Write($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] ");
+ Console.ForegroundColor = LogLevelColor; Console.Write($"[{LogLevelText}] ");
+ Console.ResetColor(); Console.WriteLine(b.Message);
+ _loggerObjects.LogsToPost.Remove(b);
+ }
+
+ try
+ {
+ Byte[] FileWrite = Encoding.UTF8.GetBytes($"[{b.TimeOfEvent:dd.MM.yyyy HH:mm:ss} | {(b.Source is not null ? b.Source.GetType().Namespace : "??")}/{(b.Source is not null ? b.Source.GetType().Name : "??")}] [{LogLevelText}] {b.Message}\n");
+ if (OpenedFile != null)
+ {
+ await OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length));
+ OpenedFile.Flush();
+ }
+ }
+ catch (Exception ex)
+ {
+ LogFatal(null, $"Couldn't write log to file: {ex}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.ResetColor(); Console.Write($"[{DateTime.Now:dd.MM.yyyy HH:mm:ss} | ??/??] ");
+ Console.ForegroundColor = ConsoleColor.DarkRed; Console.Write($"[FATAL] ");
+ Console.ResetColor(); Console.WriteLine($"An error occured while logging: {ex}");
+ await Task.Delay(1000);
+ continue;
+ }
+ }
+ });
+ }
+
+
+
+ ///
+ /// Stops the logger
+ ///
+ public static void StopLogger()
+ {
+ loggerStarted = false;
+ maxLogLevel = LoggerObjects.LogLevel.DEBUG;
+ FileName = "";
+
+ Thread.Sleep(500);
+
+ if (RunningLogger is not null)
+ RunningLogger.Dispose();
+
+ RunningLogger = null;
+
+ if (OpenedFile is not null)
+ OpenedFile.Close();
+ }
+
+
+
+ ///
+ /// Changes the log level
+ ///
+ ///
+ public static void ChangeLogLevel(LoggerObjects.LogLevel level)
+ {
+ maxLogLevel = level;
+ }
+
+
+
+ ///
+ /// Log without any LogLevel
+ ///
+ ///
+ ///
+ public static void Log(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.NONE,
+ Message = message,
+ Source = sender
+ });
+ }
+
+
+
+ ///
+ /// Log with debug log level
+ ///
+ ///
+ ///
+ public static void LogDebug(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.DEBUG,
+ Message = message,
+ Source = sender
+ });
+ }
+
+
+
+ ///
+ /// Log with info log level
+ ///
+ ///
+ ///
+ public static void LogInfo(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.INFO,
+ Message = message,
+ Source = sender
+ });
+ }
+
+
+
+ ///
+ /// Log with warn log level
+ ///
+ ///
+ ///
+ public static void LogWarn(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.WARN,
+ Message = message,
+ Source = sender
+ });
+ }
+
+
+
+ ///
+ /// Log with error log level
+ ///
+ ///
+ ///
+ public static void LogError(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.ERROR,
+ Message = message,
+ Source = sender
+ });
+ }
+
+
+
+ ///
+ /// Log with fatal log level
+ ///
+ ///
+ ///
+ public static void LogFatal(object? sender, string message)
+ {
+ _loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
+ {
+ TimeOfEvent = DateTime.Now,
+ LogLevel = LoggerObjects.LogLevel.FATAL,
+ Message = message,
+ Source = sender
+ });
+ }
+}
diff --git a/LoggerObjects.cs b/LoggerObjects.cs
new file mode 100644
index 0000000..9d43c80
--- /dev/null
+++ b/LoggerObjects.cs
@@ -0,0 +1,24 @@
+namespace Xorog.Logger;
+
+public class LoggerObjects
+{
+ internal List LogsToPost = new();
+
+ internal class LogEntry
+ {
+ public DateTime TimeOfEvent { get; set; }
+ public LogLevel LogLevel { get; set; }
+ public object? Source { get; set; } = new object();
+ public string? Message { get; set; }
+ }
+
+ public enum LogLevel
+ {
+ FATAL,
+ ERROR,
+ WARN,
+ INFO,
+ DEBUG,
+ NONE
+ }
+}
diff --git a/Xorog.Logger.csproj b/Xorog.Logger.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/Xorog.Logger.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+