diff --git a/Catalogger.Backend/Bot/Responders/Messages/MessageCreateResponder.cs b/Catalogger.Backend/Bot/Responders/Messages/MessageCreateResponder.cs index 4f2b3a7..5098cd2 100644 --- a/Catalogger.Backend/Bot/Responders/Messages/MessageCreateResponder.cs +++ b/Catalogger.Backend/Bot/Responders/Messages/MessageCreateResponder.cs @@ -38,6 +38,8 @@ public class MessageCreateResponder( public async Task RespondAsync(IMessageCreate msg, CancellationToken ct = default) { + using var __ = LogUtils.Enrich(msg); + userCache.UpdateUser(msg.Author); CataloggerMetrics.MessagesReceived.Inc(); diff --git a/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteBulkResponder.cs b/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteBulkResponder.cs index 46fdd0b..157d30d 100644 --- a/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteBulkResponder.cs +++ b/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteBulkResponder.cs @@ -41,6 +41,8 @@ public class MessageDeleteBulkResponder( public async Task RespondAsync(IMessageDeleteBulk evt, CancellationToken ct = default) { + using var _ = LogUtils.Enrich(evt); + var guild = await guildRepository.GetAsync(evt.GuildID); if (guild.IsMessageIgnored(evt.ChannelID, null, null)) return Result.Success; diff --git a/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteResponder.cs b/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteResponder.cs index 9cf621e..315daec 100644 --- a/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteResponder.cs +++ b/Catalogger.Backend/Bot/Responders/Messages/MessageDeleteResponder.cs @@ -27,6 +27,7 @@ using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Rest.Core; using Remora.Results; +using Serilog.Context; namespace Catalogger.Backend.Bot.Responders.Messages; @@ -48,6 +49,8 @@ public class MessageDeleteResponder( public async Task RespondAsync(IMessageDelete evt, CancellationToken ct = default) { + using var _ = LogUtils.Enrich(evt); + if (!evt.GuildID.IsDefined()) return Result.Success; @@ -64,13 +67,15 @@ public class MessageDeleteResponder( return Result.Success; var guild = await guildRepository.GetAsync(evt.GuildID); - if (guild.IsMessageIgnored(evt.ChannelID, null, null)) - return Result.Success; - var msg = await messageRepository.GetMessageAsync(evt.ID.Value, ct); // Sometimes a message that *should* be logged isn't stored in the database, notify the user of that if (msg == null) { + _logger.Debug( + "Deleted message {MessageId} should be logged but is not in the database", + evt.ID + ); + webhookExecutor.QueueLog( webhookExecutor.GetLogChannel(guild, LogChannelType.MessageDelete, evt.ChannelID), new Embed( @@ -106,8 +111,13 @@ public class MessageDeleteResponder( evt.ChannelID, msg.UserId ); - if (logChannel == null) - return Result.Success; + if (logChannel is null or 0) + { + _logger.Debug( + "Message {MessageId} should not be logged; either ignored or message delete logs are disabled", + evt.ID + ); + } var user = await userCache.GetUserAsync(DiscordSnowflake.New(msg.UserId)); var builder = new EmbedBuilder() diff --git a/Catalogger.Backend/Bot/Responders/Messages/MessageUpdateResponder.cs b/Catalogger.Backend/Bot/Responders/Messages/MessageUpdateResponder.cs index 023cab1..fa1e75d 100644 --- a/Catalogger.Backend/Bot/Responders/Messages/MessageUpdateResponder.cs +++ b/Catalogger.Backend/Bot/Responders/Messages/MessageUpdateResponder.cs @@ -42,6 +42,8 @@ public class MessageUpdateResponder( public async Task RespondAsync(IMessageUpdate evt, CancellationToken ct = default) { + using var _ = LogUtils.Enrich(evt); + // Discord only *very* recently changed message update events to have all fields, // so we convert the event to a MessageCreate to avoid having to unwrap every single field var msg = ConvertToMessageCreate(evt); diff --git a/Catalogger.Backend/Extensions/LogUtils.cs b/Catalogger.Backend/Extensions/LogUtils.cs new file mode 100644 index 0000000..b8499b5 --- /dev/null +++ b/Catalogger.Backend/Extensions/LogUtils.cs @@ -0,0 +1,58 @@ +using Remora.Discord.API.Abstractions.Gateway.Events; +using Remora.Rest.Core; +using Serilog.Context; + +namespace Catalogger.Backend.Extensions; + +public static class LogUtils +{ + public static IDisposable Enrich(T evt) + where T : IGatewayEvent + { + var type = ("Event", typeof(T).Name); + + return evt switch + { + IMessageDelete md => PushProperties( + type, + ("GuildId", md.GuildID), + ("ChannelId", md.ChannelID), + ("MessageId", md.ID) + ), + IMessageUpdate mc => PushProperties( + type, + ("GuildId", mc.GuildID), + ("ChannelId", mc.ChannelID), + ("MessageId", mc.ID) + ), + IMessageDeleteBulk mdb => PushProperties( + type, + ("GuildId", mdb.GuildID), + ("ChannelId", mdb.ChannelID), + ("MessageIds", mdb.IDs) + ), + _ => PushProperties(type), + }; + } + + public static IDisposable PushProperties(params (string, object?)[] properties) => + new MultiDisposable( + properties + .Select(p => + { + if (p.Item2 is Optional s) + return LogContext.PushProperty(p.Item1, s.IsDefined() ? s.Value : null); + return LogContext.PushProperty(p.Item1, p.Item2); + }) + .ToArray() + ); + + private record MultiDisposable(IDisposable[] Entries) : IDisposable + { + public void Dispose() + { + foreach (var e in Entries) + e.Dispose(); + } + } +}