fix: уведомления сервисов и исправление порогов
- Уведомления сервисов: разные цвета и тексты для остановки (🛑) и запуска (✅) - Фикс порядка действий: SELECT статуса ДО UPDATE для корректного отслеживания изменений - Фильтр алертов: только для сервисов в списке мониторинга - NotificationService: разделение на sendThresholdNotification/sendRecoveryNotification/sendServiceNotification - Исправление сохранения порогов (приведение типов для duration/warning/critical) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
c6e400ad32
commit
d35ce3a022
|
|
@ -100,6 +100,12 @@ class MetricsController extends Model
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Сначала читаем старый статус (ДО обновления)
|
||||||
|
$stmtOld = $this->pdo->prepare("SELECT status FROM service_status WHERE server_id = :server_id AND service_name = :service_name");
|
||||||
|
$stmtOld->execute([':server_id' => $serverId, ':service_name' => $serviceName]);
|
||||||
|
$oldStatusRow = $stmtOld->fetch();
|
||||||
|
$oldStatus = $oldStatusRow ? $oldStatusRow['status'] : null;
|
||||||
|
|
||||||
// Обновляем статус сервиса (INSERT OR UPDATE)
|
// Обновляем статус сервиса (INSERT OR UPDATE)
|
||||||
$stmt = $this->pdo->prepare("
|
$stmt = $this->pdo->prepare("
|
||||||
INSERT INTO service_status (server_id, service_name, status, load_state, active_state, sub_state, updated_at)
|
INSERT INTO service_status (server_id, service_name, status, load_state, active_state, sub_state, updated_at)
|
||||||
|
|
@ -121,9 +127,19 @@ class MetricsController extends Model
|
||||||
':sub_state' => $subState
|
':sub_state' => $subState
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Если сервис остановлен - создаем алерт
|
// Если статус изменился И сервис в мониторинге - шлем алерт
|
||||||
if ($serviceStatus === 'stopped') {
|
if ($oldStatus !== null && $oldStatus !== $serviceStatus) {
|
||||||
$this->createServiceAlert($serverId, $serviceName, $serviceStatus, $serverName);
|
$stmtMon = $this->pdo->prepare("SELECT monitor_services FROM agent_configs WHERE server_id = :server_id");
|
||||||
|
$stmtMon->execute([':server_id' => $serverId]);
|
||||||
|
$monConfig = $stmtMon->fetch();
|
||||||
|
$monitoredServices = [];
|
||||||
|
if ($monConfig && !empty($monConfig['monitor_services'])) {
|
||||||
|
$monitoredServices = json_decode($monConfig['monitor_services'], true) ?? [];
|
||||||
|
}
|
||||||
|
if (in_array($serviceName, $monitoredServices)) {
|
||||||
|
$this->notificationService->sendServiceNotification($serverName, $serviceName, $serviceStatus);
|
||||||
|
$this->createServiceAlert($serverId, $serviceName, $serviceStatus, $serverName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +244,7 @@ class MetricsController extends Model
|
||||||
':severity' => $severity
|
':severity' => $severity
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->notificationService->sendAlertNotification(
|
$this->notificationService->sendThresholdNotification(
|
||||||
$serverName,
|
$serverName,
|
||||||
$metricName,
|
$metricName,
|
||||||
$value,
|
$value,
|
||||||
|
|
@ -270,12 +286,10 @@ class MetricsController extends Model
|
||||||
");
|
");
|
||||||
$stmt->execute([':id' => $existingAlert['id']]);
|
$stmt->execute([':id' => $existingAlert['id']]);
|
||||||
|
|
||||||
$this->notificationService->sendAlertNotification(
|
$this->notificationService->sendRecoveryNotification(
|
||||||
$serverName,
|
$serverName,
|
||||||
$metricName,
|
$metricName,
|
||||||
$value,
|
$value
|
||||||
'resolved',
|
|
||||||
'Порог более не превышен'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -300,14 +300,14 @@ class ServerDetailController extends Model
|
||||||
foreach ($metricTypes as $metricType) {
|
foreach ($metricTypes as $metricType) {
|
||||||
$warning = $params[$metricType['name'] . '_warning'] ?? '';
|
$warning = $params[$metricType['name'] . '_warning'] ?? '';
|
||||||
$critical = $params[$metricType['name'] . '_critical'] ?? '';
|
$critical = $params[$metricType['name'] . '_critical'] ?? '';
|
||||||
$duration = $params[$metricType['name'] . '_duration'] ?? 0;
|
$duration = (int)($params[$metricType['name'] . '_duration'] ?? 0);
|
||||||
|
|
||||||
if ($warning !== '' && $critical !== '') {
|
if ($warning !== '' && $critical !== '') {
|
||||||
$insertStmt->execute([
|
$insertStmt->execute([
|
||||||
':server_id' => $id,
|
':server_id' => $id,
|
||||||
':metric_name_id' => $metricType['id'],
|
':metric_name_id' => $metricType['id'],
|
||||||
':warning_threshold' => $warning,
|
':warning_threshold' => (float)$warning,
|
||||||
':critical_threshold' => $critical,
|
':critical_threshold' => (float)$critical,
|
||||||
':duration' => $duration
|
':duration' => $duration
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,31 +24,77 @@ class NotificationService
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Отправить уведомление о алерте
|
* Отправить уведомление о превышении порога
|
||||||
*/
|
*/
|
||||||
public function sendAlertNotification($serverName, $metricName, $value, $severity, $threshold)
|
public function sendThresholdNotification($serverName, $metricName, $value, $severity, $threshold)
|
||||||
{
|
{
|
||||||
if ($severity === 'resolved') {
|
if ($severity === 'warning') {
|
||||||
$severityText = 'ВОССТАНОВЛЕНИЕ';
|
$severityText = 'ПРЕДУПРЕЖДЕНИЕ';
|
||||||
$emoji = '✅';
|
$emoji = '⚠️';
|
||||||
$subject = "{$emoji} {$severityText}: {$metricName} в норме";
|
|
||||||
$message = "Сервер: {$serverName}\n";
|
|
||||||
$message .= "Метрика: {$metricName}\n";
|
|
||||||
$message .= "Текущее значение: {$value}\n";
|
|
||||||
$message .= "Статус: Порог более не превышен\n";
|
|
||||||
$message .= "Время: " . date('d.m.Y H:i:s');
|
|
||||||
} else {
|
} else {
|
||||||
$severityText = $severity === 'critical' ? 'КРИТИЧЕСКИЙ' : 'ПРЕДУПРЕЖДЕНИЕ';
|
$severityText = 'КРИТИЧЕСКИЙ';
|
||||||
$emoji = '🚨';
|
$emoji = '🚨';
|
||||||
$subject = "{$emoji} {$severityText}: Превышение порога {$metricName}";
|
|
||||||
$message = "Сервер: {$serverName}\n";
|
|
||||||
$message .= "Метрика: {$metricName}\n";
|
|
||||||
$message .= "Значение: {$value}\n";
|
|
||||||
$message .= "Порог: {$threshold}\n";
|
|
||||||
$message .= "Время: " . date('d.m.Y H:i:s') . "\n";
|
|
||||||
$message .= "Серьёзность: {$severityText}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subject = "{$emoji} {$severityText}: {$metricName}";
|
||||||
|
$message = "🖥 Сервер: {$serverName}\n";
|
||||||
|
$message .= "📊 Метрика: {$metricName}\n";
|
||||||
|
$message .= "📈 Значение: {$value}\n";
|
||||||
|
$message .= "📏 Порог: {$threshold}\n";
|
||||||
|
$message .= "🕒 Время: " . date('d.m.Y H:i:s') . "\n";
|
||||||
|
$message .= "🏷 Серьёзность: {$severityText}";
|
||||||
|
|
||||||
|
$this->sendNotification($subject, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправить уведомление о восстановлении (порог в норме)
|
||||||
|
*/
|
||||||
|
public function sendRecoveryNotification($serverName, $metricName, $value)
|
||||||
|
{
|
||||||
|
$subject = "✅ Восстановление: {$metricName} в норме";
|
||||||
|
$message = "🖥 Сервер: {$serverName}\n";
|
||||||
|
$message .= "📊 Метрика: {$metricName}\n";
|
||||||
|
$message .= "📈 Текущее значение: {$value}\n";
|
||||||
|
$message .= "🟢 Статус: Порог более не превышен\n";
|
||||||
|
$message .= "🕒 Время: " . date('d.m.Y H:i:s');
|
||||||
|
|
||||||
|
$this->sendNotification($subject, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправить уведомление о сервисе (остановка/запуск)
|
||||||
|
*/
|
||||||
|
public function sendServiceNotification($serverName, $serviceName, $action)
|
||||||
|
{
|
||||||
|
// $action: 'stopped' или 'running'
|
||||||
|
if ($action === 'running') {
|
||||||
|
$emoji = '✅';
|
||||||
|
$actionText = 'Запуск сервиса';
|
||||||
|
$descText = "Сервис {$serviceName} запущен";
|
||||||
|
$severityText = 'ВОССТАНОВЛЕНИЕ';
|
||||||
|
} else {
|
||||||
|
$emoji = '🛑';
|
||||||
|
$actionText = 'Остановка сервиса';
|
||||||
|
$descText = "Сервис {$serviceName} остановлен";
|
||||||
|
$severityText = 'ОСТАНОВЛЕН';
|
||||||
|
}
|
||||||
|
|
||||||
|
$subject = "{$emoji} {$actionText}: {$serviceName}";
|
||||||
|
$message = "🖥 Сервер: {$serverName}\n";
|
||||||
|
$message .= "⚙️ Сервис: {$serviceName}\n";
|
||||||
|
$message .= "📝 Действие: {$descText}\n";
|
||||||
|
$message .= "🏷 Статус: {$severityText}\n";
|
||||||
|
$message .= "🕒 Время: " . date('d.m.Y H:i:s');
|
||||||
|
|
||||||
|
$this->sendNotification($subject, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Внутренний метод отправки (Email + Telegram)
|
||||||
|
*/
|
||||||
|
private function sendNotification($subject, $message)
|
||||||
|
{
|
||||||
// Отправка Email
|
// Отправка Email
|
||||||
if (!empty($this->settings['email_enabled']) && !empty($this->settings['smtp_host'])) {
|
if (!empty($this->settings['email_enabled']) && !empty($this->settings['smtp_host'])) {
|
||||||
$this->sendEmail($subject, $message);
|
$this->sendEmail($subject, $message);
|
||||||
|
|
@ -60,6 +106,19 @@ class NotificationService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправить уведомление о алерте (для обратной совместимости)
|
||||||
|
* @deprecated Используйте sendThresholdNotification или sendServiceNotification
|
||||||
|
*/
|
||||||
|
public function sendAlertNotification($serverName, $metricName, $value, $severity, $threshold)
|
||||||
|
{
|
||||||
|
if ($severity === 'resolved') {
|
||||||
|
$this->sendRecoveryNotification($serverName, $metricName, $value);
|
||||||
|
} else {
|
||||||
|
$this->sendThresholdNotification($serverName, $metricName, $value, $severity, $threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Отправить тестовое уведомление
|
* Отправить тестовое уведомление
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue