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と同じ考え方で、