"""Status cog - provides bot health and metrics commands.""" import logging import discord from discord.ext import commands from daemon_boyfriend.utils import HealthStatus, get_monitor logger = logging.getLogger(__name__) class StatusCog(commands.Cog): """Bot status and monitoring commands.""" def __init__(self, bot: commands.Bot) -> None: self.bot = bot @commands.command(name="status") @commands.has_permissions(administrator=True) async def status_command(self, ctx: commands.Context) -> None: """Show bot status and metrics (admin only).""" monitor = get_monitor() metrics = monitor.get_metrics() # Choose embed color based on health status color_map = { HealthStatus.HEALTHY: discord.Color.green(), HealthStatus.DEGRADED: discord.Color.yellow(), HealthStatus.UNHEALTHY: discord.Color.red(), } color = color_map.get(metrics.health_status, discord.Color.grey()) # Format uptime uptime_hours = metrics.uptime_seconds / 3600 if uptime_hours >= 24: uptime_str = f"{uptime_hours / 24:.1f} days" elif uptime_hours >= 1: uptime_str = f"{uptime_hours:.1f} hours" else: uptime_str = f"{metrics.uptime_seconds / 60:.1f} minutes" # Create embed embed = discord.Embed( title="Bot Status Report", color=color, ) # Status field with emoji status_emoji = { HealthStatus.HEALTHY: "🟢", HealthStatus.DEGRADED: "🟡", HealthStatus.UNHEALTHY: "🔴", } embed.add_field( name="Status", value=f"{status_emoji.get(metrics.health_status, '⚪')} {metrics.health_status.value.upper()}", inline=True, ) embed.add_field(name="Uptime", value=uptime_str, inline=True) embed.add_field(name="Guilds", value=str(len(self.bot.guilds)), inline=True) # Request metrics embed.add_field( name="Requests", value=f"Total: {metrics.total_requests}\n" f"Success: {metrics.successful_requests}\n" f"Failed: {metrics.failed_requests}", inline=True, ) embed.add_field( name="Performance", value=f"Avg response: {metrics.avg_response_time_ms:.0f}ms\n" f"Req/min: {metrics.requests_per_minute:.1f}\n" f"Error rate: {metrics.error_rate_percent:.1f}%", inline=True, ) # Last activity last_success = "Never" if metrics.last_successful_request: last_success = metrics.last_successful_request.strftime("%Y-%m-%d %H:%M:%S UTC") last_error = "None" if metrics.last_error: last_error = metrics.last_error.strftime("%Y-%m-%d %H:%M:%S UTC") embed.add_field( name="Last Activity", value=f"Success: {last_success}\nError: {last_error}", inline=False, ) # Recent errors (if any) if metrics.recent_errors: error_lines = [] for error in metrics.recent_errors[-3:]: # Last 3 errors time_str = error.timestamp.strftime("%H:%M:%S") error_lines.append(f"`{time_str}` **{error.error_type}**: {error.message[:50]}...") embed.add_field( name="Recent Errors", value="\n".join(error_lines), inline=False, ) await ctx.send(embed=embed) @commands.command(name="health") async def health_command(self, ctx: commands.Context) -> None: """Quick health check (anyone can use).""" monitor = get_monitor() metrics = monitor.get_metrics() status_emoji = { HealthStatus.HEALTHY: "🟢", HealthStatus.DEGRADED: "🟡", HealthStatus.UNHEALTHY: "🔴", } emoji = status_emoji.get(metrics.health_status, "⚪") status = metrics.health_status.value # Format uptime uptime_hours = metrics.uptime_seconds / 3600 if uptime_hours >= 1: uptime_str = f"{uptime_hours:.1f}h" else: uptime_str = f"{metrics.uptime_seconds / 60:.0f}m" await ctx.send( f"{emoji} **{status.upper()}** | Uptime: {uptime_str} | Requests: {metrics.total_requests}" ) @status_command.error async def status_error(self, ctx: commands.Context, error: commands.CommandError) -> None: """Handle status command errors.""" if isinstance(error, commands.MissingPermissions): await ctx.send("You need administrator permissions to view detailed status.") else: logger.error(f"Status command error: {error}") async def setup(bot: commands.Bot) -> None: """Load the Status cog.""" await bot.add_cog(StatusCog(bot))