161 lines
4.9 KiB
C#
161 lines
4.9 KiB
C#
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<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 (Level < LogLevel.Trace)
|
|
return; // save some ticks here
|
|
|
|
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}"]);
|
|
}
|
|
}
|