Update: Code formatting
All checks were successful
CI/CD Pipeline / Unit Tests (Python 3.10) (push) Successful in 9m23s
CI/CD Pipeline / Unit Tests (Python 3.11) (push) Successful in 9m19s
CI/CD Pipeline / Unit Tests (Python 3.9) (push) Successful in 9m19s
CI/CD Pipeline / Code Quality & Linting (push) Successful in 44s
CI/CD Pipeline / Security Scanning (push) Successful in 16s
CI/CD Pipeline / Integration Tests (push) Successful in 9m14s
CI/CD Pipeline / Build Docker Image (push) Successful in 36s
CI/CD Pipeline / Generate Test Report (push) Successful in 4s
CI/CD Pipeline / CI/CD Pipeline Status (push) Successful in 1s
CI/CD Pipeline / Unit Tests (Python 3.10) (pull_request) Successful in 9m19s
CI/CD Pipeline / Unit Tests (Python 3.11) (pull_request) Successful in 9m17s
CI/CD Pipeline / Unit Tests (Python 3.9) (pull_request) Successful in 9m19s
CI/CD Pipeline / Code Quality & Linting (pull_request) Successful in 41s
CI/CD Pipeline / Security Scanning (pull_request) Successful in 15s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 9m14s
CI/CD Pipeline / Build Docker Image (pull_request) Has been skipped
CI/CD Pipeline / Generate Test Report (pull_request) Successful in 2s
CI/CD Pipeline / CI/CD Pipeline Status (pull_request) Successful in 1s

This commit is contained in:
2025-10-27 09:43:24 +00:00
parent 5e61c838d5
commit bec3efcdd0
2 changed files with 180 additions and 506 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -5,15 +5,16 @@ This module provides graphing capabilities for server CPU and memory usage.
Generates line graphs as PNG images for embedding in Discord messages.
"""
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from collections import deque
from datetime import datetime
from typing import Dict, Optional
import io
import logging
import math
from collections import deque
from datetime import datetime
from typing import Dict, Optional
import matplotlib
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
matplotlib.use("Agg") # Use non-interactive backend for server environments
@@ -52,13 +53,9 @@ class ServerMetricsGraphs:
# Track if we have enough data for meaningful graphs (at least 2 points)
self.has_sufficient_data = False
logger.debug(
f"Initialized metrics tracking for server {server_name} ({server_id})"
)
logger.debug(f"Initialized metrics tracking for server {server_name} ({server_id})")
def add_data_point(
self, cpu_percent: float, memory_mb: float, timestamp: Optional[datetime] = None
):
def add_data_point(self, cpu_percent: float, memory_mb: float, timestamp: Optional[datetime] = None):
"""
Add a new data point to the metrics history.
@@ -76,9 +73,7 @@ class ServerMetricsGraphs:
# Update sufficient data flag
self.has_sufficient_data = len(self.data_points) >= 2
logger.debug(
f"Added metrics data point for {self.server_name}: CPU={cpu_percent}%, Memory={memory_mb}MB"
)
logger.debug(f"Added metrics data point for {self.server_name}: CPU={cpu_percent}%, Memory={memory_mb}MB")
def _calculate_cpu_scale_limit(self, max_cpu_value: float) -> int:
"""
@@ -105,9 +100,7 @@ class ServerMetricsGraphs:
BytesIO object containing PNG image data, or None if insufficient data
"""
if not self.has_sufficient_data:
logger.debug(
f"Insufficient data for CPU graph generation: {self.server_name}"
)
logger.debug(f"Insufficient data for CPU graph generation: {self.server_name}")
return None
try:
@@ -134,9 +127,7 @@ class ServerMetricsGraphs:
# Add horizontal grid lines at 100% increments for better readability
for i in range(100, cpu_scale_limit + 1, 100):
ax.axhline(
y=i, color="#ffffff", alpha=0.2, linestyle="--", linewidth=0.8
)
ax.axhline(y=i, color="#ffffff", alpha=0.2, linestyle="--", linewidth=0.8)
# Format time axis
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S"))
@@ -182,15 +173,11 @@ class ServerMetricsGraphs:
# Clean up matplotlib resources
plt.close(fig)
logger.debug(
f"Generated CPU graph for {self.server_name} (scale: 0-{cpu_scale_limit}%)"
)
logger.debug(f"Generated CPU graph for {self.server_name} (scale: 0-{cpu_scale_limit}%)")
return img_buffer
except Exception as e:
logger.error(
f"Failed to generate CPU graph for {self.server_name}: {str(e)}"
)
logger.error(f"Failed to generate CPU graph for {self.server_name}: {str(e)}")
plt.close("all") # Clean up any remaining figures
return None
@@ -202,9 +189,7 @@ class ServerMetricsGraphs:
BytesIO object containing PNG image data, or None if insufficient data
"""
if not self.has_sufficient_data:
logger.debug(
f"Insufficient data for memory graph generation: {self.server_name}"
)
logger.debug(f"Insufficient data for memory graph generation: {self.server_name}")
return None
try:
@@ -274,9 +259,7 @@ class ServerMetricsGraphs:
return img_buffer
except Exception as e:
logger.error(
f"Failed to generate memory graph for {self.server_name}: {str(e)}"
)
logger.error(f"Failed to generate memory graph for {self.server_name}: {str(e)}")
plt.close("all") # Clean up any remaining figures
return None
@@ -288,9 +271,7 @@ class ServerMetricsGraphs:
BytesIO object containing PNG image data, or None if insufficient data
"""
if not self.has_sufficient_data:
logger.debug(
f"Insufficient data for combined graph generation: {self.server_name}"
)
logger.debug(f"Insufficient data for combined graph generation: {self.server_name}")
return None
try:
@@ -326,9 +307,7 @@ class ServerMetricsGraphs:
# Add horizontal grid lines at 100% increments for CPU subplot
for i in range(100, cpu_scale_limit + 1, 100):
ax1.axhline(
y=i, color="#ffffff", alpha=0.2, linestyle="--", linewidth=0.8
)
ax1.axhline(y=i, color="#ffffff", alpha=0.2, linestyle="--", linewidth=0.8)
# Title with vCPU info if applicable
title = f"{self.server_name} - Resource Usage"
@@ -387,15 +366,11 @@ class ServerMetricsGraphs:
plt.close(fig)
logger.debug(
f"Generated combined graph for {self.server_name} (CPU scale: 0-{cpu_scale_limit}%)"
)
logger.debug(f"Generated combined graph for {self.server_name} (CPU scale: 0-{cpu_scale_limit}%)")
return img_buffer
except Exception as e:
logger.error(
f"Failed to generate combined graph for {self.server_name}: {str(e)}"
)
logger.error(f"Failed to generate combined graph for {self.server_name}: {str(e)}")
plt.close("all")
return None
@@ -468,9 +443,7 @@ class ServerMetricsManager:
self.server_graphs: Dict[str, ServerMetricsGraphs] = {}
logger.info("Initialized ServerMetricsManager")
def get_or_create_server_graphs(
self, server_id: str, server_name: str
) -> ServerMetricsGraphs:
def get_or_create_server_graphs(self, server_id: str, server_name: str) -> ServerMetricsGraphs:
"""
Get existing ServerMetricsGraphs instance or create a new one.
@@ -487,9 +460,7 @@ class ServerMetricsManager:
return self.server_graphs[server_id]
def add_server_data(
self, server_id: str, server_name: str, cpu_percent: float, memory_mb: float
):
def add_server_data(self, server_id: str, server_name: str, cpu_percent: float, memory_mb: float):
"""
Add data point to a server's metrics tracking.
@@ -541,9 +512,7 @@ class ServerMetricsManager:
self.remove_server(server_id)
if servers_to_remove:
logger.info(
f"Cleaned up metrics for {len(servers_to_remove)} inactive servers"
)
logger.info(f"Cleaned up metrics for {len(servers_to_remove)} inactive servers")
def get_summary(self) -> Dict[str, any]:
"""
@@ -554,12 +523,6 @@ class ServerMetricsManager:
"""
return {
"total_servers": len(self.server_graphs),
"servers_with_data": sum(
1
for graphs in self.server_graphs.values()
if graphs.has_sufficient_data
),
"total_data_points": sum(
len(graphs.data_points) for graphs in self.server_graphs.values()
),
"servers_with_data": sum(1 for graphs in self.server_graphs.values() if graphs.has_sufficient_data),
"total_data_points": sum(len(graphs.data_points) for graphs in self.server_graphs.values()),
}