From 8e14aac61ce880f5d81c3624c24aeb2bf6b8be51 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 01:25:10 +0000 Subject: [PATCH] =?UTF-8?q?Tier2=E3=83=A1=E3=83=88=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E3=82=B9(=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E6=95=B0=E3=83=BB=E3=83=AC=E3=82=A4=E3=83=86=E3=83=B3?= =?UTF-8?q?=E3=82=B7=E3=83=BB=E3=82=A8=E3=83=A9=E3=83=BC=E7=8E=87)?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sina-chan-monitoring側のF-1(expansion_candidates.md)に対応。 - metrics.py: sina_chan_commands_total / sina_chan_command_errors_total / sina_chan_command_latency_seconds を追加 - bot.py: on_command(開始時刻の保持)・on_command_completion(新設)・ on_command_error(エラー計上)にのみ計装を追加。各cogは変更なし hybrid_commandがslash/prefixどちらの呼び出し経路でも discord.ext.commandsの一元化イベント(command/command_completion/command_error)を 発火することをdiscord.py 2.7.1のソースで確認した上で設計。 純粋なapp_commands(shutdown等3件、discord.ext.commandsを経由しない)は対象外。 --- bot.py | 25 ++++++++++++++++++++++++- metrics.py | 18 +++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index a804feb..2949e9d 100644 --- a/bot.py +++ b/bot.py @@ -11,13 +11,23 @@ import wikidata.client import asyncio import datetime +import time import traceback import aiohttp import aiosqlite import database -from metrics import start_metrics_server, BOT_READY, BOT_GUILD_COUNT, BOT_LATENCY_SECONDS, BOT_SHARD_COUNT +from metrics import ( + start_metrics_server, + BOT_READY, + BOT_GUILD_COUNT, + BOT_LATENCY_SECONDS, + BOT_SHARD_COUNT, + BOT_COMMANDS_TOTAL, + BOT_COMMAND_ERRORS_TOTAL, + BOT_COMMAND_LATENCY_SECONDS, +) from twitter import * from dateutil.relativedelta import relativedelta as rdelta @@ -649,6 +659,7 @@ async def rtopic(ctx, ch:discord.TextChannel=None): @bot.event async def on_command(ctx:commands.Context): + ctx._t2_start = time.monotonic() if ctx.interaction:return ch = await bot.fetch_channel(693048961107230811) e = discord.Embed(title=f"prefixコマンド:{ctx.command.full_parent_name}の実行", @@ -667,6 +678,15 @@ async def on_command(ctx:commands.Context): e.timestamp = ctx.message.created_at await ch.send(embed=e) +@bot.event +async def on_command_completion(ctx:commands.Context): + command_name = ctx.command.qualified_name + cmd_type = "slash" if ctx.interaction else "prefix" + BOT_COMMANDS_TOTAL.labels(command=command_name, type=cmd_type).inc() + start = getattr(ctx, "_t2_start", None) + if start is not None: + BOT_COMMAND_LATENCY_SECONDS.labels(command=command_name, type=cmd_type).observe(time.monotonic() - start) + @bot.event async def on_interaction(interaction:discord.Interaction): ch = await bot.fetch_channel(693048961107230811) @@ -698,6 +718,9 @@ async def on_command_error(ctx, error): el""" if isinstance(error, commands.HybridCommandError): error = error.original + command_name = ctx.command.qualified_name if ctx.command else "(unknown)" + cmd_type = "slash" if ctx.interaction else "prefix" + BOT_COMMAND_ERRORS_TOTAL.labels(command=command_name, type=cmd_type, error_type=type(error).__name__).inc() if isinstance(error, (commands.CommandOnCooldown, app_commands.CommandOnCooldown)): # クールダウン embed = discord.Embed(title=await ctx._("cmd-error-t"), description=await ctx._( diff --git a/metrics.py b/metrics.py index 0289503..9578750 100644 --- a/metrics.py +++ b/metrics.py @@ -1,10 +1,26 @@ -from prometheus_client import start_http_server, Gauge +from prometheus_client import start_http_server, Gauge, Counter, Histogram BOT_READY = Gauge("sina_chan_ready", "1 if the bot is ready, 0 otherwise") BOT_GUILD_COUNT = Gauge("sina_chan_guild_count", "Number of guilds the bot is in") BOT_LATENCY_SECONDS = Gauge("sina_chan_latency_seconds", "Discord gateway latency") BOT_SHARD_COUNT = Gauge("sina_chan_shard_count", "Number of shards") +BOT_COMMANDS_TOTAL = Counter( + "sina_chan_commands_total", + "Number of commands that completed successfully", + ["command", "type"], +) +BOT_COMMAND_ERRORS_TOTAL = Counter( + "sina_chan_command_errors_total", + "Number of commands that ended in an error", + ["command", "type", "error_type"], +) +BOT_COMMAND_LATENCY_SECONDS = Histogram( + "sina_chan_command_latency_seconds", + "Command execution time in seconds, from invocation to successful completion", + ["command", "type"], +) + def start_metrics_server(port: int = 9200) -> None: # ループバック限定。既存のmysqld_exporter・blackbox_exporterと同じ考え方で、