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 + + +