diff --git a/src/Controllers/Api/MetricsController.php b/src/Controllers/Api/MetricsController.php index 27395d7..c74d2e5 100755 --- a/src/Controllers/Api/MetricsController.php +++ b/src/Controllers/Api/MetricsController.php @@ -100,6 +100,12 @@ class MetricsController extends Model 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) $stmt = $this->pdo->prepare(" 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 ]); - // Если сервис остановлен - создаем алерт - if ($serviceStatus === 'stopped') { - $this->createServiceAlert($serverId, $serviceName, $serviceStatus, $serverName); + // Если статус изменился И сервис в мониторинге - шлем алерт + if ($oldStatus !== null && $oldStatus !== $serviceStatus) { + $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 ]); - $this->notificationService->sendAlertNotification( + $this->notificationService->sendThresholdNotification( $serverName, $metricName, $value, @@ -270,12 +286,10 @@ class MetricsController extends Model "); $stmt->execute([':id' => $existingAlert['id']]); - $this->notificationService->sendAlertNotification( + $this->notificationService->sendRecoveryNotification( $serverName, $metricName, - $value, - 'resolved', - 'Порог более не превышен' + $value ); } } diff --git a/src/Controllers/ServerDetailController.php b/src/Controllers/ServerDetailController.php index 075d739..41f287a 100755 --- a/src/Controllers/ServerDetailController.php +++ b/src/Controllers/ServerDetailController.php @@ -300,14 +300,14 @@ class ServerDetailController extends Model foreach ($metricTypes as $metricType) { $warning = $params[$metricType['name'] . '_warning'] ?? ''; $critical = $params[$metricType['name'] . '_critical'] ?? ''; - $duration = $params[$metricType['name'] . '_duration'] ?? 0; + $duration = (int)($params[$metricType['name'] . '_duration'] ?? 0); if ($warning !== '' && $critical !== '') { $insertStmt->execute([ ':server_id' => $id, ':metric_name_id' => $metricType['id'], - ':warning_threshold' => $warning, - ':critical_threshold' => $critical, + ':warning_threshold' => (float)$warning, + ':critical_threshold' => (float)$critical, ':duration' => $duration ]); } diff --git a/src/Services/NotificationService.php b/src/Services/NotificationService.php index 682b368..f8a7a3e 100755 --- a/src/Services/NotificationService.php +++ b/src/Services/NotificationService.php @@ -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') { - $severityText = 'ВОССТАНОВЛЕНИЕ'; - $emoji = '✅'; - $subject = "{$emoji} {$severityText}: {$metricName} в норме"; - $message = "Сервер: {$serverName}\n"; - $message .= "Метрика: {$metricName}\n"; - $message .= "Текущее значение: {$value}\n"; - $message .= "Статус: Порог более не превышен\n"; - $message .= "Время: " . date('d.m.Y H:i:s'); + if ($severity === 'warning') { + $severityText = 'ПРЕДУПРЕЖДЕНИЕ'; + $emoji = '⚠️'; } else { - $severityText = $severity === 'critical' ? 'КРИТИЧЕСКИЙ' : 'ПРЕДУПРЕЖДЕНИЕ'; + $severityText = 'КРИТИЧЕСКИЙ'; $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 if (!empty($this->settings['email_enabled']) && !empty($this->settings['smtp_host'])) { $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); + } + } + /** * Отправить тестовое уведомление */