Add RAM usage in GB and swap metrics to agent, server, UI and CSV export

This commit is contained in:
2026-07-17 17:10:47 +07:00
parent 513b8ede84
commit 76f74201e5
12 changed files with 272 additions and 35 deletions
+72 -7
View File
@@ -49,6 +49,45 @@
</div>
</div>
<div class="row g-4 mb-4">
<div class="col-md-6">
<div class="card text-center shadow-sm">
<div class="card-body">
<div class="text-muted small">RAM</div>
<div class="fw-bold">
{% if computer.current_ram_used_gb is not none and computer.current_ram_total_gb is not none %}
{{ computer.current_ram_used_gb | round(1) }} / {{ computer.current_ram_total_gb | round(1) }} GB
<span class="text-muted small">({{ computer.current_ram_percent | round(1) if computer.current_ram_percent is not none else '-' }}%)</span>
{% else %}
{{ computer.current_ram_percent | round(1) if computer.current_ram_percent is not none else '-' }}%
{% endif %}
</div>
{% if computer.current_ram_available_gb is not none %}
<div class="text-muted small">доступно {{ computer.current_ram_available_gb | round(1) }} GB</div>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="card text-center shadow-sm">
<div class="card-body">
<div class="text-muted small">Swap</div>
<div class="fw-bold">
{% if computer.current_swap_used_gb is not none and computer.current_swap_total_gb is not none %}
{{ computer.current_swap_used_gb | round(1) }} / {{ computer.current_swap_total_gb | round(1) }} GB
<span class="text-muted small">({{ computer.current_swap_percent | round(1) if computer.current_swap_percent is not none else '-' }}%)</span>
{% else %}
{{ computer.current_swap_percent | round(1) if computer.current_swap_percent is not none else '-' }}%
{% endif %}
</div>
{% if computer.current_swap_free_gb is not none %}
<div class="text-muted small">свободно {{ computer.current_swap_free_gb | round(1) }} GB</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title">Активные сессии</h5>
@@ -75,7 +114,7 @@
</div>
<div class="row g-4 mb-4">
<div class="col-md-6">
<div class="col-md-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">CPU, %</h5>
@@ -83,7 +122,7 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-md-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">RAM, %</h5>
@@ -91,6 +130,14 @@
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Swap, %</h5>
<canvas id="swapChart"></canvas>
</div>
</div>
</div>
</div>
<div class="card shadow-sm mb-4">
@@ -120,13 +167,21 @@
<div class="card-body">
<h5 class="card-title">История heartbeats</h5>
<table class="table table-sm">
<thead><tr><th>Время</th><th>CPU</th><th>RAM</th><th>IP</th></tr></thead>
<thead><tr><th>Время</th><th>CPU</th><th>RAM</th><th>RAM GB</th><th>Swap</th><th>IP</th></tr></thead>
<tbody>
{% for h in heartbeats[-20:] | reverse %}
<tr>
<td>{{ h.timestamp[:16] | replace('T', ' ') if h.timestamp else '-' }}</td>
<td>{{ h.cpu_percent | round(1) }}%</td>
<td>{{ h.ram_percent | round(1) }}%</td>
<td>
{% if h.ram_used_gb is not none and h.ram_total_gb is not none %}
{{ h.ram_used_gb | round(1) }} / {{ h.ram_total_gb | round(1) }}
{% else %}
-
{% endif %}
</td>
<td>{{ h.swap_percent | round(1) if h.swap_percent is not none else '-' }}%</td>
<td>{{ h.local_ip or '-' }}</td>
</tr>
{% endfor %}
@@ -135,22 +190,32 @@
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const heartbeats = {{ heartbeats | tojson }};
const labels = heartbeats.map(h => h.timestamp.replace('T', ' ').slice(0, 16));
const cpuData = heartbeats.map(h => h.cpu_percent);
const ramData = heartbeats.map(h => h.ram_percent);
const cpuData = heartbeats.map(h => h.cpu_percent ?? null);
const ramData = heartbeats.map(h => h.ram_percent ?? null);
const swapData = heartbeats.map(h => h.swap_percent ?? null);
new Chart(document.getElementById('cpuChart'), {
type: 'line',
data: { labels, datasets: [{ label: 'CPU %', data: cpuData, borderColor: 'rgb(255, 99, 132)', tension: 0.2 }] },
options: { scales: { y: { beginAtZero: true, max: 100 } } }
options: { scales: { y: { beginAtZero: true, max: 100 } }, spanGaps: true }
});
new Chart(document.getElementById('ramChart'), {
type: 'line',
data: { labels, datasets: [{ label: 'RAM %', data: ramData, borderColor: 'rgb(54, 162, 235)', tension: 0.2 }] },
options: { scales: { y: { beginAtZero: true, max: 100 } } }
options: { scales: { y: { beginAtZero: true, max: 100 } }, spanGaps: true }
});
new Chart(document.getElementById('swapChart'), {
type: 'line',
data: { labels, datasets: [{ label: 'Swap %', data: swapData, borderColor: 'rgb(255, 159, 64)', tension: 0.2 }] },
options: { scales: { y: { beginAtZero: true, max: 100 } }, spanGaps: true }
});
</script>
{% endblock %}