
本文详解如何使用 discord.py 实现消息删除与编辑的完整日志记录功能,包括自动捕获被删消息内容、精准对比编辑前后的文本差异,并将结构化日志发送至指定频道,适用于运维型服务器管理机器人。
本文详解如何使用 discord.py 实现消息删除与编辑的完整日志记录功能,包括自动捕获被删消息内容、精准对比编辑前后的文本差异,并将结构化日志发送至指定频道,适用于运维型服务器管理机器人。
要构建一个可靠的服务器日志系统,仅记录消息删除是不够的——真正关键的是可追溯的编辑行为。on_message_edit 事件与 on_message_delete 不同,它天然提供两个 discord.Message 对象:before(编辑前状态)和 after(编辑后状态),使内容对比成为可能。
以下是完整的日志处理实现(基于 Cog 结构):
import discord
from discord import app_commands
from discord.ext import commands
class LoggingCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.Cog.listener()
async def on_message_delete(self, message: discord.Message):
# 跳过机器人自身消息及系统消息(如频道主题变更)
if not message.author.bot and message.content.strip():
embed = discord.Embed(
title="?️ Message Deleted",
color=0xff4d4d,
timestamp=message.created_at
)
embed.add_field(name="Author", value=f"{message.author.mention} (`{message.author}`)", inline=False)
embed.add_field(name="Channel", value=message.channel.mention, inline=False)
embed.add_field(name="Content", value=message.content or "(empty)", inline=False)
if message.attachments:
embed.add_field(name="Attachments", value=f"{len(message.attachments)} file(s)", inline=False)
log_channel = discord.utils.get(message.guild.channels, name="logging")
if log_channel:
await log_channel.send(embed=embed)
@commands.Cog.listener()
async def on_message_edit(self, before: discord.Message, after: discord.Message):
# 忽略编辑事件中的非内容变更(如仅更新 embed 或时间戳)
if before.content == after.content:
return
# 同样过滤掉机器人消息和空内容
if not before.author.bot and (before.content.strip() or after.content.strip()):
embed = discord.Embed(
title="✏️ Message Edited",
color=0xffcc00,
timestamp=after.edited_at or after.created_at
)
embed.add_field(name="Author", value=f"{before.author.mention} (`{before.author}`)", inline=False)
embed.add_field(name="Channel", value=before.channel.mention, inline=False)
embed.add_field(
name="Before Edit",
value=before.content[:1024] or "(empty)",
inline=False
)
embed.add_field(
name="After Edit",
value=after.content[:1024] or "(empty)",
inline=False
)
# 若内容过长,标注截断提示
if len(before.content) > 1024 or len(after.content) > 1024:
embed.set_footer(text="Content truncated for readability — full history available via audit log")
log_channel = discord.utils.get(before.guild.channels, name="logging")
if log_channel:
await log_channel.send(embed=embed)
async def setup(bot: commands.Bot):
await bot.add_cog(LoggingCog(bot))
⚠️ 重要注意事项:
- on_message_edit 不会触发于纯 embed 更新、附件增删或仅时间戳变更(如 pin/unpin),仅当 message.content 实际变化时才触发;
- 确保 Bot 拥有 View Audit Log 权限,以便在必要时回溯原始事件;
- 日志频道名 "logging" 需与服务器实际频道名一致,建议通过 ID 替代名称查找以提升健壮性(如 guild.get_channel(123...));
- 生产环境建议添加异常处理(如 try/except discord.Forbidden)并限制日志频率,避免刷屏;
- 敏感信息(如令牌、密码)若曾出现在消息中,即使被编辑也已在日志中留存——请配合内容审核策略与定期日志清理机制。
通过该方案,管理员可在日志频道中清晰区分删除与编辑事件,直观比对修改前后内容,大幅提升服务器内容治理的透明度与可审计性。











