shaiwatcher/modules/usage/usage_stats.py
Franz Rolfsvaag 4e86eb43fc 0.4.1.0.a2
- Docs site changes
  - Details brief no longer opens automatically on narrower devices
  - Implemented a counter that displays the number of executions for each command
2025-08-16 02:26:49 +02:00

83 lines
3.3 KiB
Python

# modules/usage/usage_stats.py
from __future__ import annotations
from discord.ext import commands
import discord
COUNTER_KEY_PREFIX = "cmd::"
def _key_from_app(cmd: discord.app_commands.Command) -> str:
# app command qualified_name is "group sub" or "name"
name = getattr(cmd, "qualified_name", None) or getattr(cmd, "name", "unknown")
return f"{COUNTER_KEY_PREFIX}{name}"
def _key_from_ctx(ctx: commands.Context) -> str:
# prefix/hybrid qualified_name is "group sub" or "name"
c = getattr(ctx, "command", None)
name = getattr(c, "qualified_name", None) or getattr(c, "name", "unknown")
return f"{COUNTER_KEY_PREFIX}{name}"
class UsageStatsCog(commands.Cog):
"""Lightweight command run/attempt counters persisted in DataManager."""
def __init__(self, bot: commands.Bot):
self.bot = bot
print("[usage] UsageStatsCog init")
# ---- successful completions ----
@commands.Cog.listener()
async def on_app_command_completion(self, interaction: discord.Interaction, command: discord.app_commands.Command):
dm = getattr(self.bot, "data_manager", None)
if not dm:
print("[usage] skip app (no data_manager)")
return
try:
key = _key_from_app(command)
newv = dm.incr_counter(key, 1)
print(f"[usage] app ++ {key} -> {newv}")
except Exception as e:
print("[usage] incr app failed:", repr(e))
@commands.Cog.listener()
async def on_command_completion(self, ctx: commands.Context):
dm = getattr(self.bot, "data_manager", None)
if not dm:
print("[usage] skip prefix (no data_manager)")
return
try:
key = _key_from_ctx(ctx)
newv = dm.incr_counter(key, 1)
print(f"[usage] px ++ {key} -> {newv}")
except Exception as e:
print("[usage] incr prefix failed:", repr(e))
# ---- attempts that error (optional but useful while testing) ----
@commands.Cog.listener()
async def on_app_command_error(self, interaction: discord.Interaction, error: Exception):
# Count attempts (separate key) so you can confirm the listener fires at all.
dm = getattr(self.bot, "data_manager", None)
cmd = getattr(interaction, "command", None)
if dm and isinstance(cmd, discord.app_commands.Command):
try:
key = _key_from_app(cmd).replace("cmd::", "cmd_attempt::")
newv = dm.incr_counter(key, 1)
print(f"[usage] app !! {key} -> {newv} ({type(error).__name__})")
except Exception as e:
print("[usage] app err incr failed:", repr(e))
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context, error: Exception):
dm = getattr(self.bot, "data_manager", None)
if dm and getattr(ctx, "command", None):
try:
key = _key_from_ctx(ctx).replace("cmd::", "cmd_attempt::")
newv = dm.incr_counter(key, 1)
print(f"[usage] px !! {key} -> {newv} ({type(error).__name__})")
except Exception as e:
print("[usage] px err incr failed:", repr(e))
async def setup(bot: commands.Bot):
await bot.add_cog(UsageStatsCog(bot))
print("[usage] UsageStatsCog loaded")