qamp/Qrakhen.Qamp.Core/Logging/ILogger.cs

162 lines
5.1 KiB
C#

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Xml.XPath;
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<T>(string? name = null, LogLevel? level = null);
ILogger Get(string name, LogLevel? level = null);
}
public class LoggerService
{
private static readonly Dictionary<string, ILogger> _loggers = new Dictionary<string, ILogger>();
public static LogLevel Default = LogLevel.All;
public static ILogger Get<T>(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<LogLevel, (string First, string Extra)> headers = new() {
{ LogLevel.Critical, (" !? ", " !? ") },
{ LogLevel.Error, (" !! ", " ! ") },
{ LogLevel.Warn, (" !> ", " ! ") },
{ LogLevel.Info, (" :> ", " : ") },
{ LogLevel.Debug, (" > ", " ") },
{ LogLevel.Trace, (" > ", " ") },
{ LogLevel.Verbose, (" > ", " ") },
};
private static Dictionary<LogLevel, ConsoleColor> 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<string> 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}" ]);
}
}