Remove 'report' option in logging

The feature was previously meant for monitoring errors in a large public
bot instance, but is massively redundant and even annoying when using
as a self-hosted instance.
Besides, the information it did report was excessive and of little use.
This commit is contained in:
Noi 2022-07-27 19:23:49 -07:00
parent c77e4bd579
commit ebdaa6482c
9 changed files with 21 additions and 55 deletions

View file

@ -19,7 +19,6 @@ class InstanceConfig {
/// List of assemblies to load, by file. Paths are always relative to the bot directory. /// List of assemblies to load, by file. Paths are always relative to the bot directory.
/// </summary> /// </summary>
internal IReadOnlyList<string> Assemblies { get; } internal IReadOnlyList<string> Assemblies { get; }
internal string InstanceLogTarget { get; }
public string? SqlHost { get; } public string? SqlHost { get; }
public string? SqlDatabase { get; } public string? SqlDatabase { get; }
@ -47,7 +46,6 @@ class InstanceConfig {
} }
BotToken = ReadConfKey<string>(conf, nameof(BotToken), true); BotToken = ReadConfKey<string>(conf, nameof(BotToken), true);
InstanceLogTarget = ReadConfKey<string>(conf, nameof(InstanceLogTarget), true);
try { try {
Assemblies = Common.Utilities.LoadStringOrStringArray(conf[nameof(Assemblies)]).AsReadOnly(); Assemblies = Common.Utilities.LoadStringOrStringArray(conf[nameof(Assemblies)]).AsReadOnly();

View file

@ -51,7 +51,7 @@ static class ModuleLoader {
newreport.Append($" {t.Name}"); newreport.Append($" {t.Name}");
newmods.Add((RegexbotModule)mod); newmods.Add((RegexbotModule)mod);
} }
rb._svcLogging.DoLog(false, nameof(ModuleLoader), newreport.ToString()); rb._svcLogging.DoLog(nameof(ModuleLoader), newreport.ToString());
return newmods; return newmods;
} }
} }

View file

@ -34,15 +34,13 @@ class Program {
AlwaysDownloadUsers = true AlwaysDownloadUsers = true
}); });
// Initialize services, load modules
_main = new RegexbotClient(cfg, client); _main = new RegexbotClient(cfg, client);
// Set up application close handler // Set up application close handler
Console.CancelKeyPress += Console_CancelKeyPress; Console.CancelKeyPress += Console_CancelKeyPress;
// TODO Set up unhandled exception handler // Proceed to connect
// send error notification to instance log channel, if possible
// And off we go.
await _main.DiscordClient.LoginAsync(TokenType.Bot, cfg.BotToken); await _main.DiscordClient.LoginAsync(TokenType.Bot, cfg.BotToken);
await _main.DiscordClient.StartAsync(); await _main.DiscordClient.StartAsync();
await Task.Delay(-1); await Task.Delay(-1);
@ -51,7 +49,7 @@ class Program {
private static void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) { private static void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) {
e.Cancel = true; e.Cancel = true;
_main._svcLogging.DoLog(true, nameof(RegexBot), "Shutting down. Reason: Interrupt signal."); _main._svcLogging.DoLog(nameof(RegexBot), "Shutting down.");
var finishingTasks = Task.Run(async () => { var finishingTasks = Task.Run(async () => {
// TODO periodic task service: stop processing, wait for all tasks to finish // TODO periodic task service: stop processing, wait for all tasks to finish
@ -60,7 +58,7 @@ class Program {
}); });
if (!finishingTasks.Wait(5000)) if (!finishingTasks.Wait(5000))
_main._svcLogging.DoLog(false, nameof(RegexBot), "Could not disconnect properly. Exiting..."); _main._svcLogging.DoLog(nameof(RegexBot), "Warning: Normal shutdown is taking too long. Exiting now.");
Environment.Exit(0); Environment.Exit(0);
} }
} }

View file

@ -30,8 +30,8 @@ public partial class RegexbotClient {
_svcCommonFunctions = new Services.CommonFunctions.CommonFunctionsService(this); _svcCommonFunctions = new Services.CommonFunctions.CommonFunctionsService(this);
_svcEntityCache = new Services.EntityCache.EntityCacheService(this); _svcEntityCache = new Services.EntityCache.EntityCacheService(this);
var ver = Assembly.GetExecutingAssembly().GetName().Version!; var ver = Assembly.GetExecutingAssembly().GetName().Version!.ToString(3);
_svcLogging.DoLog(true, nameof(RegexBot), $"{nameof(RegexBot)} v{ver:3} - https://github.com/NoiTheCat/RegexBot"); _svcLogging.DoLog(nameof(RegexBot), $"{nameof(RegexBot)} v{ver} - https://github.com/NoiTheCat/RegexBot");
// Load externally defined functionality // Load externally defined functionality
Modules = ModuleLoader.Load(Config, this); Modules = ModuleLoader.Load(Config, this);

View file

@ -73,16 +73,12 @@ public abstract class RegexbotModule {
/// <param name="message">The log message to send. Multi-line messages are acceptable.</param> /// <param name="message">The log message to send. Multi-line messages are acceptable.</param>
protected void Log(SocketGuild guild, string? message) { protected void Log(SocketGuild guild, string? message) {
var gname = guild.Name ?? $"Guild ID {guild.Id}"; var gname = guild.Name ?? $"Guild ID {guild.Id}";
Bot._svcLogging.DoLog(false, $"{gname}] [{Name}", message); Bot._svcLogging.DoLog($"{gname}] [{Name}", message);
} }
/// <summary> /// <summary>
/// Emits a log message to the bot console and, optionally, the logging webhook. /// Emits a log message to the bot console and, optionally, the logging webhook.
/// </summary> /// </summary>
/// <param name="message">The log message to send. Multi-line messages are acceptable.</param> /// <param name="message">The log message to send. Multi-line messages are acceptable.</param>
/// <param name="report"> protected void Log(string message) => Bot._svcLogging.DoLog(Name, message);
/// Specifies if the log message should be sent to the reporting channel.
/// Only messages of very high importance should use this option.
/// </param>
protected void Log(string message, bool report = false) => Bot._svcLogging.DoLog(report, Name, message);
} }

View file

@ -7,9 +7,9 @@ class MessageCachingSubservice {
// Hooked // Hooked
public event EcMessageUpdateHandler? OnCachePreUpdate; public event EcMessageUpdateHandler? OnCachePreUpdate;
private readonly Action<string, bool> _log; private readonly Action<string> _log;
internal MessageCachingSubservice(RegexbotClient bot, Action<string, bool> logMethod) { internal MessageCachingSubservice(RegexbotClient bot, Action<string> logMethod) {
_log = logMethod; _log = logMethod;
bot.DiscordClient.MessageReceived += DiscordClient_MessageReceived; bot.DiscordClient.MessageReceived += DiscordClient_MessageReceived;
bot.DiscordClient.MessageUpdated += DiscordClient_MessageUpdated; bot.DiscordClient.MessageUpdated += DiscordClient_MessageUpdated;
@ -63,8 +63,8 @@ class MessageCachingSubservice {
try { try {
await (Task)handler.DynamicInvoke(oldMsg, newMsg)!; await (Task)handler.DynamicInvoke(oldMsg, newMsg)!;
} catch (Exception ex) { } catch (Exception ex) {
_log($"Unhandled exception in {nameof(RegexbotClient.EcOnMessageUpdate)} handler '{handler.Method.Name}':", false); _log($"Unhandled exception in {nameof(RegexbotClient.EcOnMessageUpdate)} handler '{handler.Method.Name}':\n"
_log(ex.ToString(), false); + ex.ToString());
} }
} }
} }

View file

@ -1,5 +1,4 @@
using Discord; using Discord;
using Discord.Webhook;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@ -9,11 +8,9 @@ namespace RegexBot.Services.Logging;
/// </summary> /// </summary>
class LoggingService : Service { class LoggingService : Service {
// NOTE: Service.Log's functionality is implemented here. DO NOT use within this class. // NOTE: Service.Log's functionality is implemented here. DO NOT use within this class.
private readonly DiscordWebhookClient _instLogWebhook;
private readonly string? _logBasePath; private readonly string? _logBasePath;
internal LoggingService(RegexbotClient bot) : base(bot) { internal LoggingService(RegexbotClient bot) : base(bot) {
_instLogWebhook = new DiscordWebhookClient(bot.Config.InstanceLogTarget);
_logBasePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) _logBasePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)
+ Path.DirectorySeparatorChar + "logs"; + Path.DirectorySeparatorChar + "logs";
try { try {
@ -21,7 +18,7 @@ class LoggingService : Service {
Directory.GetFiles(_logBasePath); Directory.GetFiles(_logBasePath);
} catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) { } catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) {
_logBasePath = null; _logBasePath = null;
Output(Name, "Cannot create or access logging directory. File logging will be disabled."); DoLog(Name, "Cannot create or access logging directory. File logging will be disabled.");
} }
bot.DiscordClient.Log += DiscordClient_Log; bot.DiscordClient.Log += DiscordClient_Log;
@ -33,9 +30,8 @@ class LoggingService : Service {
/// </summary> /// </summary>
private Task DiscordClient_Log(LogMessage arg) { private Task DiscordClient_Log(LogMessage arg) {
var msg = $"[{Enum.GetName(typeof(LogSeverity), arg.Severity)}] {arg.Message}"; var msg = $"[{Enum.GetName(typeof(LogSeverity), arg.Severity)}] {arg.Message}";
if (arg.Exception != null) msg += "\n```\n" + arg.Exception.ToString() + "\n```"; if (arg.Exception != null) msg += arg.Exception.ToString();
var important = arg.Severity != LogSeverity.Info;
switch (arg.Message) { // Prevent webhook logs for these 'important' Discord.Net messages switch (arg.Message) { // Prevent webhook logs for these 'important' Discord.Net messages
case "Connecting": case "Connecting":
case "Connected": case "Connected":
@ -44,15 +40,16 @@ class LoggingService : Service {
case "Disconnected": case "Disconnected":
case "Resumed previous session": case "Resumed previous session":
case "Failed to resume previous session": case "Failed to resume previous session":
important = false;
break; break;
} }
DoLog(important, "Discord.Net", msg); DoLog("Discord.Net", msg);
return Task.CompletedTask; return Task.CompletedTask;
} }
private void Output(string source, string message) { // Hooked
internal void DoLog(string source, string? message) {
message ??= "(null)";
var now = DateTimeOffset.UtcNow; var now = DateTimeOffset.UtcNow;
var output = new StringBuilder(); var output = new StringBuilder();
var prefix = $"[{now:u}] [{source}] "; var prefix = $"[{now:u}] [{source}] ";
@ -66,24 +63,4 @@ class LoggingService : Service {
File.AppendAllText(filename, outstr, Encoding.UTF8); File.AppendAllText(filename, outstr, Encoding.UTF8);
} }
} }
// Hooked
internal void DoLog(bool report, string source, string? message) {
message ??= "(null)";
Output(source, message);
if (report) Task.Run(() => ReportInstanceWebhook(source, message));
}
private async Task ReportInstanceWebhook(string source, string message) {
try {
EmbedBuilder e = new() {
Footer = new EmbedFooterBuilder() { Text = source },
Timestamp = DateTimeOffset.UtcNow,
Description = message
};
await _instLogWebhook.SendMessageAsync(embeds: new[] { e.Build() });
} catch (Exception ex) {
DoLog(false, Name, "Failed to send message to reporting channel: " + ex.Message);
}
}
} }

View file

@ -75,8 +75,6 @@ class ModuleStateService : Service {
return false; return false;
} }
// TODO Guild-specific service options? If implemented, this is where to load them.
// Load moderator list // Load moderator list
var mods = new EntityList(guildConf["Moderators"]!, true); var mods = new EntityList(guildConf["Moderators"]!, true);
@ -94,7 +92,7 @@ class ModuleStateService : Service {
Log("Unhandled exception while initializing guild state for module:\n" + Log("Unhandled exception while initializing guild state for module:\n" +
$"Module: {module.Name} | " + $"Module: {module.Name} | " +
$"Guild: {guildId} ({BotClient.DiscordClient.GetGuild(guildId)?.Name ?? "unknown name"})\n" + $"Guild: {guildId} ({BotClient.DiscordClient.GetGuild(guildId)?.Name ?? "unknown name"})\n" +
$"```\n{ex}\n```", true); $"```\n{ex}\n```");
return false; return false;
} }
} }

View file

@ -17,6 +17,5 @@ internal abstract class Service {
/// Emits a log message. /// Emits a log message.
/// </summary> /// </summary>
/// <param name="message">The log message to send. Multi-line messages are acceptable.</param> /// <param name="message">The log message to send. Multi-line messages are acceptable.</param>
/// <param name="report">Specify if the log message should be sent to a reporting channel.</param> protected void Log(string message) => BotClient._svcLogging.DoLog(Name, message);
protected void Log(string message, bool report = false) => BotClient._svcLogging.DoLog(report, Name, message);
} }