はじめに
discord botやその他アプリケーションを運用する際、エラーを一元管理するためにSentryを導入しました。
その際にdiscord botで行った手順を紹介します。
Sentryとは
Sentry とは、エラーを検知、監視できるサービスです。
複数アプリケーションのエラーを一元管理できます。
エラー監視方法
プロジェクトの作成
Choose a platform: 「PYTHON」を選択します。
Set your default alert settings:デフォルトの「I'll create my own alerts later」を選択します。
プロジェクトに名前を付けてください:プロジェクト名を設定します。
Sentry用環境変数の設定
プロジェクトの作成完了後、使い方が表示されます。
この使い方に従えばSentryでエラー監視できます。
ただし、 sentry_sdk.init
の最初の引数、DSNはハードコーディングを避け、環境変数として設定しましょう。
DSNとはData Source Nameの略で、エラーなどイベントの送信先です。Sentryのプロジェクトごとに作成されます。
DSNが外部に流出すると、あなたのプロジェクトに第三者がイベントを送信する可能性があります。
そのため環境変数としてDSNを設定しましょう。
今回は .env
を使って環境変数を設定します。
-
.env
を扱うためのパッケージをインストールPipenvやPoetryなどパッケージ管理ツールを使う場合は適宜読み替えてください。
pip install python-dotenv
-
.env
ファイルを作成.envSENTRY_DSN="https://xxxxxxxxxxxx" SENTRY_ENVIRONMENT="development"
SENTRY_DSN
の値にDSNを設定します。未設定の場合、Sentryへイベント送信を行いません。SENTRY_ENVIRONMENT
ではproduction、developmentなどの環境を表す文字列を設定できます。Sentryでは他にも環境変数を設定できます。詳細は、公式ドキュメント を参照ください。
例外のキャプチャ
Sentryはデフォルトでは、キャッチされない例外、ログレベルERROR以上のログをイベントとして送信します。
discord.pyはBotが停止しないよう、デフォルトでエラーをハンドリングしていて、そのままではイベントが送信されません。
コマンドは on_command_error 、タスクは tasks.Loop.error 内で capture_exception
を使ってエラーをキャプチャする必要があります。
import os
import sentry_sdk
from discord.ext import commands, tasks
from dotenv import load_dotenv
from sentry_sdk import capture_exception
class MyBot(commands.Bot):
async def on_ready(self):
print(f"Ready: {self.user}")
self.add_cog(MyCog(self))
async def on_command_error(self, context: commands.Context, exception: Exception):
capture_exception(exception)
return await super().on_command_error(context, exception)
class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.do_task.start()
@commands.command()
async def ping(self, ctx: commands.Context):
await ctx.send("pong")
@tasks.loop(minutes=1)
async def do_task(self):
1 / 0
@do_task.error
async def task_error(self, exception: Exception):
capture_exception(exception)
def main():
load_dotenv()
sentry_sdk.init(traces_sample_rate=1.0)
token = os.environ["DISCORD_BOT_TOKEN"]
bot = MyBot(command_prefix="/")
bot.run(token)
if __name__ == "__main__":
main()
注:コード例では環境変数 DISCORD_BOT_TOKEN
にdiscord botのtokenを設定しています。
存在しないコマンドを入力したり、時間経過でタスクが実行されると、画像のようにIssueへエラーが追加されていきます。
Discord/Slackとの連携
このままではエラーが発生しても通知が来ず不便です。
DiscordやSlackと連携して、エラーの通知が来るようにしましょう。
現在、Slack integrationは有料プランのみになっていますが、Slack(Legacy)のURLに直接アクセスすれば無料プランでも設定可能なようです。
以下の記事を参考にして、設定することができました。
Webhook URLを変更すれば、Slackも通知可能です。