notificationData = $this->createNotificationData(); $this->problemData = $this->createProblemData(); } /** * Create full report */ public function indexAction() { $this->getTabs()->add( 'alertsummary', array( 'title' => $this->translate( 'Show recent alerts and visualize notifications and problems' . ' based on their amount and chronological distribution' ), 'label' => $this->translate('Alert Summary'), 'url' => Url::fromRequest() ) )->extend(new DashboardAction())->extend(new MenuAction())->activate('alertsummary'); $this->view->title = $this->translate('Alert Summary'); $this->view->intervalBox = $this->createIntervalBox(); list($recentAlerts, $recentAlertsUrl) = $this->createRecentAlerts(); $this->view->recentAlerts = $recentAlerts; $this->view->recentAlertsUrl = $recentAlertsUrl; $this->view->interval = $this->getInterval(); $this->view->defectChart = $this->createDefectImage(); $this->view->healingChart = $this->createHealingChart(); $this->view->perf = $this->createNotificationPerfdata(); $this->view->trend = $this->createTrendInformation(); $this->setAutorefreshInterval(15); $query = $this->backend->select()->from( 'notification', array( 'host_name', 'host_display_name', 'service_description', 'service_display_name', 'notification_output', 'notification_contact_name', 'notification_start_time', 'notification_state' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $this->view->notifications = $query; $this->view->notificationsUrl = 'monitoring/list/notifications'; $this->setupLimitControl(); if (($limit = $this->params->get('limit'))) { $query->limit($limit); } else { $query->limit(25); } } /** * Create data for charts * * @return array */ private function createNotificationData() { $interval = $this->getInterval(); $query = $this->backend->select()->from( 'notification', array( 'notification_start_time' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->addFilter( new FilterExpression( 'notification_start_time', '>=', $this->getBeginDate($interval)->format('Y-m-d H:i:s') ) ); $query->order('notification_start_time', 'asc'); $records = $query->getQuery()->fetchAll(); $data = array(); $period = $this->createPeriod($interval); foreach ($period as $entry) { $id = $this->getPeriodFormat($interval, $entry->getTimestamp()); $data[$id] = array($id, 0); } foreach ($records as $item) { $id = $this->getPeriodFormat($interval, $item->notification_start_time); if (empty($data[$id])) { $data[$id] = array($id, 0); } $data[$id][1]++; } return $data; } /** * Trend information for notifications * * @return stdClass */ private function createTrendInformation() { $date = new DateTime(); $beginDate = $date->sub(new DateInterval('P3D')); $query = $this->backend->select()->from( 'notification', array( 'notification_start_time' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->addFilter( new FilterExpression( 'notification_start_time', '>=', $beginDate->format('Y-m-d H:i:s') ) ); $query->order('notification_start_time', 'asc'); $records = $query->getQuery()->fetchAll(); $slots = array(); $period = new DatePeriod($beginDate, new DateInterval('P1D'), 2, DatePeriod::EXCLUDE_START_DATE); foreach ($period as $entry) { $slots[$entry->format('Y-m-d')] = 0; } foreach ($records as $item) { $id = strftime('%Y-%m-%d', $item->notification_start_time); if (isset($slots[$id])) { $slots[$id]++; } } $yesterday = array_shift($slots); $today = array_shift($slots); $out = new stdClass(); if ($yesterday === $today) { $out->trend = $this->translate('unchanged'); } elseif ($yesterday > $today) { $out->trend = $this->translate('down'); } else { $out->trend = $this->translate('up'); } if ($yesterday <= 0) { $out->percent = 100; } elseif ($yesterday === $today) { $out->percent = 0; } else { $out->percent = sprintf( '%.2f', 100 - ((100/($yesterday > $today ? $yesterday : $today)) * ($yesterday > $today ? $today : $yesterday)) ); } return $out; } /** * Perfdata for notifications * * @return stdClass */ private function createNotificationPerfdata() { $interval = $this->getInterval(); $query = $this->backend->select()->from( 'notification', array( 'notification_start_time' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->addFilter( new FilterExpression( 'notification_start_time', '>=', $this->getBeginDate($interval)->format('Y-m-d H:i:s') ) ); $query->order('notification_start_time', 'desc'); $records = $query->getQuery()->fetchAll(); $slots = array(); foreach ($records as $item) { $id = strftime('%Y-%m-%d %H:%I:00', $item->notification_start_time); if (empty($slots[$id])) { $slots[$id] = 0; } $slots[$id]++; } $out = new stdClass(); if (! empty($slots)) { $out->avg = sprintf('%.2f', array_sum($slots) / count($slots)); } else { $out->avg = '0.0'; } $out->last = array_shift($slots); return $out; } /** * Problems for notifications * * @return array */ private function createProblemData() { $interval = $this->getInterval(); $query = $this->backend->select()->from( 'eventhistory', array( 'timestamp' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->addFilter( new FilterExpression( 'timestamp', '>=', $this->getBeginDate($interval)->getTimestamp() ) ); $query->addFilter( new FilterExpression( 'state', '>', 0 ) ); $defects = array(); $records = $query->getQuery()->fetchAll(); $period = $this->createPeriod($interval); foreach ($period as $entry) { $id = $this->getPeriodFormat($interval, $entry->getTimestamp()); $defects[$id] = array($id, 0); } foreach ($records as $item) { $id = $this->getPeriodFormat($interval, $item->timestamp); if (empty($defects[$id])) { $defects[$id] = array($id, 0); } $defects[$id][1]++; } return $defects; } /** * Healing svg image * * @return GridChart */ public function createHealingChart() { $gridChart = new GridChart(); $gridChart->title = $this->translate('Healing Chart'); $gridChart->description = $this->translate('Notifications and average reaction time per hour.'); $gridChart->alignTopLeft(); $gridChart->setAxisLabel($this->createPeriodDescription(), $this->translate('Notifications')) ->setXAxis(new StaticAxis()) ->setYAxis(new LinearUnit(10)) ->setAxisMin(null, 0); $interval = $this->getInterval(); $query = $this->backend->select()->from( 'notification', array( 'notification_object_id', 'notification_start_time', 'notification_state', 'acknowledgement_entry_time' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->addFilter( new FilterExpression( 'notification_start_time', '>=', $this->getBeginDate($interval)->format('Y-m-d H:i:s') ) ); $query->order('notification_start_time', 'asc'); $records = $query->getQuery()->fetchAll(); $interval = $this->getInterval(); $period = $this->createPeriod($interval); $dAvg = array(); $dMax = array(); $notifications = array(); $rData = array(); foreach ($period as $entry) { $id = $this->getPeriodFormat($interval, $entry->getTimestamp()); $dMax[$id] = array($id, 0); $dAvg[$id] = array($id, 0, 0); $notifications[$id] = array($id, 0); } foreach ($records as $item) { $id = $this->getPeriodFormat($interval, $item->notification_start_time); if ($item->notification_state == '0' && isset($rData[$item->notification_object_id])) { $rData[$item->notification_object_id]['recover'] = $item->notification_start_time - $rData[$item->notification_object_id]['entry']; } elseif ($item->notification_state !== '0') { $recover = 0; if ($item->acknowledgement_entry_time) { $recover = $item->acknowledgement_entry_time - $item->notification_start_time; /* * Acknowledgements may happen before the actual notification starts, since notifications * can be configured to start a certain time after the problem. In that case we assume * a reaction time of 0s. */ if ($recover < 0) { $recover = 0; } } $rData[$item->notification_object_id] = array( 'id' => $id, 'entry' => $item->notification_start_time, 'recover' => $recover ); } } foreach ($rData as $item) { $notifications[$item['id']][1]++; if ($item['recover'] > $dMax[$item['id']][1]) { $dMax[$item['id']][1] = (int) $item['recover']; } $dAvg[$item['id']][1] += (int) $item['recover']; $dAvg[$item['id']][2]++; } foreach ($dAvg as &$item) { if ($item[2] > 0) { $item[1] = ($item[1]/$item[2])/60/60; } } foreach ($dMax as &$item) { $item[1] = $item[1]/60/60; } $gridChart->drawBars( array( 'label' => $this->translate('Notifications'), 'color' => '#07C0D9', 'data' => $notifications, 'showPoints' => true, 'tooltip' => '{title}: {value} {label}' ) ); $gridChart->drawLines( array( 'label' => $this->translate('Avg (min)'), 'color' => '#ffaa44', 'data' => $dAvg, 'showPoints' => true, 'tooltip' => $this->translate('{title}: {value}m min. reaction time') ) ); $gridChart->drawLines( array( 'label' => $this->translate('Max (min)'), 'color' => '#ff5566', 'data' => $dMax, 'showPoints' => true, 'tooltip' => $this->translate('{title}: {value}m max. reaction time') ) ); return $gridChart; } /** * Notifications and defects * * @return GridChart */ public function createDefectImage() { $gridChart = new GridChart(); $gridChart->title = $this->translate('Defect Chart'); $gridChart->description = $this->translate('Notifications and defects per hour'); $gridChart->alignTopLeft(); $gridChart->setAxisLabel($this->createPeriodDescription(), $this->translate('Notifications')) ->setXAxis(new StaticAxis()) ->setYAxis(new LinearUnit(10)) ->setAxisMin(null, 0); $gridChart->drawBars( array( 'label' => $this->translate('Notifications'), 'color' => '#07C0D9', 'data' => $this->notificationData, 'showPoints' => true, 'tooltip' => '{title}: {value} {label}' ) ); $gridChart->drawLines( array( 'label' => $this->translate('Defects'), 'color' => '#ff5566', 'data' => $this->problemData, 'showPoints' => true, 'tooltip' => '{title}: {value} {label}' ) ); return $gridChart; } /** * Top recent alerts * * @return array */ private function createRecentAlerts() { $query = $this->backend->select()->from( 'notification', array( 'host_name', 'host_display_name', 'service_description', 'service_display_name', 'notification_output', 'notification_contact_name', 'notification_start_time', 'notification_state' ) ); $this->applyRestriction('monitoring/filter/objects', $query); $query->order('notification_start_time', 'desc'); return array( $query->limit(5), 'monitoring/list/notifications?sort=notification_start_time&dir=desc' ); } /** * Interval selector box * * @return SelectBox */ private function createIntervalBox() { $box = new SelectBox( 'intervalBox', array( '1d' => $this->translate('One day'), '1w' => $this->translate('One week'), '1m' => $this->translate('One month'), '1y' => $this->translate('One year') ), $this->translate('Report interval'), 'interval' ); $box->applyRequest($this->getRequest()); return $box; } /** * Return reasonable date time format for an interval * * @param string $interval * @param string $timestamp * * @return string */ private function getPeriodFormat($interval, $timestamp) { $format = ''; if ($interval === '1d') { $format = '%H:00'; } elseif ($interval === '1w') { $format = '%Y-%m-%d'; } elseif ($interval === '1m') { $format = '%Y-%m-%d'; } elseif ($interval === '1y') { $format = '%Y-%m'; } return strftime($format, $timestamp); } /** * Create a reasonable period based in interval strings * * @param $interval * @return DatePeriod */ private function createPeriod($interval) { if ($interval === '1d') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('PT1H'), 24); } elseif ($interval === '1w') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1D'), 7); } elseif ($interval === '1m') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1D'), 31); } elseif ($interval === '1y') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1M'), 12); } } /** * Return start timestamps based on interval strings * * @param $interval * @return DateTime|null */ private function getBeginDate($interval) { $new = new DateTime(); if ($interval === '1d') { return $new->sub(new DateInterval('P1D')); } elseif ($interval === '1w') { return $new->sub(new DateInterval('P1W')); } elseif ($interval === '1m') { return $new->sub(new DateInterval('P1M')); } elseif ($interval === '1y') { return $new->sub(new DateInterval('P1Y')); } return null; } /** * Getter for interval * * @return string * * @throws Zend_Controller_Action_Exception */ private function getInterval() { $interval = $this->getParam('interval', '1d'); if (false === in_array($interval, array('1d', '1w', '1m', '1y'))) { throw new Zend_Controller_Action_Exception($this->translate('Value for interval not valid')); } return $interval; } /** * Create a human-readable description of the current interval size * * @return string The description of the current interval size */ private function createPeriodDescription() { $int = $this->getInterval(); switch ($int) { case '1d': return $this->translate('Hour'); break; case '1w'; return $this->translate('Day'); break; case '1m': return $this->translate('Day'); break; case '1y': return $this->translate('Month'); break; } } }