using System.Diagnostics; using System.Runtime.CompilerServices; namespace Qrakhen.Qamp.Core.Logging; public interface ILogger { LogLevel Level { get; set; } void Log(LogLevel level, params object?[] values); void Critical(params object?[] values); void Error(params object?[] values); void Warn(params object?[] values); void Info(params object?[] values); void Debug(params object?[] values); void Trace(params object?[] values); void Verbose(params object?[] values); void Method(object? value = null, string? caller = null); } [Flags] public enum LogLevel { Mute = 0x00, Critical = 0x01, Error = 0x02, Warn = 0x04, Info = 0x08, Debug = 0x10, Trace = 0x20, Verbose = 0x40, All = Critical | Error | Warn | Info | Debug | Trace | Verbose } public interface ILogFormatter { string[] Format(object? value, int maxWidth = 80); } public interface ILoggerService { ILogger Get(string? name = null, LogLevel? level = null); ILogger Get(string name, LogLevel? level = null); } public class LoggerService { private static readonly Dictionary _loggers = new Dictionary(); public static LogLevel Default = LogLevel.All; public static ILogger Get(string? name = null, LogLevel? level = null) { level ??= Default; string _name = nameof(T); if (!string.IsNullOrEmpty(name)) _name = $"{_name}:{name}"; return Get(_name, level); } public static ILogger Get(string name, LogLevel? level = null) { level ??= Default; ILogger? logger; if (_loggers.TryGetValue(name, out logger)) return logger; logger = new Logger(name, level.Value); _loggers.Add(name, logger); return logger; } } public class Logger : ILogger, ILogFormatter { public string Name { get; private set; } private LogLevel _level; public LogLevel Level { get => true ? LoggerService.Default : _level; set => _level = value; } private static Dictionary headers = new() { { LogLevel.Critical, (" !? ", " !? ") }, { LogLevel.Error, (" !! ", " ! ") }, { LogLevel.Warn, (" !> ", " ! ") }, { LogLevel.Info, (" :> ", " : ") }, { LogLevel.Debug, (" > ", " ") }, { LogLevel.Trace, (" > ", " ") }, { LogLevel.Verbose, (" > ", " ") }, }; private static Dictionary colors = new() { { LogLevel.Critical, ConsoleColor.DarkRed }, { LogLevel.Error, ConsoleColor.Red }, { LogLevel.Warn, ConsoleColor.Yellow }, { LogLevel.Info, ConsoleColor.White }, { LogLevel.Debug, ConsoleColor.Gray }, { LogLevel.Trace, ConsoleColor.DarkGray }, { LogLevel.Verbose, ConsoleColor.DarkGray }, }; public Logger(string name, LogLevel level) { Name = name; Level = level; } public string[] Format(object? value, int maxWidth = 80) { List result = []; if (value == null) result.Add("null"); else if (value is string str) result.AddRange(str.Split('\n')); else if (value is Exception e) { result.Add(e.Message); if (!string.IsNullOrEmpty(e.StackTrace)) result.AddRange(e.StackTrace.Split('\n')); } else result.Add(value?.ToString() ?? "null"); return result.ToArray(); } public void Log(LogLevel level, params object?[] values) { if ((level & Level) != level) return; var header = headers[level]; Console.ForegroundColor = colors[level]; foreach (var value in values) { var lines = Format(value); for (int i = 0; i < lines.Length; i++) Console.WriteLine($"{(i == 0 ? header.First : header.Extra)}{lines[i]}"); } Console.ForegroundColor = ConsoleColor.White; } public void Critical(params object?[] values) => Log(LogLevel.Critical, values); public void Error(params object?[] values) => Log(LogLevel.Error, values); public void Warn(params object?[] values) => Log(LogLevel.Warn, values); public void Info(params object?[] values) => Log(LogLevel.Info, values); public void Debug(params object?[] values) => Log(LogLevel.Debug, values); public void Trace(params object?[] values) => Log(LogLevel.Trace, values); public void Verbose(params object?[] values) => Log(LogLevel.Verbose, values); public void Method(object? value = null, [CallerMemberName] string? caller = null) { if (caller == null) { var st = new StackTrace(); var previous = st.GetFrame(1)?.GetMethod(); if (previous != null) caller = $"{previous.DeclaringType?.Name}.{previous.Name}"; } Log(LogLevel.Trace, [ $"[{caller}] {value}" ]); } }