分类: Discord 机器人开发

Discord 机器人开发#32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️

本文译自韩语原文。

要点速览

Discord 自带的审核日志只会告诉你'谁删了几条',却看不到被删的内容。本文把 raw 事件和 on_audit_log_entry_create 组合起来,做一个把被删内容、删除者、成员进出、身份组变更和踢出都以嵌入消息记录到同一个频道的日志机器人。

  • Python 3.10.12 · discord.py 2.7.1 · python-dotenv 1.2.3 · 2026-09-25 亲自运行验证
  • 被删消息的'内容'只有在机器人缓存里时才能看到 → 把 max_messages 调大,并且必须开启 Message Content 和 Server Members Intent
  • 删除者要在 guild.audit_logs() 里按 target、频道和时间(15 秒)查找;自己删自己的消息不会在审核日志里留下记录
  • 踢出和封禁通过 on_audit_log_entry_create(2.2+,Intents.moderation)实时收到,连执行者和原因都有
目录13 项

大家好!我是 Mojangcam 😎

上一篇 #31 我们做了一个临时语音频道(Temp Voice)机器人:进入大厅就自动创建频道,人走空了就自动删除。这一篇要做的是服务器管理员迟早都会想要的功能:"这是谁删的?"

今天要做的日志机器人能做这些事:

  • 有人删除消息时,删除前的内容会原样留在日志频道里
  • 如果是管理员删了别人的消息,连是谁删的也会记下来
  • 成员加入时会记录账号创建日期(识别小号和机器人!),离开时会记录他拥有过的身份组
  • 踢出和封禁会实时记录执行的管理员和原因

为什么需要机器人?🧠 Discord 自己也有 服务器设置 → 审核日志 菜单,但它不显示被删消息的内容。只会显示"谁删了几条"。一旦发生纠纷,想证明"刚才那个人骂了人又删掉了",就只能靠机器人提前记下来。

#서버-로그 (服务器日志) 频道里堆满了消息删除(红色)·成员加入(绿色)嵌入消息的画面,以及各事件对应的颜色图例

这一篇的日志机器人会和 #21 违禁词过滤、#25 错误处理 一起,担当 "社区综合管理机器人"的运营透明度模块。


📌 准备工作

  • Python 3.9 以上 (推荐 3.10+) — 代码里用了 dict[str, int] 写法,所以 3.9 起才能运行
  • discord.py 2.7.1 (截至 2026-09-25 PyPI 最新版) — on_audit_log_entry_create 从 2.2 才开始有,旧版本一定要升级
  • python-dotenv 1.x
  • 已在 Discord 开发者门户创建机器人并邀请进服务器 (权限:查看审核日志、发送消息、嵌入链接)
终端
pip install -U discord.py python-dotenv

在项目文件夹里新建 .env 文件并填入令牌。把令牌直接写进代码,上传到 GitHub 时非常容易泄露 😱

文本
token=여기에_봇_토큰

💡 记得把 .env 加进 .gitignore。(echo .env >> .gitignore)

⚠️ 这一篇需要两个特权 Intent(Privileged Intents)。请在开发者门户 → Bot 标签页里打开 Message Content Intent(想看到被删消息的内容就必须开)和 Server Members Intent(检测成员进出和身份组变更)。不开的话,删除日志里的内容会是空的,或者成员进出事件根本不会触发。

🧩 日志机器人要记录的内容

今天要做的日志一共 6 种。用颜色区分,只要滚动一下就能看出发生了什么。

事件 记录内容 嵌入消息颜色
消息删除 作者、频道、删除前的内容、附件文件名、删除者 红色
消息编辑 编辑前后的内容、消息跳转链接 橙色
加入·离开 账号创建日期(识别新账号)、加入日期、拥有过的身份组 绿色 / 灰色
昵称·身份组变更 变更前后、新增·移除的身份组 蓝色
踢出·封禁·解封 执行的管理员、对象、原因 深红色
频道创建·删除 频道名称·类型 绿色 / 红色

📌 第 1 步 - 基本设置和 3 个 Intent

Python
# discord.py 2.7.1 / Python 3.9+ / python-dotenv 1.x
import os
import json
import asyncio

import discord
from discord import app_commands
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()
token = os.getenv("token")

CONFIG_FILE = "log_config.json"   # {服务器ID(str): 日志频道ID(int)}
MAX_CONTENT = 1000                # 嵌入字段最多 1024 字 → 留点余量截断

intents = discord.Intents.default()
intents.message_content = True   # 想看被删消息的'内容'就必须开 (特权 Intent)
intents.members = True           # 检测成员进出·昵称·身份组变更 (特权 Intent)
intents.moderation = True        # 踢出·封禁 + 审核日志事件

bot = commands.Bot(command_prefix="!", intents=intents, max_messages=5000)

log_channels: dict[str, int] = {}
lock = asyncio.Lock()

我们逐个拆开来看 💡

  • intents.message_content : 让机器人能看到别人发的消息的内容。关掉的话,删除日志里的 content 会是空字符串。这是一个也需要在门户里打开的特权 Intent。
  • intents.members : on_member_join / on_member_remove / on_member_update 都绑定在这个 Intent 上。同样是特权 Intent。
  • intents.moderation : on_member_ban / on_member_unban 以及今天的主角 on_audit_log_entry_create 都属于它。它不是特权 Intent,只在代码里打开就行。(和旧名字 intents.bans 是同一个东西。)
  • max_messages=5000 : 机器人记住的消息数量。默认值是 1000,而被删消息的内容只有在这个缓存里时才能看到,所以调大了一些。

📌 第 2 步 - 保存日志频道和嵌入消息公共函数

每个服务器的日志频道都不一样,所以把 {服务器ID: 频道ID} 存进 JSON。和 #31 完全一样的写法。

Python
def save():
    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        json.dump(log_channels, f, ensure_ascii=False, indent=2)


def load():
    global log_channels
    if os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, encoding="utf-8") as f:
            log_channels = json.load(f)


def get_log_channel(guild: discord.Guild):
    cid = log_channels.get(str(guild.id))
    return guild.get_channel(cid) if cid else None


def make_embed(title: str, color: discord.Color, user=None) -> discord.Embed:
    embed = discord.Embed(title=title, color=color, timestamp=discord.utils.utcnow())
    if user is not None:
        embed.set_author(name=f"{user} ({user.id})", icon_url=user.display_avatar.url)
    return embed


async def send_log(guild: discord.Guild, embed: discord.Embed):
    channel = get_log_channel(guild)
    if channel is None:
        return
    try:
        await channel.send(embed=embed)
    except discord.Forbidden:
        print(f"⚠️ {guild.name}: 没有在日志频道发送消息的权限。")


def cut(text: str) -> str:
    text = text or "(没有内容 — 只有嵌入/附件,或不在缓存中)"
    return text if len(text) <= MAX_CONTENT else text[:MAX_CONTENT] + " …(已省略)"
  • timestamp=discord.utils.utcnow() : 嵌入消息底部会自动显示"今天 下午3:12"这样的时间,而且是按查看者自己的时区显示。日志里最重要的就是时间嘛!
  • set_author(name, icon_url) : 在嵌入消息最上方放上头像 + 名字 (ID)。之所以把 ID 一起留下,是因为之后就算对方改了昵称或者退出服务器,ID 也不会变。
  • send_log 里的 try/except : 如果有人改了日志频道的权限,机器人可能会因为 Forbidden 崩掉。按 #25 学过的方法把它捕获,只在控制台打印一下就跳过。
  • cut() : 嵌入字段的值有 1024 字的限制。超过就会报 400 Bad Request,所以提前截断。

📌 第 3 步 - 核心!捕获消息删除和编辑

这里要用到 raw 事件。on_message_delete 只会通知缓存里有的消息,而 on_raw_message_delete 即使不在缓存里,也会告诉你"哪个频道的哪个 ID 被删了"。

删除消息时机器人的处理流程 - 发生删除、查询缓存、查询审核日志 3 个阶段,以及不同情况下"删除者"一栏显示的值

Python
async def find_deleter(guild: discord.Guild, author_id: int, channel_id: int):
    """在审核日志里查找'刚刚在这个频道删了这个人消息的管理员'。"""
    try:
        async for entry in guild.audit_logs(limit=5, action=discord.AuditLogAction.message_delete):
            same_target = entry.target is not None and entry.target.id == author_id
            same_channel = entry.extra.channel.id == channel_id
            recent = (discord.utils.utcnow() - entry.created_at).total_seconds() < 15
            if same_target and same_channel and recent:
                return entry.user
    except discord.Forbidden:
        return None
    return None


@bot.event
async def on_raw_message_delete(payload: discord.RawMessageDeleteEvent):
    if payload.guild_id is None:      # 忽略私信
        return
    guild = bot.get_guild(payload.guild_id)
    msg = payload.cached_message

    embed = make_embed("🗑️ 消息删除", discord.Color.red(), msg.author if msg else None)
    embed.add_field(name="频道", value=f"<#{payload.channel_id}>", inline=True)

    if msg is None:
        embed.add_field(name="内容", value="不在缓存中的消息 (机器人启动前的消息)", inline=False)
        embed.set_footer(text=f"消息 ID: {payload.message_id}")
    else:
        if msg.author.bot:
            return
        deleter = await find_deleter(guild, msg.author.id, payload.channel_id)
        who = deleter.mention if deleter else "本人 (或无法确认)"
        embed.add_field(name="删除者", value=who, inline=True)
        embed.add_field(name="内容", value=cut(msg.content), inline=False)
        if msg.attachments:
            files = "\n".join(a.filename for a in msg.attachments)
            embed.add_field(name="附件", value=files, inline=False)
        embed.set_footer(text=f"消息 ID: {msg.id}")

    await send_log(guild, embed)


@bot.event
async def on_raw_message_edit(payload: discord.RawMessageUpdateEvent):
    if payload.guild_id is None:
        return
    before = payload.cached_message
    after = payload.message
    if before is None or after.author.bot:
        return
    if before.content == after.content:      # 过滤掉生成嵌入预览等'假编辑'
        return

    guild = bot.get_guild(payload.guild_id)
    embed = make_embed("✏️ 消息编辑", discord.Color.orange(), after.author)
    embed.add_field(name="频道", value=after.channel.mention, inline=True)
    embed.add_field(name="跳转", value=f"[跳到消息]({after.jump_url})", inline=True)
    embed.add_field(name="编辑前", value=cut(before.content), inline=False)
    embed.add_field(name="编辑后", value=cut(after.content), inline=False)
    await send_log(guild, embed)


@bot.event
async def on_raw_bulk_message_delete(payload: discord.RawBulkMessageDeleteEvent):
    if payload.guild_id is None:
        return
    guild = bot.get_guild(payload.guild_id)
    embed = make_embed("🧹 批量删除消息", discord.Color.dark_red())
    embed.add_field(name="频道", value=f"<#{payload.channel_id}>", inline=True)
    embed.add_field(name="数量", value=f"{len(payload.message_ids)} 条", inline=True)
    await send_log(guild, embed)

我们逐个拆开来看 💡

  • payload.cached_message : 被删的消息如果在机器人缓存里,就是 Message 对象,不在就是 None。机器人启动前发出的消息不在缓存里,所以记为"无法确认内容",但频道和消息 ID 还是会留下。这对调查也有帮助。
  • guild.audit_logs(limit=5, action=...) : 按从新到旧的顺序遍历服务器审核日志的异步迭代器。不能用 for,必须用 async for 来遍历。机器人没有查看审核日志权限时会抛出 Forbidden,所以用 try 包起来了。
  • entry.target / entry.extra.channel / entry.created_at : message_delete 条目里,target 是发消息的人,extra.channel 是被删消息所在的频道,extra.count 是删除的条数。三项都对得上、并且是 15 秒内生成的条目,那它的 entry.user(执行者)就是删除者。
  • "本人 (或无法确认)" : 自己删自己的消息,审核日志里根本不会留下记录。所以在审核日志里找不到时,就当作本人删除。不过,如果同一个管理员连续删除同一个人的消息,Discord 只会把已有条目的 count 加一,而不会新建条目,这时可能会因为 15 秒的条件而漏掉。只要记住它不是 100% 准确就好。
  • payload.message (编辑事件) : 这是编辑后的消息(2.5 起新增)。编辑前的消息从 cached_message 里取。贴上链接时,Discord 生成预览嵌入会再发一次编辑事件,这里让 content 相同时直接跳过,避免日志变得乱七八糟。
  • on_raw_bulk_message_delete : 管理员执行"删除 100 条消息"这类批量删除(purge)时,不会逐条触发删除事件,而是只来一次这个事件。把内容全部记下来日志会爆炸,所以只记录了条数。

📌 第 4 步 - 加入·离开·昵称·身份组变更

Python
@bot.event
async def on_member_join(member: discord.Member):
    embed = make_embed("📥 成员加入", discord.Color.green(), member)
    embed.add_field(name="成员", value=member.mention, inline=True)
    embed.add_field(name="账号创建日期", value=discord.utils.format_dt(member.created_at, "R"), inline=True)
    embed.add_field(name="当前人数", value=f"{member.guild.member_count} 人", inline=True)
    await send_log(member.guild, embed)


@bot.event
async def on_member_remove(member: discord.Member):
    embed = make_embed("📤 成员离开", discord.Color.light_grey(), member)
    embed.add_field(name="成员", value=f"{member} ({member.mention})", inline=True)
    if member.joined_at:
        embed.add_field(name="加入日期", value=discord.utils.format_dt(member.joined_at, "R"), inline=True)
    roles = [r.mention for r in member.roles if r != member.guild.default_role]
    if roles:
        embed.add_field(name="拥有过的身份组", value=" ".join(roles), inline=False)
    await send_log(member.guild, embed)


@bot.event
async def on_member_update(before: discord.Member, after: discord.Member):
    if before.nick != after.nick:
        embed = make_embed("🏷️ 昵称变更", discord.Color.blue(), after)
        embed.add_field(name="变更前", value=before.nick or "(无)", inline=True)
        embed.add_field(name="变更后", value=after.nick or "(无)", inline=True)
        await send_log(after.guild, embed)

    added = [r for r in after.roles if r not in before.roles]
    removed = [r for r in before.roles if r not in after.roles]
    if added or removed:
        embed = make_embed("🎭 身份组变更", discord.Color.blurple(), after)
        if added:
            embed.add_field(name="➕ 新增", value=" ".join(r.mention for r in added), inline=False)
        if removed:
            embed.add_field(name="➖ 移除", value=" ".join(r.mention for r in removed), inline=False)
        await send_log(after.guild, embed)
  • format_dt(时间, "R") : 转换成 <t:1790291186:R> 格式,Discord 就会显示成 "3 天前"、"2 年前" 这样的相对时间。加入日志里账号创建日期如果是"12 分钟前"呢?那很可能是机器人账号或小号。这是管理员们最喜欢的字段 👀
  • on_member_remove : 自己退出也好,被踢出、被封禁也好,全部都走这个事件。所以"为什么离开"要靠下一步的审核日志事件另外记录。
  • 比较 before.roles / after.roles : on_member_update 在昵称、身份组、禁言、服务器头像等任何东西变化时都会触发。所以要在里面自己比较"到底变了什么"。这里用身份组列表的差集来区分新增和移除。

📌 第 5 步 - 踢出·封禁用审核日志事件(谁·为什么)

Python
MOD_ACTIONS = {
    discord.AuditLogAction.kick: ("👢 踢出(Kick)", discord.Color.dark_orange()),
    discord.AuditLogAction.ban: ("🔨 封禁(Ban)", discord.Color.dark_red()),
    discord.AuditLogAction.unban: ("🕊️ 解除封禁(Unban)", discord.Color.teal()),
}


@bot.event
async def on_audit_log_entry_create(entry: discord.AuditLogEntry):
    if entry.action not in MOD_ACTIONS:
        return
    title, color = MOD_ACTIONS[entry.action]
    embed = make_embed(title, color, entry.user)
    target = entry.target
    embed.add_field(name="对象", value=f"{target} (<@{target.id}>)" if target else "(未知)", inline=True)
    embed.add_field(name="执行者", value=entry.user.mention if entry.user else "(未知)", inline=True)
    embed.add_field(name="原因", value=entry.reason or "(未填写原因)", inline=False)
    await send_log(entry.guild, embed)
  • on_audit_log_entry_create : 服务器审核日志里生成新条目的那一刻就会实时调用(discord.py 2.2+,需要 Intents.moderation,机器人必须有查看审核日志权限)。不像第 3 步那样事后去翻找,而是 Discord 主动通知你,所以准确得多。
  • entry.action : 表示是什么操作的 AuditLogAction 枚举。今天只挑了踢出、封禁、解封三种,但还有 channel_create、role_update、member_role_update 等几十种。只要在字典里加一行,日志种类就会增加。
  • entry.user / entry.target / entry.reason : 分别是执行的管理员、被处理的人,以及管理员踢人时填写的原因。没填原因时是 None,所以换成了"(未填写原因)"。

💡 执行者显示为 None?用户信息不在缓存里时可能会这样。entry.user_id(2.2+)总是有值的,所以直接用 f"<@{entry.user_id}>" 打出提及也可以。

📌 第 6 步 - 频道创建·删除 + 日志频道设置命令

Python
@bot.event
async def on_guild_channel_create(channel: discord.abc.GuildChannel):
    embed = make_embed("📁 频道创建", discord.Color.green())
    embed.add_field(name="频道", value=f"{channel.mention} (`{channel.name}`)", inline=True)
    embed.add_field(name="类型", value=str(channel.type), inline=True)
    await send_log(channel.guild, embed)


@bot.event
async def on_guild_channel_delete(channel: discord.abc.GuildChannel):
    embed = make_embed("🗂️ 频道删除", discord.Color.red())
    embed.add_field(name="频道", value=f"`{channel.name}`", inline=True)
    embed.add_field(name="类型", value=str(channel.type), inline=True)
    await send_log(channel.guild, embed)


@bot.tree.command(name="로그설정", description="[管理员] 设置发送服务器日志的频道")
@app_commands.describe(채널="用来存放日志的文字频道")
@app_commands.checks.has_permissions(administrator=True)
async def set_log(interaction: discord.Interaction, 채널: discord.TextChannel):
    me = interaction.guild.me
    perms = 채널.permissions_for(me)
    if not (perms.send_messages and perms.embed_links):
        return await interaction.response.send_message(
            f"❌ 我在 {채널.mention} 没有**发送消息·嵌入链接**权限。", ephemeral=True)
    async with lock:
        log_channels[str(interaction.guild.id)] = 채널.id
        save()
    await interaction.response.send_message(f"✅ 以后服务器日志会记录在 {채널.mention}!", ephemeral=True)
    await 채널.send(embed=make_embed("🟢 已设为日志频道", discord.Color.green(), interaction.user))


@bot.tree.command(name="로그해제", description="[管理员] 停止记录服务器日志")
@app_commands.checks.has_permissions(administrator=True)
async def unset_log(interaction: discord.Interaction):
    async with lock:
        log_channels.pop(str(interaction.guild.id), None)
        save()
    await interaction.response.send_message("⏹️ 已关闭日志记录。", ephemeral=True)


@bot.tree.error
async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError):
    if isinstance(error, app_commands.MissingPermissions):
        await interaction.response.send_message("❌ 只有管理员才能使用这个命令。", ephemeral=True)
    else:
        raise error


@bot.event
async def on_ready():
    load()
    await bot.tree.sync()
    print(f"✅ 已登录: {bot.user} / 已设置日志的服务器 {len(log_channels)} 个")


bot.run(token)

执行 /로그설정 (日志设置) 命令后仅自己可见的回复、日志频道收到的设置完成嵌入消息,以及机器人事先检查的项目清单

  • 채널: discord.TextChannel : 把斜杠命令参数的类型设为频道,Discord 就会弹出频道选择界面。就是我们在 #15 命令组篇 里见过的那个功能。
  • 채널.permissions_for(me) : 在设置的时候就提前检查机器人能不能真的在日志频道里发消息。比起之后事件触发时悄悄失败,现在就告诉管理员要友好得多。
  • bot.tree.error : 非管理员输入命令时会抛出 MissingPermissions,不捕获的话只会弹出"交互失败"这种不友好的提示。和 #25 里的写法完全一样。

📎 把第 1~6 步的代码块按顺序拼起来,就是完整版。保存为 logbot.py 直接运行就行。

📌 运行结果

  1. 执行 python logbot.py → 控制台显示 ✅ 已登录: 机器人名字 / 已设置日志的服务器 0 个
  2. 管理员新建一个类似 #서버-로그 (服务器日志) 的私密频道,然后执行 /로그설정 채널:#서버-로그 (日志设置命令) → 会收到一条绿色的"🟢 已设为日志频道"嵌入消息。
  3. 在任意频道发一条消息再删掉 → 🗑️ 红色嵌入消息里会原样留下删除的内容。管理员删除别人的消息时,"删除者"一栏会显示管理员的提及。
  4. 编辑消息 → ✏️ 橙色嵌入消息会并排显示编辑前后的内容,点链接就能跳到那条消息。
  5. 用小号加入服务器再退出 → 会依次出现 📥 加入(账号创建日期"N 分钟前"!) → 📤 离开;如果执行踢出,📤 离开后面还会跟着一条带执行者和原因的 👢 踢出嵌入消息。

💡 日志频道一定要锁好权限,只让管理员看得到。这个频道会原样保留被删消息的内容,普通成员看到的话,就会有人抱怨"我都删了怎么还留着"。另外别忘了大概每个月清理一次旧日志。

💡 附赠 - 增加日志种类

只要在 MOD_ACTIONS 字典里添加条目,审核日志的种类就会增加。下面是常用的几个。

Python
discord.AuditLogAction.member_update: ("⏳ 禁言/昵称变更", discord.Color.gold()),
discord.AuditLogAction.role_create: ("🎨 身份组创建", discord.Color.green()),
discord.AuditLogAction.role_delete: ("🎨 身份组删除", discord.Color.red()),
discord.AuditLogAction.message_bulk_delete: ("🧹 批量删除 (管理员)", discord.Color.dark_red()),

打印 entry.changes.before / entry.changes.after 看看,连"身份组名称从 A 改成了 B""禁言到什么时候"这样的详细变更也能取出来。语音频道进出日志,只要在 #31 用过的 on_voice_state_update 里加一行嵌入消息就搞定了。

📌 常见错误

  1. 删除日志里的内容只显示"(没有内容)" → 原因:没在开发者门户打开 Message Content Intent,或者代码里漏了 intents.message_content = True → 解决:两边都打开并重启机器人。机器人启动之前发出的消息不在缓存里,本来就看不到,这是正常的。
  2. on_member_join / on_member_remove 不触发 → 原因:没设置 Server Members Intent → 解决:在门户 Bot 标签页打开它,并确认 intents.members = True。不开的话连错误都没有,只是悄悄地不触发,很容易让人摸不着头脑。
  3. discord.errors.Forbidden: 403 Forbidden (error code: 50013): Missing Permissions → 原因:机器人的身份组没有查看审核日志权限 → 解决:服务器设置 → 身份组 → 在机器人身份组里勾选"查看审核日志"。没有这个权限的话,on_audit_log_entry_create 也不会触发。
  4. HTTPException: 400 Bad Request (error code: 50035): Invalid Form Body — In embeds.0.fields.2.value: Must be 1024 or fewer in length → 原因:往嵌入字段里放了超过 1024 字的内容 → 解决:像示例里的 cut() 那样截断。如果长消息很多,也可以把内容用 discord.File 作为文本文件附上。
  5. TypeError: 'async_generator' object is not iterable → 原因:用 for 遍历了 guild.audit_logs() → 解决:改成 async for。它是异步迭代器。
  6. 每次贴链接,编辑日志都会出现两次 → 原因:Discord 附加链接预览(嵌入)时会再发送一次编辑事件 → 解决:像示例那样,before.content == after.content 时直接跳过。
  7. 机器人报 discord.errors.PrivilegedIntentsRequired,连启动都启动不了 → 原因:代码里打开了特权 Intent,门户里却没打开 → 解决:门户 Bot 标签页 → Privileged Gateway Intents 里把两个都设为 ON。

🙌 结语

今天我们把 raw 事件 + 审核日志(Audit Log)查询 + on_audit_log_entry_create 三者组合起来,完成了一个从消息删除·编辑到成员进出·身份组变更·踢出·封禁,都以嵌入消息记录到同一个频道的日志机器人。总结一下:

  • 被删消息的内容只有在缓存里时才能看到 → 把 max_messages 调大,打开 2 个特权 Intent
  • 是谁删的要在 guild.audit_logs() 里按 target、频道和时间查找 (本人删除没有记录)
  • 踢出和封禁用 on_audit_log_entry_create 实时接收,连执行者和原因都有
  • 嵌入字段有 1024 字限制,日志频道要锁成仅管理员可见

下一篇会讲 #31 里预告过的临时语音频道扩展 — 转让房主、踢人、仅限邀请(白名单)的房间,以及会同时生成文字频道的"派对房"。敬请期待 🙌

你的服务器最需要哪种日志?欢迎在评论里告诉我,我会考虑加到附赠部分里 😎


📚 推荐一起阅读

连载 · 共 32 篇中的第 31 篇

Discord 机器人开发

  1. #1Discord 机器人开发 - Slash Command 完全攻略!
  2. #2为 Slash Command 添加选项(Arguments)!
  3. #3在 Slash Command 中添加子命令(Subcommand)!
  4. #4用 Slash Command 发送 Embed 嵌入消息!
  5. #5实现按钮(Button)交互!
  6. #6实现下拉菜单(Select Menu)!
  7. #7用模态框(Modal)接收用户输入(Python 示例)
  8. #8用嵌入消息(Embed)的图片和字段美化消息(Python 示例)
  9. #9接入 AI(Claude·ChatGPT API)!(Python 示例)
  10. #10支持多语言(i18n)!(Python 示例)
  11. #11用 Flask 制作网页仪表盘!(Python 示例)
  12. #12管理命令冷却时间(Cooldown)与权限(Permission)!(Python 示例)
  13. #13用身份组·频道自动化管理服务器!(Python 示例)
  14. #14保存数据!JSON vs SQLite(Python 示例)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (韩语)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (韩语)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (韩语)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (韩语)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (韩语)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (韩语)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (韩语)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (韩语)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (韩语)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (韩语)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (韩语)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (韩语)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (韩语)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (韩语)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (韩语)
  30. #30打造投票·问卷(Poll)机器人!原生投票 + 按钮实时统计(Python 示例)🗳️
  31. #32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️当前文章
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (韩语)
显示全部 32 篇收起

作者

Mojangcam

亲手写代码、跑服务器、解决卡住的报错,把一路学到的东西记录下来的开发与 IT 实战博客