延續昨天主題,今天接著介紹錯誤處理。
進度

昨天介紹了日誌系統,今天來介紹與它息息相關的錯誤處理。
進度圖跟昨天一樣 XD
錯誤處理
其實 discord.py
已經幫忙處理很多錯誤了,只不過,有時候我們還是會希望可以稍微插手一下,讓 Discord BOT 可以呈現一些錯誤提示;或者是使用昨天介紹的日誌系統,把需要的資訊紀錄都記錄下來。
接下來,會盡量把前面幾種不同的功能的錯誤處理都展示一下。
Client
的 event
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import discord
intents = discord.Intents.default() intents.message_content = True
client = discord.Client(intents=intents)
@client.event async def on_message(message: discord.Message): if message.author == client.user: return
if message.content.startswith("ping"): a = 1 / 0 await message.channel.send("Pong!")
@client.event async def on_error(event, *args, **kwargs): print(f"發生錯誤: {event} {args} {kwargs}") if event == "on_message": await args[0].channel.send(f"{event} 發生錯誤了!")
bot.run('token')
|

當對事件的處理發生錯誤時,就可以被 on_error
捕捉到。雖然可以知道是哪一個事件觸發的,但詳細的錯誤訊息需要另外用 sys.exc_info()
才能拿到了。
Bot
的 command
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import discord from discord.ext import commands
intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='>', intents=intents)
@bot.command() async def ping(ctx): a = 1 / 0 await ctx.send('pong')
@bot.event async def on_command_error(ctx: commands.Context, error: commands.CommandError): await ctx.send(f"發生錯誤了: {error}")
bot.run('token')
|

Bot
可以用自己的 on_command_error
捕捉 bot.command
內的錯誤,不用跟 on_error
擠在一起。
CommandTree
內的 command
這邊用 Slash Command 作為例子
1 2 3 4 5 6 7 8 9 10 11 12
|
@bot.tree.command() async def ping(interaction: discord.Interaction): a = 1 / 0 await interaction.response.send_message("Pong!")
@bot.tree.error async def on_error(interaction: discord.Interaction, error: Exception) -> None: await interaction.response.send_message(f"Oops! {error}", ephemeral=True)
|

當 CommandTree
這個容器內的應用指令發生錯誤時,可以用 on_error
來捕捉錯誤。如果需要知道是哪個應用指令出錯,可以用 discord.Interaction.command
取得。
元件的 callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
async def on_click(interaction: discord.Interaction): a = 1 / 0 await interaction.response.send_message("剛剛點擊了按鈕")
async def on_btn_error( interaction: discord.Interaction, error: Exception, item: discord.ui.Item ) -> None: await interaction.response.send_message(f"Oops! {error}", ephemeral=True)
@bot.command() async def ping(ctx: commands.Context): view = discord.ui.View() btn = discord.ui.Button(label="我是按鈕") btn.callback = on_click view.add_item(btn) view.on_error = on_btn_error await ctx.send("點擊下方按鈕", view=view)
|

如果要捕捉 View
內的錯誤,可以用 View.on_error
來設定。有需要的話,可以從 Item
來取得發生錯誤的元件的相關資訊。
Modal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
class Questionnaire(discord.ui.Modal, title="Questionnaire Response"): name = discord.ui.TextInput(label='Name') answer = discord.ui.TextInput(label='Answer', style=discord.TextStyle.paragraph)
async def on_submit(self, interaction: discord.Interaction): a = 1 / 0 await interaction.response.send_message( f"Thanks for your response, {self.name}!", ephemeral=True ) async def on_error(self, interaction: discord.Interaction, error: Exception) -> None: await interaction.response.send_message(f"Oops! {error}", ephemeral=True)
|

如果在 on_submit
發生錯誤,則會被 on_error
捕捉到。由於 Modal 一定要用 subclass 的方式,所以就直接把 on_error
放在 class 之中就好了。同時,這樣管理這些程式碼也可以提高可維護性。
Task
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import discord import logging from discord.ext import commands, tasks
intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='', intents=intents) logger = logging.getLogger("discord")
@bot.command() async def ping(ctx): slow_count.start() await ctx.send('pong')
@tasks.loop(seconds=1.0, count=5) async def slow_count(): a = 1 / (3 - slow_count.current_loop) await ctx.send(slow_count.current_loop)
@slow_count.after_loop async def after_slow_count(): logger.info('done!')
@slow_count.error async def on_slow_count_error(error: Exception): logger.error(f"{error}")
bot.run('token')
|
Discord BOT 在執行第 4 次的時候發生錯誤,導致只有傳送 0 到 2,後面剩餘的次數就沒繼續執行了。

雖然 task 中斷了,但是 after_loop
的內容依然有執行 (紀錄 Log)。而且,發生錯誤的那次,有被 error
捕捉到。

小結
今天介紹了各種情境下要如何去捕捉錯誤,之後不論是要像這篇文章一樣,讓 Discord BOT 把錯誤訊息回傳出來;或是使用昨天介紹的日誌系統,把這些錯誤訊息記錄下來,都是可以的做法。