diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e4ca311 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "nuget" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/Entities/LogEntry.cs b/Entities/LogEntry.cs index e041532..081bae6 100644 --- a/Entities/LogEntry.cs +++ b/Entities/LogEntry.cs @@ -1,9 +1,33 @@ -namespace Xorog.Logger.Entities; +namespace Xorog.Logger; public class LogEntry { - public DateTime TimeOfEvent { get; set; } - public LogLevel LogLevel { get; set; } - public string Message { get; set; } - public Exception? Exception { get; set; } + internal LogEntry() { } + + internal string RawMessage { get; set; } + + /// + /// The time of the event. + /// + public DateTime TimeOfEvent { get; internal set; } + + /// + /// The severity of the event. + /// + public CustomLogLevel LogLevel { get; internal set; } + + /// + /// The message describing the event. + /// + public string Message { get; internal set; } + + /// + /// Any objects involved in creating the event message. + /// + public object[] Args { get; internal set; } = Array.Empty(); + + /// + /// The exception that's been caused. + /// + public Exception? Exception { get; internal set; } } \ No newline at end of file diff --git a/Entities/StringPart.cs b/Entities/StringPart.cs new file mode 100644 index 0000000..6f8cc23 --- /dev/null +++ b/Entities/StringPart.cs @@ -0,0 +1,13 @@ +namespace Xorog.Logger; + +internal class StringPart : IDisposable +{ + internal string String { get; set; } + internal ConsoleColor? Color { get; set; } + + public void Dispose() + { + String = ""; + Color = null; + } +} diff --git a/Enums/CustomLogLevel.cs b/Enums/CustomLogLevel.cs new file mode 100644 index 0000000..42fc1e8 --- /dev/null +++ b/Enums/CustomLogLevel.cs @@ -0,0 +1,14 @@ +namespace Xorog.Logger; + +public enum CustomLogLevel +{ + None, + Fatal, + Error, + Warn, + Info, + Debug, + Debug2, + Trace, + Trace2 +} \ No newline at end of file diff --git a/Enums/LogLevel.cs b/Enums/LogLevel.cs deleted file mode 100644 index 0ff84e1..0000000 --- a/Enums/LogLevel.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Xorog.Logger.Enums; - -public enum LogLevel -{ - NONE, - FATAL, - ERROR, - WARN, - INFO, - DEBUG, - DEBUG2, - TRACE, - TRACE2 -} \ No newline at end of file diff --git a/Events/LogMessageEventArgs.cs b/Events/LogMessageEventArgs.cs index 866b949..30fe8fd 100644 --- a/Events/LogMessageEventArgs.cs +++ b/Events/LogMessageEventArgs.cs @@ -1,7 +1,6 @@ -namespace Xorog.Logger; +namespace Xorog.Logger.EventArgs; -public class LogMessageEventArgs : EventArgs +public class LogMessageEventArgs : System.EventArgs { public LogEntry LogEntry { get; set; } - } \ No newline at end of file diff --git a/Global.cs b/Global.cs index 26ca27b..e2658b3 100644 --- a/Global.cs +++ b/Global.cs @@ -4,7 +4,4 @@ global using System.Collections.Generic; global using System.IO; global using System.Linq; global using System.Text; -global using System.Threading.Tasks; -global using Xorog.Logger.Entities; -global using Xorog.Logger.Enums; -global using LogLevel = Xorog.Logger.Enums.LogLevel; \ No newline at end of file +global using System.Threading.Tasks; \ No newline at end of file diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs new file mode 100644 index 0000000..67e20ae --- /dev/null +++ b/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "", Scope = "member", Target = "~P:Xorog.Logger.LoggerProvider._logger")] diff --git a/Logger.cs b/Logger.cs deleted file mode 100644 index 6a224f8..0000000 --- a/Logger.cs +++ /dev/null @@ -1,407 +0,0 @@ -namespace Xorog.Logger; - -public class Logger : ILogger -{ - internal Logger() { } - - private bool loggerStarted = false; - private LogLevel maxLogLevel = LogLevel.DEBUG; - - private string FileName = ""; - private FileStream OpenedFile { get; set; } - - internal List LogsToPost = new(); - internal List Blacklist = new(); - internal List FileBlackList = new(); - - private Task RunningLogger = null; - - public event EventHandler LogRaised; - - - /// - /// 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 Logger StartLogger(string filePath = "", LogLevel level = LogLevel.DEBUG, DateTime cleanUpBefore = new DateTime(), bool ThrowOnFailedDeletion = false) - { - var handler = new Logger(); - - if (handler.loggerStarted) - throw new Exception($"The logger is already started"); - - if (filePath is not "") - { - handler.FileName = filePath; - handler.OpenedFile = File.Open(handler.FileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read); - } - - handler.loggerStarted = true; - handler.maxLogLevel = level; - - if (cleanUpBefore != new DateTime()) - { - foreach (var b in Directory.GetFiles(new FileInfo(filePath).Directory.FullName)) - { - try - { - FileInfo fi = new(b); - if (fi.CreationTimeUtc < cleanUpBefore) - { - fi.Delete(); - handler.LogDebug($"{fi.Name} deleted"); - } - } - catch (Exception ex) - { - if (!ThrowOnFailedDeletion) - handler.LogError( $"Couldn't delete log file {b}", ex); - else - throw new Exception($"Failed to delete {b}: {ex}"); - } - } - } - - handler.RunningLogger = Task.Run(async () => - { - while (handler.loggerStarted) - { - try - { - while (handler.LogsToPost.Count == 0) - { - Thread.Sleep(10); - } - - for (int i = 0; i < handler.LogsToPost.Count; i++) - { - var currentLog = handler.LogsToPost[0]; - handler.LogsToPost.Remove(currentLog); - - - if (currentLog is null) - { - continue; - } - - string LogLevelText = currentLog.LogLevel.ToString(); - - if (LogLevelText.Length < 6) - LogLevelText += new string(' ', 6 - LogLevelText.Length); - - ConsoleColor LogLevelColor; - ConsoleColor BackgroundColor; - - LogLevelColor = currentLog.LogLevel switch - { - LogLevel.TRACE => ConsoleColor.Gray, - LogLevel.DEBUG2 => ConsoleColor.Gray, - LogLevel.DEBUG => ConsoleColor.Gray, - LogLevel.INFO => ConsoleColor.Green, - LogLevel.WARN => ConsoleColor.Yellow, - LogLevel.ERROR => ConsoleColor.Red, - LogLevel.FATAL => ConsoleColor.Black, - _ => ConsoleColor.Gray - }; - - BackgroundColor = currentLog.LogLevel switch - { - LogLevel.FATAL => ConsoleColor.DarkRed, - _ => ConsoleColor.Black - }; - - string LogMessage = currentLog.Message; - - foreach (var blacklistobject in handler.Blacklist) - LogMessage = LogMessage.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase); - - if (handler.maxLogLevel >= currentLog.LogLevel) - { - Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss}] "); - Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]"); - Console.ResetColor(); Console.WriteLine($" {LogMessage}"); - - if (currentLog.Exception is not null) - Console.WriteLine(currentLog.Exception.ToString()); - } - - _ = Task.Run(() => - { - handler.LogRaised?.Invoke(null, new LogMessageEventArgs() { LogEntry = currentLog }); - }); - - try - { - if (!handler.FileBlackList.Contains(currentLog.LogLevel)) - { - Byte[] FileWrite = Encoding.UTF8.GetBytes($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss}] [{LogLevelText}] {LogMessage}\n{(currentLog.Exception is not null ? $"{currentLog.Exception}\n" : "")}"); - if (handler.OpenedFile != null) - { - await handler.OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length)); - handler.OpenedFile.Flush(); - } - } - } - catch (Exception ex) - { - handler.LogFatal($"Couldn't write log to file: {ex}"); - } - } - } - catch (Exception ex) - { - handler.LogError("An exception occured while trying to display a log message", ex); - await Task.Delay(1000); - continue; - } - } - }); - - return new Logger(); - } - - - - /// - /// Stops the logger - /// - public void StopLogger() - { - loggerStarted = false; - maxLogLevel = LogLevel.DEBUG; - FileName = ""; - - Thread.Sleep(500); - - if (RunningLogger is not null) - RunningLogger.Dispose(); - - RunningLogger = null; - - if (OpenedFile is not null) - OpenedFile.Close(); - } - - - - /// - /// Add blacklisted string to censor automatically - /// - /// - public void AddBlacklist(string blacklist) - { - Blacklist.Add(blacklist); - } - - /// - /// Add blacklisted log level to not save - /// - /// - public void AddLogLevelBlacklist(LogLevel level) - { - FileBlackList.Add(level); - } - - - - /// - /// Changes the log level - /// - /// - public void ChangeLogLevel(LogLevel level) - { - maxLogLevel = level; - } - - - - /// - /// Log with none log level - /// - /// - /// - public void LogNone(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.NONE, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with trace log level - /// - /// - /// - public void LogTrace(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.TRACE, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with debug2 log level - /// - /// - /// - public void LogDebug2(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.DEBUG2, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with debug log level - /// - /// - /// - public void LogDebug(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.DEBUG, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with info log level - /// - /// - /// - public void LogInfo(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.INFO, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with warn log level - /// - /// - /// - public void LogWarn(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.WARN, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with error log level - /// - /// - /// - public void LogError(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.ERROR, - Message = message, - Exception = exception - }); - } - - - - /// - /// Log with fatal log level - /// - /// - /// - public void LogFatal(string message, Exception? exception = null) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = LogLevel.FATAL, - Message = message, - Exception = exception - }); - } - - - /// - /// Log with standard Microsoft.Extensions.Logging format - /// - /// - /// - /// - /// - /// - /// - public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) - { - LogsToPost.Add(new LogEntry - { - TimeOfEvent = DateTime.Now, - LogLevel = logLevel switch - { - Microsoft.Extensions.Logging.LogLevel.Debug => LogLevel.DEBUG2, - Microsoft.Extensions.Logging.LogLevel.Trace => LogLevel.TRACE2, - Microsoft.Extensions.Logging.LogLevel.Information => LogLevel.INFO, - Microsoft.Extensions.Logging.LogLevel.Warning => LogLevel.WARN, - Microsoft.Extensions.Logging.LogLevel.Error => LogLevel.ERROR, - Microsoft.Extensions.Logging.LogLevel.Critical => LogLevel.FATAL, - Microsoft.Extensions.Logging.LogLevel.None => LogLevel.NONE, - _ => throw new NotImplementedException() - }, - Message = $"[{eventId.Id,2}] {formatter(state, exception)}", - Exception = exception - }); - } - - - - public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) - { - return loggerStarted; - } - - - - public IDisposable BeginScope(TState state) - { - return default!; - } -} diff --git a/LoggerClient.cs b/LoggerClient.cs new file mode 100644 index 0000000..6b1a463 --- /dev/null +++ b/LoggerClient.cs @@ -0,0 +1,696 @@ +using Newtonsoft.Json; +using Xorog.Logger.EventArgs; + +namespace Xorog.Logger; + +public sealed class LoggerClient : ILogger +{ + internal LoggerClient() { } + + /// + /// The . + /// + public LoggerProvider Provider { get; internal set; } + + private bool LoggerStarted = false; + private CustomLogLevel MaxLogLevel = CustomLogLevel.Debug; + + private string FileName = ""; + private FileStream OpenedFile { get; set; } + + internal List LogsToPost = new(); + internal List Blacklist = new(); + internal List FileBlackList = new(); + + private Task RunningLogger = null; + + /// + /// Fired when a log message has been sent. + /// + public event EventHandler LogRaised; + + + /// + /// 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 LoggerClient StartLogger(string filePath = "", CustomLogLevel level = CustomLogLevel.Debug, DateTime cleanUpBefore = new DateTime(), bool ThrowOnFailedDeletion = false) + { + DirectoryInfo directoryInfo = new(new FileInfo(filePath).DirectoryName); + + if (!directoryInfo.Exists) + directoryInfo.Create(); + + filePath = filePath.Replace("\\", "/"); + + var handler = new LoggerClient(); + handler.Provider = new(handler); + + if (handler.LoggerStarted) + throw new Exception($"The logger is already started"); + + if (filePath is not "") + { + if (filePath.Contains('/')) + { + var dirPath = filePath[..filePath.LastIndexOf('/')]; + + if (!Directory.Exists(dirPath)) + _ = Directory.CreateDirectory(dirPath); + } + + handler.FileName = filePath; + handler.OpenedFile = File.Open(handler.FileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read); + } + + handler.LoggerStarted = true; + handler.MaxLogLevel = level; + + if (cleanUpBefore != new DateTime()) + { + foreach (var b in Directory.GetFiles(new FileInfo(filePath).Directory.FullName)) + { + try + { + FileInfo fi = new(b); + if (fi.CreationTimeUtc < cleanUpBefore) + { + fi.Delete(); + handler.LogDebug($"{fi.Name} deleted"); + } + } + catch (Exception ex) + { + if (!ThrowOnFailedDeletion) + handler.LogError( $"Couldn't delete log file {b}", ex); + else + throw new Exception($"Failed to delete {b}: {ex}"); + } + } + } + + handler.RunningLogger = Task.Run(async () => + { + while (handler.LoggerStarted) + { + try + { + while (handler.LogsToPost.Count == 0) + { + Thread.Sleep(10); + } + + for (var i = 0; i < handler.LogsToPost.Count; i++) + { + var currentLog = handler.LogsToPost[0]; + _ = handler.LogsToPost.Remove(currentLog); + + + if (currentLog is null || currentLog.RawMessage is null) + { + continue; + } + + var LogLevelText = $"{currentLog.LogLevel,-6}"; + + ConsoleColor LogLevelColor; + ConsoleColor BackgroundColor; + + LogLevelColor = currentLog.LogLevel switch + { + CustomLogLevel.Trace => ConsoleColor.Gray, + CustomLogLevel.Debug2 => ConsoleColor.Gray, + CustomLogLevel.Debug => ConsoleColor.Gray, + CustomLogLevel.Info => ConsoleColor.Cyan, + CustomLogLevel.Warn => ConsoleColor.Yellow, + CustomLogLevel.Error => ConsoleColor.Red, + CustomLogLevel.Fatal => ConsoleColor.Black, + _ => ConsoleColor.Gray + }; + + BackgroundColor = currentLog.LogLevel switch + { + CustomLogLevel.Fatal => ConsoleColor.DarkRed, + _ => ConsoleColor.Black + }; + + var leftOver = currentLog.RawMessage; + + foreach (var blacklistobject in handler.Blacklist) + leftOver = leftOver.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase); + + var currentArg = 0; + var inTemplate = false; + var attemptedParsing = false; + List builder = new(); + + while (leftOver.Length > 0) + { + if (inTemplate) + { + attemptedParsing = true; + if (currentLog.Args?.Length >= currentArg && currentLog.Args?.Length != 0) + { + try + { + var endIndex = leftOver.IndexOf('}'); + + if (currentArg > currentLog.Args.Length) + continue; + + var objectToAdd = currentLog.Args[currentArg]; + currentArg++; + + if (objectToAdd is null) + continue; + + if (objectToAdd.GetType() == typeof(int)) + builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta }); + else if (objectToAdd.GetType() == typeof(long)) + builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta }); + else if (objectToAdd.GetType() == typeof(uint)) + builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta }); + else if (objectToAdd.GetType() == typeof(ulong)) + builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta }); + else + builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan }); + + inTemplate = false; + + leftOver = leftOver[(endIndex + 1)..]; + attemptedParsing = false; + } + catch (Exception) + { + currentArg++; + continue; + } + continue; + } + } + + inTemplate = false; + + var placeholderIndex = leftOver.IndexOf('{'); + + if (placeholderIndex != -1) + inTemplate = true; + + if (placeholderIndex == -1 || placeholderIndex > leftOver.Length) + placeholderIndex = leftOver.Length; + + if (placeholderIndex == 0 && attemptedParsing) + placeholderIndex = leftOver.Length; + + var str = leftOver[..placeholderIndex]; + if (!string.IsNullOrEmpty(str)) + builder.Add(new StringPart { String = str }); + + leftOver = leftOver[placeholderIndex..]; + attemptedParsing = false; + } + + if (handler.MaxLogLevel >= currentLog.LogLevel) + { + Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] "); + Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]"); Console.ResetColor(); Console.Write(" "); + + foreach (var part in builder) + { + Console.ForegroundColor = part.Color ?? ConsoleColor.White; + Console.BackgroundColor = ConsoleColor.Black; + + Console.Write($"{part.String}"); + } + Console.ResetColor(); + Console.WriteLine(); + + if (currentLog.Exception is not null) + try + { + Console.WriteLine(JsonConvert.SerializeObject(currentLog.Exception, Formatting.Indented, new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + Error = (serializer, err) => err.ErrorContext.Handled = true + })); + } + catch (Exception) + { + Console.WriteLine(currentLog.Exception); + } + } + + currentLog.Message = string.Join("", builder.Select(x => x.String)); + + for (var i1 = 0; i1 < builder.Count; i1++) + { + builder[i1].Dispose(); + } + builder.Clear(); + + _ = Task.Run(() => handler.LogRaised?.Invoke(null, new LogMessageEventArgs() { LogEntry = currentLog })); + + try + { + if (!handler.FileBlackList.Contains(currentLog.LogLevel)) + { + var FileWrite = Encoding.UTF8.GetBytes($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] [{LogLevelText}] {currentLog.Message}\n{(currentLog.Exception is not null ? $"{currentLog.Exception}\n" : "")}"); + if (handler.OpenedFile != null) + { + await handler.OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length)); + handler.OpenedFile.Flush(); + } + } + } + catch (Exception ex) + { + handler.LogFatal($"Couldn't write log to file: {ex}"); + } + } + } + catch (Exception ex) + { + handler.LogError("An exception occurred while trying to display a log message", ex); + await Task.Delay(1000); + continue; + } + } + }); + + return handler; + } + + /// + /// Stops the logger + /// + public void StopLogger() + { + LoggerStarted = false; + MaxLogLevel = CustomLogLevel.Debug; + FileName = ""; + + Thread.Sleep(500); + + RunningLogger?.Dispose(); + + RunningLogger = null; + + this.OpenedFile?.Close(); + } + + /// + /// Add strings automatically censor on output to console and file. + /// + /// The strings to censor + public void AddBlacklist(params string[] blacklist) + { + for (var i = 0; i < blacklist.Length; i++) + { + if (!string.IsNullOrWhiteSpace(blacklist[i])) + Blacklist.Add(blacklist[i]); + } + } + + /// + /// Add blacklisted log level to not save + /// + /// The log levels not to save to the log file + public void AddLogLevelBlacklist(params CustomLogLevel[] levels) + { + for (var i = 0; i < levels.Length; i++) + { + FileBlackList.Add(levels[i]); + } + } + + /// + /// Changes the log level + /// + /// The new log level to apply + public void ChangeLogLevel(CustomLogLevel level) => MaxLogLevel = level; + + /// + /// Log with none log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogNone(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.None, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with none log level + /// + /// The message to display + /// The exception that was caused + public void LogNone(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.None, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with none log level + /// + /// The message to display + /// The objects involved in the event + public void LogNone(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.None, + RawMessage = message, + Args = args + }); + + /// + /// Log with trace log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogTrace(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Trace, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with trace log level + /// + /// The message to display + /// The exception that was caused + public void LogTrace(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Trace, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with trace log level + /// + /// The message to display + /// The objects involved in the event + public void LogTrace(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Trace, + RawMessage = message, + Args = args, + }); + + /// + /// Log with debug2 log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogDebug2(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug2, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with debug2 log level + /// + /// The message to display + /// The exception that was caused + public void LogDebug2(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug2, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with debug2 log level + /// + /// The message to display + /// The objects involved in the event + public void LogDebug2(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug2, + RawMessage = message, + Args = args + }); + + /// + /// Log with debug log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogDebug(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with debug log level + /// + /// The message to display + /// The exception that was caused + public void LogDebug(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with debug log level + /// + /// The message to display + /// The objects involved in the event + public void LogDebug(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Debug, + RawMessage = message, + Args = args + }); + + /// + /// Log with info log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogInfo(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Info, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with info log level + /// + /// The message to display + /// The exception that was caused + public void LogInfo(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Info, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with info log level + /// + /// The message to display + /// The objects involved in the event + public void LogInfo(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Info, + RawMessage = message, + Args = args + }); + + /// + /// Log with warn log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogWarn(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Warn, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with warn log level + /// + /// The message to display + /// The exception that was caused + public void LogWarn(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Warn, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with warn log level + /// + /// The message to display + /// The objects involved in the event + public void LogWarn(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Warn, + RawMessage = message, + Args = args + }); + + /// + /// Log with error log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogError(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Error, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with error log level + /// + /// The message to display + /// The exception that was caused + public void LogError(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Error, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with error log level + /// + /// The message to display + /// The objects involved in the event + public void LogError(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Error, + RawMessage = message, + Args = args + }); + + /// + /// Log with fatal log level + /// + /// The message to display + /// The exception that was caused + /// The objects involved in the event + public void LogFatal(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Fatal, + RawMessage = message, + Args = args, + Exception = exception + }); + + /// + /// Log with fatal log level + /// + /// The message to display + /// The exception that was caused + public void LogFatal(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Fatal, + RawMessage = message, + Exception = exception + }); + + /// + /// Log with fatal log level + /// + /// The message to display + /// The objects involved in the event + public void LogFatal(string message, params object[] args) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = CustomLogLevel.Fatal, + RawMessage = message, + Args = args + }); + + /// + /// Log with standard Microsoft.Extensions.Logging format + /// + /// + /// + /// + /// + /// + /// + public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => LogsToPost.Add(new LogEntry + { + TimeOfEvent = DateTime.Now, + LogLevel = logLevel switch + { + Microsoft.Extensions.Logging.LogLevel.Debug => CustomLogLevel.Debug2, + Microsoft.Extensions.Logging.LogLevel.Trace => CustomLogLevel.Trace2, + Microsoft.Extensions.Logging.LogLevel.Information => CustomLogLevel.Info, + Microsoft.Extensions.Logging.LogLevel.Warning => CustomLogLevel.Warn, + Microsoft.Extensions.Logging.LogLevel.Error => CustomLogLevel.Error, + Microsoft.Extensions.Logging.LogLevel.Critical => CustomLogLevel.Fatal, + Microsoft.Extensions.Logging.LogLevel.None => CustomLogLevel.None, + _ => CustomLogLevel.None, + }, + RawMessage = $"[{eventId.Id}] {formatter(state, exception)}", + Exception = exception + }); + + public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) + => LoggerStarted; + + public IDisposable BeginScope(TState state) + => default!; +} diff --git a/LoggerProvider.cs b/LoggerProvider.cs index ac8a673..b8d02be 100644 --- a/LoggerProvider.cs +++ b/LoggerProvider.cs @@ -1,24 +1,16 @@ -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Xorog.Logger; -namespace Xorog.Logger; -public class LoggerProvider : ILoggerProvider +public sealed class LoggerProvider : ILoggerProvider { - private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); + internal LoggerProvider(LoggerClient logger) + => this._logger = logger; - public ILogger CreateLogger(string categoryName) - { - return _loggers.GetOrAdd(categoryName, name => new Logger()); - } - public void Dispose() - { - _loggers.Clear(); - GC.SuppressFinalize(this); - } + private LoggerClient _logger { get; set; } + + public ILogger CreateLogger(string categoryName) + => this._logger; + + public void Dispose() + => GC.SuppressFinalize(this); } diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..e91e38b --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "Xorog.Logger": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 2e8a43a..f1e54bb 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# Xorog.Logger \ No newline at end of file +# Xorog.Logger + +The logger used in projects of Fortunevale. + +## Used in + +- [BeatRecorder](https://github.com/TheXorog/BeatRecorder) + + diff --git a/Xorog.Logger.csproj b/Xorog.Logger.csproj index 590a571..c16daaa 100644 --- a/Xorog.Logger.csproj +++ b/Xorog.Logger.csproj @@ -1,11 +1,12 @@ - net6.0 + net8.0 enable annotations Debug;Release;x64 - AnyCPU;x64 + x64 + False @@ -14,10 +15,12 @@ embedded + True embedded + False @@ -26,14 +29,17 @@ embedded + True embedded + False - + +