feat: добавлен мониторинг температур (CPU, GPU, HDD/SSD)

- Обновлен скрипт установки агента (добавлены lm-sensors, smartmontools)
- Агент теперь собирает температуры: CPU (через psutil), Диски (smartctl), GPU (nvidia-smi)
- Бэкенд автоматически определяет единицу измерения °C для метрик temp_*
- Добавлен общий график Температуры на страницу сервера
This commit is contained in:
mirivlad 2026-04-14 01:21:59 +08:00
parent 91cfbca893
commit de34962360
2 changed files with 71 additions and 2 deletions

View File

@ -50,7 +50,7 @@ echo 'Установка агента мониторинга...'
if ! command -v python3 &> /dev/null; then if ! command -v python3 &> /dev/null; then
echo 'Установка Python3...' echo 'Установка Python3...'
apt-get update apt-get update
apt-get install -y python3 python3-pip apt-get install -y python3 python3-pip lm-sensors smartmontools
fi fi
# Устанавливаем psutil # Устанавливаем psutil

View File

@ -188,7 +188,26 @@
<!-- Диски: Doughnut графики -->
<!-- Температуры -->
{% set has_temps = false %}
{% for m in metrics %}{% if m starts with 'temp_' %}{% set has_temps = true %}{% endif %}{% endfor %}
{% if has_temps %}
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h6 class="mb-0"><i class="fas fa-thermometer-half"></i> Температуры</h6>
</div>
<div class="card-body">
<canvas id="chart-temperatures" width="100%" height="200"></canvas>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Диски: Doughnut графики -->
<div class="row mb-3"> <div class="row mb-3">
{% for metricName, metricData in metrics %} {% for metricName, metricData in metrics %}
{% if metricName starts with 'disk_used_' and metricName != 'disk_used' %} {% if metricName starts with 'disk_used_' and metricName != 'disk_used' %}
@ -834,6 +853,56 @@ document.addEventListener('mousemove', function(e) {
{% endif %} {% endif %}
{% endfor %} {% endfor %}
// График температур
{% set temp_metrics = [] %}
{% for m in metrics %}{% if m starts with 'temp_' %}{% set temp_metrics = temp_metrics|merge([m]) %}{% endif %}{% endfor %}
{% if temp_metrics %}
(function() {
var ctx = document.getElementById('chart-temperatures');
if (!ctx) return;
var labels = [];
{% if metrics[temp_metrics[0]] is defined %}
{% for p in metrics[temp_metrics[0]]|slice(-100) %}
labels.push('{{ p.time_bucket|default(p.created_at)|date("d.m H:i") }}');
{% endfor %}
{% endif %}
var datasets = [];
{% for m in temp_metrics %}
var data_{{ m }} = {
label: '{{ m|replace({'temp_': '', '_': ' '})|title }}',
data: [],
fill: false,
tension: 0.1,
pointRadius: 1,
borderWidth: 1
};
{% for p in metrics[m]|slice(-100) %}
data_{{ m }}.data.push({{ p.value }});
{% endfor %}
datasets.push(data_{{ m }});
{% endfor %}
new Chart(ctx.getContext('2d'), {
type: 'line',
data: { labels: labels, datasets: datasets },
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { display: true, position: 'top' },
tooltip: { enabled: true, mode: 'index', intersect: false },
zoom: { zoom: { wheel: { enabled: true }, pinch: { enabled: true }, mode: 'x' }, pan: { enabled: true, mode: 'x' } }
},
scales: { y: { beginAtZero: false, ticks: { callback: v => v + '°C' } } }
}
});
})();
{% endif %}
// Doughnut графики для разделов дисков // Doughnut графики для разделов дисков
{% for metricName, metricData in metrics %} {% for metricName, metricData in metrics %}
{% if metricName starts with 'disk_used_' and metricName != 'disk_used' %} {% if metricName starts with 'disk_used_' and metricName != 'disk_used' %}