diff --git a/Config.cs b/Config.cs index 4528d1f..7b497c8 100644 --- a/Config.cs +++ b/Config.cs @@ -12,7 +12,6 @@ internal static class Config internal static string token = ""; internal static ulong logChannel; internal static string welcomeMessage = ""; - internal static LogLevel logLevel = LogLevel.Information; internal static TimestampFormat timestampFormat = TimestampFormat.RelativeTime; internal static bool randomAssignment = false; internal static bool randomAssignRoleOverride = false; @@ -32,8 +31,6 @@ internal static class Config internal static string username = "supportchild"; internal static string password = ""; - internal static JToken interviews; - private static string configPath = "./config.yml"; public static void LoadConfig() @@ -68,11 +65,12 @@ internal static class Config welcomeMessage = json.SelectToken("bot.welcome-message")?.Value() ?? ""; string stringLogLevel = json.SelectToken("bot.console-log-level")?.Value() ?? ""; - if (!Enum.TryParse(stringLogLevel, true, out logLevel)) + if (!Enum.TryParse(stringLogLevel, true, out LogLevel logLevel)) { logLevel = LogLevel.Information; Logger.Warn("Log level '" + stringLogLevel + "' invalid, using 'Information' instead."); } + Logger.SetLogLevel(logLevel); string stringTimestampFormat = json.SelectToken("bot.timestamp-format")?.Value() ?? "RelativeTime"; @@ -100,8 +98,5 @@ internal static class Config database = json.SelectToken("database.name")?.Value() ?? "supportchild"; username = json.SelectToken("database.user")?.Value() ?? "supportchild"; password = json.SelectToken("database.password")?.Value() ?? ""; - - // Set up interviewer - interviews = json.SelectToken("interviews"); } } \ No newline at end of file diff --git a/Logger.cs b/Logger.cs index 4ae7522..1a64687 100644 --- a/Logger.cs +++ b/Logger.cs @@ -1,68 +1,137 @@ using Microsoft.Extensions.Logging; using System; -using System.Reflection; namespace SupportChild; -public static class Logger +internal class LogTestFactory : ILoggerProvider { - public static void Debug(string message) + public void Dispose() { } + + public ILogger CreateLogger(string categoryName) { - try - { - SupportChild.client.Logger.Log(LogLevel.Debug, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message); - } - catch (NullReferenceException) - { - Console.WriteLine("[DEBUG] " + message); - } + return Logger.instance; + } +} + +public class Logger : ILogger +{ + public static Logger instance { get; } = new Logger(); + + private static LogLevel minimumLogLevel = LogLevel.Trace; + private readonly object @lock = new(); + + internal static void SetLogLevel(LogLevel level) + { + minimumLogLevel = level; } - public static void Log(string message) + internal static void Debug(string message, Exception exception = null) { - try - { - SupportChild.client.Logger.Log(LogLevel.Information, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message); - } - catch (NullReferenceException) - { - Console.WriteLine("[INFO] " + message); - } + instance.Log(LogLevel.Debug, new EventId(420, "BOT"), exception, message); } - public static void Warn(string message) + internal static void Log(string message, Exception exception = null) { - try - { - SupportChild.client.Logger.Log(LogLevel.Warning, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message); - } - catch (NullReferenceException) - { - Console.WriteLine("[WARNING] " + message); - } + instance.Log(LogLevel.Information, new EventId(420, "BOT"), exception, message); } - public static void Error(string message) + internal static void Warn(string message, Exception exception = null) { - try - { - SupportChild.client.Logger.Log(LogLevel.Error, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message); - } - catch (NullReferenceException) - { - Console.WriteLine("[ERROR] " + message); - } + instance.Log(LogLevel.Warning, new EventId(420, "BOT"), exception, message); } - public static void Fatal(string message) + internal static void Error(string message, Exception exception = null) { - try + instance.Log(LogLevel.Error, new EventId(420, "BOT"), exception, message); + } + + internal static void Fatal(string message, Exception exception = null) + { + instance.Log(LogLevel.Critical, new EventId(420, "BOT"), exception, message); + } + + public bool IsEnabled(LogLevel logLevel) + { + return logLevel >= minimumLogLevel && logLevel != LogLevel.None; + } + + public IDisposable BeginScope(TState state) where TState : notnull => default; + + private static ConsoleColor GetLogLevelColour(LogLevel logLevel) + { + return logLevel switch { - SupportChild.client.Logger.Log(LogLevel.Critical, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message); - } - catch (NullReferenceException) + LogLevel.Trace => ConsoleColor.White, + LogLevel.Debug => ConsoleColor.DarkGray, + LogLevel.Information => ConsoleColor.DarkBlue, + LogLevel.Warning => ConsoleColor.Yellow, + LogLevel.Error => ConsoleColor.Red, + _ => ConsoleColor.White + }; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + return; + + string[] logLevelParts = logLevel switch { - Console.WriteLine("[CRITICAL] " + message); + LogLevel.Trace => ["[", "Trace", "] "], + LogLevel.Debug => ["[", "Debug", "] "], + LogLevel.Information => ["[", "Info", "] "], + LogLevel.Warning => ["[", "Warn", "] "], + LogLevel.Error => ["[", "Error", "] "], + LogLevel.Critical => ["[", "\u001b[1mCrit\u001b[0m", "] "], + _ => ["[", "None", "] "], + }; + + lock (@lock) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write("["); + + Console.ResetColor(); + Console.ForegroundColor = GetLogLevelColour(logLevel); + Console.Write($"{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")}"); + + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write("] "); + + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write("["); + + Console.ForegroundColor = eventId == 420 ? ConsoleColor.Green : ConsoleColor.DarkGreen; + Console.Write(eventId == 420 ? "BOT" : "API"); + + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write("] "); + Console.Write(logLevelParts[0]); + + Console.ForegroundColor = GetLogLevelColour(logLevel); + if (logLevel == LogLevel.Critical) + { + Console.BackgroundColor = ConsoleColor.DarkRed; + } + Console.Write(logLevelParts[1]); + + Console.ResetColor(); + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write(logLevelParts[2]); + + Console.ResetColor(); + if (logLevel is LogLevel.Trace or LogLevel.Debug) + { + Console.ForegroundColor = ConsoleColor.Gray; + } + Console.WriteLine(formatter(state, exception)); + + if (exception != null) + { + Console.WriteLine($"{exception} : {exception.Message}\n{exception.StackTrace}"); + } + + Console.ResetColor(); } } } \ No newline at end of file diff --git a/SupportChild.cs b/SupportChild.cs index 55fa6b5..68a290f 100644 --- a/SupportChild.cs +++ b/SupportChild.cs @@ -148,7 +148,6 @@ internal static class SupportChild Logger.Log("Setting up Discord client..."); DiscordClientBuilder clientBuilder = DiscordClientBuilder.CreateDefault(Config.token, DiscordIntents.All) .SetReconnectOnFatalGatewayErrors() - .SetLogLevel(Config.logLevel) .ConfigureServices(configure => { configure.AddSingleton(new ErrorHandler()); @@ -212,6 +211,10 @@ internal static class SupportChild { clientConfig.LogUnknownEvents = false; clientConfig.LogUnknownAuditlogs = false; + }) + .ConfigureLogging(config => + { + config.AddProvider(new LogTestFactory()); }); client = clientBuilder.Build(); @@ -221,8 +224,6 @@ internal static class SupportChild } } - - internal class ErrorHandler : IClientErrorHandler { public ValueTask HandleEventHandlerError(string name, Exception exception, Delegate invokedDelegate, object sender, object args)