feat: Implement server and client metrics collection and monitoring
- Added a new PHP script for collecting server metrics every 30 seconds. - Created a ServerMonitoring class to handle metrics collection for CPU, RAM, Disk, and Network. - Introduced database tables for storing server and client metrics. - Updated server view template to display real-time metrics using Chart.js. - Added translations for monitoring UI elements. - Created a new monitoring template for detailed server metrics visualization. - Implemented client speed tracking and display in the monitoring UI.
This commit is contained in:
@@ -1,5 +1,34 @@
|
||||
{% extends "layout.twig" %}
|
||||
{% block title %}{{ t('servers.title') }}{% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
<style>
|
||||
.server-metrics {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 0.75rem;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.metric-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 6px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.metric-badge i {
|
||||
font-size: 10px;
|
||||
}
|
||||
.metric-sparkline {
|
||||
height: 20px;
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-7xl mx-auto px-4 py-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
@@ -27,12 +56,13 @@
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">{{ t('servers.name') }}</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">{{ t('servers.host') }}</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">{{ t('servers.status') }}</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">{{ t('common.metrics') }}</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">{{ t('servers.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for server in servers %}
|
||||
<tr class="border-t">
|
||||
<tr class="border-t" data-server-id="{{ server.id }}">
|
||||
<td class="px-6 py-4 font-medium">{{ server.name }}</td>
|
||||
<td class="px-6 py-4">{{ server.host }}</td>
|
||||
<td class="px-6 py-4">
|
||||
@@ -40,6 +70,30 @@
|
||||
{{ server.status }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{% if server.status == 'active' %}
|
||||
<div class="server-metrics" id="metrics-{{ server.id }}">
|
||||
<div class="metric-badge">
|
||||
<i class="fas fa-microchip" style="color:#dc3545"></i>
|
||||
<span class="metric-val" data-metric="cpu">--</span>
|
||||
</div>
|
||||
<div class="metric-badge">
|
||||
<i class="fas fa-memory" style="color:#ffc107"></i>
|
||||
<span class="metric-val" data-metric="ram">--</span>
|
||||
</div>
|
||||
<div class="metric-badge">
|
||||
<i class="fas fa-hdd" style="color:#17a2b8"></i>
|
||||
<span class="metric-val" data-metric="disk">--</span>
|
||||
</div>
|
||||
<div class="metric-badge">
|
||||
<i class="fas fa-network-wired" style="color:#28a745"></i>
|
||||
<span class="metric-val" data-metric="network">--</span>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-gray-400 text-xs">Not deployed</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 space-x-3">
|
||||
<a href="/servers/{{ server.id }}" class="text-purple-600 hover:text-purple-900">
|
||||
<i class="fas fa-eye mr-1"></i>{{ t('servers.view') }}
|
||||
@@ -64,3 +118,65 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Get all active server IDs
|
||||
const activeServers = [
|
||||
{% for server in servers %}
|
||||
{% if server.status == 'active' %}
|
||||
{{ server.id }},
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
async function updateServerMetrics(serverId) {
|
||||
try {
|
||||
const response = await fetch(`/api/servers/${serverId}/metrics?hours=1`, {
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
console.log(`Server ${serverId} metrics:`, data);
|
||||
|
||||
if (data.success && data.metrics.length > 0) {
|
||||
const latest = data.metrics[data.metrics.length - 1];
|
||||
const metricsDiv = document.getElementById(`metrics-${serverId}`);
|
||||
|
||||
console.log(`Server ${serverId} latest:`, latest);
|
||||
|
||||
if (metricsDiv) {
|
||||
const cpuVal = parseFloat(latest.cpu_percent).toFixed(1);
|
||||
metricsDiv.querySelector('[data-metric="cpu"]').textContent = `${cpuVal}%`;
|
||||
|
||||
const ramPercent = (latest.ram_used_mb / latest.ram_total_mb * 100).toFixed(0);
|
||||
metricsDiv.querySelector('[data-metric="ram"]').textContent = `${ramPercent}%`;
|
||||
|
||||
const diskPercent = (latest.disk_used_gb / latest.disk_total_gb * 100).toFixed(0);
|
||||
metricsDiv.querySelector('[data-metric="disk"]').textContent = `${diskPercent}%`;
|
||||
|
||||
const netRx = parseFloat(latest.network_rx_mbps).toFixed(1);
|
||||
const netTx = parseFloat(latest.network_tx_mbps).toFixed(1);
|
||||
metricsDiv.querySelector('[data-metric="network"]').textContent = `↓${netRx}↑${netTx}`;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch metrics for server ${serverId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateAllMetrics() {
|
||||
activeServers.forEach(serverId => {
|
||||
updateServerMetrics(serverId);
|
||||
});
|
||||
}
|
||||
|
||||
// Initial load
|
||||
if (activeServers.length > 0) {
|
||||
updateAllMetrics();
|
||||
// Update every 30 seconds
|
||||
setInterval(updateAllMetrics, 30000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user