using Discord;
using System.Reflection;
using System.Text;
namespace RegexBot.Services.Logging;
///
/// Implements program-wide logging.
///
class LoggingService : Service {
// NOTE: Service.Log's functionality is implemented here. DO NOT use within this class.
private readonly string _logBasePath;
internal LoggingService(RegexbotClient bot) : base(bot) {
_logBasePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)
+ Path.DirectorySeparatorChar + "logs";
try {
if (!Directory.Exists(_logBasePath)) Directory.CreateDirectory(_logBasePath);
Directory.GetFiles(_logBasePath);
} catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) {
throw new Exception("Cannot create or access logging directory.");
}
bot.DiscordClient.Log += DiscordClient_Log;
}
///
/// Discord.Net logging events handled here.
/// Only events with high importance are stored. Others are just printed to console.
///
private Task DiscordClient_Log(LogMessage arg) {
var msg = $"[{Enum.GetName(typeof(LogSeverity), arg.Severity)}] {arg.Message}";
if (arg.Exception != null) msg += arg.Exception.ToString();
switch (arg.Message) { // Prevent webhook logs for these 'important' Discord.Net messages
case "Connecting":
case "Connected":
case "Ready":
case "Disconnecting":
case "Disconnected":
case "Resumed previous session":
case "Failed to resume previous session":
break;
}
DoLog("Discord.Net", msg);
return Task.CompletedTask;
}
// Hooked
internal void DoLog(string source, string? message) {
message ??= "(null)";
var now = DateTimeOffset.Now;
var output = new StringBuilder();
var prefix = $"[{now:s}] [{source}] ";
foreach (var line in message.Split(["\r\n", "\n"], StringSplitOptions.None)) {
output.Append(prefix).AppendLine(line);
}
var outstr = output.ToString();
Console.Write(outstr);
var filename = _logBasePath + Path.DirectorySeparatorChar + $"{now:yyyy-MM}.log";
File.AppendAllText(filename, outstr, Encoding.UTF8);
}
}