Files
server-manager/src/Services/MonitoringService.php

246 lines
8.0 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace ServerManager\Services;
use ServerManager\Core\Database;
use ServerManager\Core\Logger;
use ServerManager\Core\App;
use ServerManager\Services\SSHService;
class MonitoringService
{
private Database $db;
private Logger $logger;
public function __construct()
{
$this->db = Database::getInstance();
$this->logger = Logger::getInstance();
}
public function collectMetrics(int $serverId): ?array
{
$server = $this->db->fetch('SELECT * FROM servers WHERE id = ? AND status = \'active\'', [$serverId]);
if (!$server || !$server['is_active']) {
return null;
}
$server = App::getEncryption()->decryptArray($server, ['ssh_password', 'ssh_key']);
try {
$ssh = new SSHService();
if (!$ssh->connect($server, true)) {
return ['status' => 'offline'];
}
$metrics = [
'server_id' => $serverId,
'status' => 'online',
'cpu_usage' => $this->getCPUUsage($ssh),
'ram_usage' => $this->getRAMUsage($ssh),
'disk_usage' => $this->getDiskUsage($ssh),
'load_average' => $this->getLoadAverage($ssh),
'uptime' => $this->getUptime($ssh),
];
$this->saveMetrics($metrics);
$ssh->disconnect();
return $metrics;
} catch (\Throwable $e) {
$this->logger->warning("Failed to collect metrics for server {$serverId}: " . $e->getMessage());
$this->saveMetrics([
'server_id' => $serverId,
'status' => 'offline',
'cpu_usage' => 0,
'ram_usage' => 0,
'disk_usage' => 0,
'load_average' => 0,
'uptime' => '',
]);
return ['status' => 'offline'];
}
}
public function collectAllMetrics(): array
{
$servers = $this->db->fetchAll('SELECT * FROM servers WHERE status = \'active\' AND is_active = 1');
$results = [];
foreach ($servers as $server) {
$results[$server['id']] = $this->collectMetrics($server['id']);
}
return $results;
}
private function getCPUUsage(SSHService $ssh): float
{
$result = $ssh->exec("top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1");
return (float) trim($result['output']);
}
private function getRAMUsage(SSHService $ssh): float
{
$result = $ssh->exec("free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100}'");
return (float) trim($result['output']);
}
private function getDiskUsage(SSHService $ssh): float
{
$result = $ssh->exec("df / | tail -1 | awk '{print $5}' | sed 's/%//'");
return (float) trim($result['output']);
}
private function getLoadAverage(SSHService $ssh): float
{
$result = $ssh->exec("cat /proc/loadavg | awk '{print $1}'");
return (float) trim($result['output']);
}
private function getUptime(SSHService $ssh): string
{
$result = $ssh->exec("uptime -p");
return trim(str_replace('up ', '', $result['output']));
}
public function saveMetrics(array $metrics): void
{
$now = date('Y-m-d H:i:s');
$this->db->insert('monitoring_history', [
'server_id' => $metrics['server_id'],
'status' => $metrics['status'],
'cpu_usage' => $metrics['cpu_usage'],
'ram_usage' => $metrics['ram_usage'],
'disk_usage' => $metrics['disk_usage'],
'load_average' => $metrics['load_average'],
'uptime' => $metrics['uptime'] ?? '',
'created_at' => $now,
]);
$this->db->query(
"UPDATE servers SET
last_check_at = ?,
current_status = ?,
cpu_usage = ?,
ram_usage = ?,
disk_usage = ?,
load_average = ?,
uptime = ?
WHERE id = ?",
[
$now,
$metrics['status'],
$metrics['cpu_usage'],
$metrics['ram_usage'],
$metrics['disk_usage'],
$metrics['load_average'],
$metrics['uptime'] ?? '',
$metrics['server_id'],
]
);
$retention = App::getConfig()['monitoring']['retention_days'] ?? 30;
$this->db->query(
"DELETE FROM monitoring_history WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)",
[$retention]
);
}
public function getLatestMetrics(int $serverId): ?array
{
return $this->db->fetch(
'SELECT * FROM monitoring_history WHERE server_id = ? ORDER BY created_at DESC LIMIT 1',
[$serverId]
);
}
public function getHistoricalMetrics(int $serverId, int $hours = 24): array
{
return $this->db->fetchAll(
'SELECT * FROM monitoring_history
WHERE server_id = ? AND created_at >= DATE_SUB(NOW(), INTERVAL ? HOUR)
ORDER BY created_at ASC',
[$serverId, $hours]
);
}
public function getAggregatedHistoricalMetrics(array $serverIds, int $hours = 24): array
{
if (empty($serverIds)) {
return [];
}
$placeholders = implode(',', array_fill(0, count($serverIds), '?'));
$params = $serverIds;
$params[] = $hours;
return $this->db->fetchAll(
"SELECT
DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:00') as time_bucket,
AVG(cpu_usage) as avg_cpu,
AVG(ram_usage) as avg_ram,
AVG(disk_usage) as avg_disk
FROM monitoring_history
WHERE server_id IN ({$placeholders})
AND created_at >= DATE_SUB(NOW(), INTERVAL ? HOUR)
GROUP BY time_bucket
ORDER BY time_bucket ASC",
$params
);
}
public function getDashboardStats(?array $serverIds = null): array
{
$where = '';
$params = [];
if ($serverIds !== null) {
if (empty($serverIds)) {
$serverIds = [-1];
}
$placeholders = implode(',', array_fill(0, count($serverIds), '?'));
$where = " AND s.id IN ({$placeholders})";
$params = $serverIds;
}
$totalServers = $this->db->fetch("SELECT COUNT(*) as total FROM servers s WHERE s.status = 'active'{$where}", $params);
$onlineServers = $this->db->fetch(
"SELECT COUNT(*) as total FROM servers s WHERE s.current_status = 'online' AND s.status = 'active' AND s.is_active = 1{$where}",
$params
);
$offlineServers = $this->db->fetch(
"SELECT COUNT(*) as total FROM servers s WHERE s.current_status = 'offline' AND s.status = 'active' AND s.is_active = 1{$where}",
$params
);
$avgCpu = $this->db->fetch(
"SELECT AVG(s.cpu_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
$params
);
$avgRam = $this->db->fetch(
"SELECT AVG(s.ram_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
$params
);
$avgDisk = $this->db->fetch(
"SELECT AVG(s.disk_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
$params
);
return [
'total_servers' => (int) ($totalServers['total'] ?? 0),
'online_servers' => (int) ($onlineServers['total'] ?? 0),
'offline_servers' => (int) ($offlineServers['total'] ?? 0),
'avg_cpu' => round((float) ($avgCpu['avg'] ?? 0), 1),
'avg_ram' => round((float) ($avgRam['avg'] ?? 0), 1),
'avg_disk' => round((float) ($avgDisk['avg'] ?? 0), 1),
];
}
}