Add display_metrics setting per server

- Add display_metrics JSON field to servers table
- Update server edit form with metric checkboxes
- ServerDetailController now uses server's display_metrics setting
- If no metrics selected - show all (backward compatibility)
- Removed hardcoded metric names from queries
This commit is contained in:
mirivlad 2026-04-25 19:54:00 +08:00
parent a11cfb5165
commit e20354e89d
3 changed files with 73 additions and 13 deletions

View File

@ -141,6 +141,17 @@ class ServerController extends Model
$tokenRow = $stmt->fetch();
$decryptedToken = $tokenRow ? \App\Utils\EncryptionHelper::decrypt($tokenRow['encrypted_token']) : null;
// Получаем все метрики которые есть у серве<D0B2><D0B5>а
$stmt = $this->pdo->prepare("
SELECT DISTINCT mn.id, mn.name, mn.unit
FROM metric_names mn
JOIN server_metrics sm ON sm.metric_name_id = mn.id
WHERE sm.server_id = :server_id
ORDER BY mn.name
");
$stmt->execute([':server_id' => $id]);
$allMetrics = $stmt->fetchAll();
if (!$server) {
return $response->withHeader('Location', '/servers')->withStatus(302);
}
@ -149,7 +160,8 @@ class ServerController extends Model
'title' => 'Редактировать сервер',
'server' => $server,
'groups' => $groups,
'agent_token' => $decryptedToken
'agent_token' => $decryptedToken,
'allMetrics' => $allMetrics
];
return $this->twig->render($response, 'servers/edit.twig', $templateData);
@ -160,6 +172,10 @@ class ServerController extends Model
$id = $args['id'];
$params = $request->getParsedBody();
// Собираем выбранные метрики
$displayMetrics = $params['display_metrics'] ?? [];
$displayMetricsJson = json_encode(array_values($displayMetrics));
$stmt = $this->pdo->prepare("
UPDATE servers
SET name = :name,
@ -167,7 +183,8 @@ class ServerController extends Model
group_id = :group_id,
description = :description,
offline_timeout = :offline_timeout,
notify_on_offline = :notify_on_offline
notify_on_offline = :notify_on_offline,
display_metrics = :display_metrics
WHERE id = :id
");
@ -178,7 +195,8 @@ class ServerController extends Model
':group_id' => $params['group_id'] ?? null,
':description' => $params['description'] ?? '',
':offline_timeout' => (int)($params['offline_timeout'] ?? 300),
':notify_on_offline' => isset($params['notify_on_offline']) ? 1 : 0
':notify_on_offline' => isset($params['notify_on_offline']) ? 1 : 0,
':display_metrics' => $displayMetricsJson
]);
if ($result) {

View File

@ -38,6 +38,16 @@ class ServerDetailController extends Model
return $response->withHeader('Location', '/servers')->withStatus(302);
}
// Получаем настройки отображаемых метрик
$displayMetricsSetting = $server['display_metrics'] ?? null;
$displayMetrics = null;
if ($displayMetricsSetting) {
$decoded = json_decode($displayMetricsSetting, true);
if (is_array($decoded) && count($decoded) > 0) {
$displayMetrics = $decoded;
}
}
// Получаем параметры
$queryParams = $request->getQueryParams();
$startDate = $queryParams['start'] ?? null;
@ -121,6 +131,19 @@ class ServerDetailController extends Model
$startStr = $startDate->format('Y-m-d H:i:s');
$endStr = $endDate->format('Y-m-d H:i:s');
// Формируем фильтр метрик из настроек сервера
$metricsFilter = '';
$metricParams = [];
if ($displayMetrics) {
$placeholders = [];
foreach ($displayMetrics as $i => $m) {
$key = ':metric_' . $i;
$placeholders[] = $key;
$metricParams[$key] = $m;
}
$metricsFilter = 'AND mn.name IN (' . implode(', ', $placeholders) . ')';
}
// Запрос с агрегацией если нужно
if ($groupBy) {
// Оптимизированный запрос с подзапросом и LIMIT для больших периодов
@ -140,15 +163,13 @@ class ServerDetailController extends Model
LIMIT 200000
) sm
INNER JOIN metric_names mn ON mn.id = sm.metric_name_id
WHERE mn.name IN ('cpu_load', 'ram_used', 'ram_total_gb', 'disk_used', 'disk_used_root',
'disk_used_home', 'disk_used_boot', 'disk_total_gb_root', 'disk_total_gb_home',
'temp_cpu', 'temp_disk_sda', 'temp_disk_sdb', 'temp_disk_sdc',
'net_in_enp4s0', 'net_out_enp4s0', 'disk_used_mnt_data')
WHERE 1=1 {$metricsFilter}
{$groupBy}
ORDER BY time_bucket ASC
";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr]);
$executeParams = array_merge([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr], $metricParams);
$stmt->execute($executeParams);
} else {
$sql = "
SELECT sm.value, mn.name, mn.unit, sm.created_at
@ -158,15 +179,13 @@ class ServerDetailController extends Model
WHERE sm.server_id = :id
AND sm.created_at >= :start_date
AND sm.created_at <= :end_date
AND mn.name IN ('cpu_load', 'ram_used', 'ram_total_gb', 'disk_used', 'disk_used_root',
'disk_used_home', 'disk_used_boot', 'disk_total_gb_root', 'disk_total_gb_home',
'temp_cpu', 'temp_disk_sda', 'temp_disk_sdb', 'temp_disk_sdc',
'net_in_enp4s0', 'net_out_enp4s0', 'disk_used_mnt_data')
{$metricsFilter}
ORDER BY sm.created_at ASC
LIMIT 5000
";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr]);
$executeParams = array_merge([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr], $metricParams);
$stmt->execute($executeParams);
}
$metrics = $stmt->fetchAll();

View File

@ -39,6 +39,29 @@
<small class="form-text text-muted">Дополнительная информация о сервере</small>
</div>
{% if allMetrics|length > 0 %}
<hr>
<h5 class="mb-3"><i class="fas fa-chart-line"></i> Отображаемые метрики</h5>
<p class="text-muted small">Выберите метрики, которые будут показываться на графиках. Пустой выбор = все метрики.</p>
<div class="row mb-3">
{% set savedMetrics = server.display_metrics|json_decode ?: [] %}
{% for metric in allMetrics %}
<div class="col-md-4 col-lg-3 mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="display_metrics[]"
id="metric_{{ metric.name }}" value="{{ metric.name }}"
{% if metric.name in savedMetrics %}checked{% endif %}>
<label class="form-check-label" for="metric_{{ metric.name }}">
{{ metric.name }}
{% if metric.unit %}({{ metric.unit }}){% endif %}
</label>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<hr>
<h5 class="mb-3"><i class="fas fa-wifi"></i> Настройки мониторинга недоступности</h5>