From 5619ac960c47611c34075ee03b5506ebd00a016d Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Thu, 2 Apr 2015 16:25:20 +0200 Subject: [PATCH] Add inline pies to host and service back to multi-select views Add old inline pie code and visualize handled/unhandled state. refs #8565 --- library/Icinga/Util/String.php | 14 +++++ library/Icinga/Web/Widget/Chart/InlinePie.php | 56 +++++++++++++++++++ .../controllers/HostsController.php | 10 +++- .../controllers/ServicesController.php | 21 ++++++- .../views/scripts/hosts/show.phtml | 7 +++ .../partials/host/objects-header.phtml | 8 --- .../partials/service/objects-header.phtml | 9 --- .../views/scripts/services/show.phtml | 10 ++++ .../library/Monitoring/Object/ServiceList.php | 41 ++++++++++++-- 9 files changed, 153 insertions(+), 23 deletions(-) diff --git a/library/Icinga/Util/String.php b/library/Icinga/Util/String.php index d9bd5a6d3..0d42d0e76 100644 --- a/library/Icinga/Util/String.php +++ b/library/Icinga/Util/String.php @@ -80,6 +80,20 @@ class String return $matches; } + /** + * Check if a string ends with a different string + * + * @param $haystack The string to search for matches + * @param $needle The string to match at the start of the haystack + * + * @return bool Whether or not needle is at the beginning of haystack + */ + public static function endsWith($haystack, $needle) + { + return $needle === '' || + (($temp = strlen($haystack) - strlen($needle)) >= 0 && false !== strpos($haystack, $needle, $temp)); + } + /** * Generates an array of strings that constitutes the cartesian product of all passed sets, with all * string combinations concatenated using the passed join-operator. diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php index 0bddc906d..70aadf666 100644 --- a/library/Icinga/Web/Widget/Chart/InlinePie.php +++ b/library/Icinga/Web/Widget/Chart/InlinePie.php @@ -5,11 +5,13 @@ namespace Icinga\Web\Widget\Chart; use Icinga\Chart\PieChart; use Icinga\Module\Monitoring\Plugin\PerfdataSet; +use Icinga\Util\String; use Icinga\Web\Widget\AbstractWidget; use Icinga\Web\Url; use Icinga\Util\Format; use Icinga\Application\Logger; use Icinga\Exception\IcingaException; +use stdClass; /** * A SVG-PieChart intended to be displayed as a small icon next to labels, to offer a better visualization of the @@ -27,6 +29,45 @@ class InlinePie extends AbstractWidget const NUMBER_FORMAT_BYTES = 'bytes'; const NUMBER_FORMAT_RATIO = 'ratio'; + public static $colorsHostStates = array( + '#44bb77', // up + '#ff99aa', // down + '#cc77ff', // unreachable + '#77aaff' // pending + ); + + public static $colorsHostStatesHandledUnhandled = array( + '#44bb77', // up + '#44bb77', + '#ff99aa', // down + '#ff5566', + '#cc77ff', // unreachable + '#aa44ff', + '#77aaff', // pending + '#77aaff' + ); + + public static $colorsServiceStates = array( + '#44bb77', // Ok + '#ffaa44', // Warning + '#ff99aa', // Critical + '#aa44ff', // Unknown + '#77aaff' // Pending + ); + + public static $colorsServiceStatesHandleUnhandled = array( + '#44bb77', // Ok + '#44bb77', + '#ffaa44', // Warning + '#ffcc66', + '#ff99aa', // Critical + '#ff5566', + '#cc77ff', // Unknown + '#aa44ff', + '#77aaff', // Pending + '#77aaff' + ); + /** * The template string used for rendering this widget * @@ -231,4 +272,19 @@ EOD; $template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template); return $template; } + + public static function createFromStateSummary(stdClass $states, $title, array $colors) + { + $handledUnhandledStates = array(); + foreach ($states as $key => $value) { + if (String::endsWith($key, '_handled') || String::endsWith($key, '_unhandled')) { + $handledUnhandledStates[$key] = $value; + } + } + $chart = new self(array_values($handledUnhandledStates), $title, $colors); + return $chart + ->setSize(50) + ->setTitle('') + ->setSparklineClass('sparkline-multi'); + } } diff --git a/modules/monitoring/application/controllers/HostsController.php b/modules/monitoring/application/controllers/HostsController.php index b8e36e2b0..3c59f4643 100644 --- a/modules/monitoring/application/controllers/HostsController.php +++ b/modules/monitoring/application/controllers/HostsController.php @@ -14,6 +14,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\HostList; use Icinga\Web\Url; +use Icinga\Web\Widget\Chart\InlinePie; class Monitoring_HostsController extends Controller { @@ -127,13 +128,20 @@ class Monitoring_HostsController extends Controller $this->view->removeAckForm = $removeAckForm; } + $hostStates = (object)$this->hostList->getStateSummary(); + $this->view->hostStatesPieChart = InlinePie::createFromStateSummary( + $hostStates, + $this->translate('Host State'), + InlinePie::$colorsHostStatesHandledUnhandled + ); + $this->setAutorefreshInterval(15); $this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/hosts/reschedule-check'); $this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/hosts/schedule-downtime'); $this->view->processCheckResultAllLink = Url::fromRequest()->setPath('monitoring/hosts/process-check-result'); $this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/hosts/add-comment'); $this->view->deleteCommentLink = Url::fromRequest()->setPath('monitoring/hosts/delete-comment'); - $this->view->stats = (object)$this->hostList->getStateSummary(); + $this->view->stats = $hostStates; $this->view->objects = $this->hostList; $this->view->unhandledObjects = $unhandledObjects; $unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString(); diff --git a/modules/monitoring/application/controllers/ServicesController.php b/modules/monitoring/application/controllers/ServicesController.php index 691897a57..e7199ed26 100644 --- a/modules/monitoring/application/controllers/ServicesController.php +++ b/modules/monitoring/application/controllers/ServicesController.php @@ -15,7 +15,9 @@ use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\ServiceList; +use Icinga\Util\String; use Icinga\Web\Url; +use Icinga\Web\Widget\Chart\InlinePie; class Monitoring_ServicesController extends Controller { @@ -109,6 +111,8 @@ class Monitoring_ServicesController extends Controller 'host_name', 'host_output', 'host_state', + 'host_problem', + 'host_handled', 'service_output', 'service_description', 'service_state', @@ -153,6 +157,20 @@ class Monitoring_ServicesController extends Controller ->handleRequest(); $this->view->removeAckForm = $removeAckForm; } + + $serviceStates = $this->serviceList->getServiceStateSummary(); + $this->view->serviceStatesPieChart = InlinePie::createFromStateSummary( + $serviceStates, + $this->translate('Service State'), + InlinePie::$colorsServiceStatesHandleUnhandled + ); + + $hostStates = $this->serviceList->getHostStateSummary(); + $this->view->hostStatesPieChart = InlinePie::createFromStateSummary( + $hostStates, + $this->translate('Host State'), + InlinePie::$colorsHostStatesHandledUnhandled + ); /* if (! empty($objectsInDowntime)) { $removeDowntimeForm = new DeleteDowntimeCommandForm(); @@ -170,7 +188,8 @@ class Monitoring_ServicesController extends Controller ); $this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/services/add-comment'); $this->view->deleteCommentLink = Url::fromRequest()->setPath('monitoring/services/delete-comment'); - $this->view->stats = $this->serviceList->getStateSummary(); + $this->view->stats = $serviceStates; + $this->view->hostStats = $hostStates; $this->view->objects = $this->serviceList; $this->view->unhandledObjects = $unhandledObjects; $unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString(); diff --git a/modules/monitoring/application/views/scripts/hosts/show.phtml b/modules/monitoring/application/views/scripts/hosts/show.phtml index d56f92af4..ab92a2f04 100644 --- a/modules/monitoring/application/views/scripts/hosts/show.phtml +++ b/modules/monitoring/application/views/scripts/hosts/show.phtml @@ -9,6 +9,13 @@ use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm; render('list/components/hostssummary.phtml') ?> + +
+
+ translate('Host States:') ?> +   +
+ render('partials/host/objects-header.phtml'); ?> diff --git a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml index 322243be1..d2ce6a500 100644 --- a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml @@ -12,14 +12,6 @@ $hiddenRich = array();

- - - - - - - - diff --git a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml index 5580446a1..24524954c 100644 --- a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml @@ -10,15 +10,6 @@ use Icinga\Module\Monitoring\Object\Service; 0): ?>

icon('host'); ?> translate('Host'); ?>icon('paste'); ?> translate('Plugin Output'); ?>
- - - - - - - - - render('list/components/servicesummary.phtml') ?> +
+
+ translate('Service States:') ?> +   +
+
+ translate('Host States:') ?> +   +
+ render('partials/service/objects-header.phtml'); ?> diff --git a/modules/monitoring/library/Monitoring/Object/ServiceList.php b/modules/monitoring/library/Monitoring/Object/ServiceList.php index 861075004..4d0e053d7 100644 --- a/modules/monitoring/library/Monitoring/Object/ServiceList.php +++ b/modules/monitoring/library/Monitoring/Object/ServiceList.php @@ -10,6 +10,10 @@ use Icinga\Util\String; */ class ServiceList extends ObjectList { + protected $hostStateSummary; + + protected $serviceStateSummary; + protected $dataViewName = 'serviceStatus'; protected $columns = array('host_name', 'service_description'); @@ -33,7 +37,32 @@ class ServiceList extends ObjectList * * @return object The summary */ - public function getStateSummary() + public function getServiceStateSummary() + { + if (! $this->serviceStateSummary) { + $this->initStateSummaries(); + } + return (object)$this->serviceStateSummary; + } + + /** + * Create a state summary of all hosts that can be consumed by hostsummary.phtml + * + * @return object The summary + */ + public function getHostStateSummary() + { + if (! $this->hostStateSummary) { + $this->initStateSummaries(); + } + return (object)$this->hostStateSummary; + } + + /** + * Calculate the current state summary and populate hostStateSummary and serviceStateSummary + * properties + */ + protected function initStateSummaries() { $serviceStates = array_fill_keys(self::getServiceStatesSummaryEmpty(), 0); $hostStates = array_fill_keys(HostList::getHostStatesSummaryEmpty(), 0); @@ -47,15 +76,19 @@ class ServiceList extends ObjectList $stateName = 'services_' . $service::getStateText($service->state); ++$serviceStates[$stateName]; ++$serviceStates[$stateName . ($unhandled ? '_unhandled' : '_handled')]; + if (! isset($knownHostStates[$service->getHost()->getName()])) { - $knownHostStates[$service->getHost()->getName()] = true; + $unhandledHost = (bool) $service->host_problem === true && (bool) $service->host_handled === false; ++$hostStates['hosts_' . $service->getHost()->getStateText($service->host_state)]; + ++$hostStates['hosts_' . $service->getHost()->getStateText($service->host_state) + . ($unhandledHost ? '_unhandled' : '_handled')]; + $knownHostStates[$service->getHost()->getName()] = true; } } $serviceStates['services_total'] = count($this); - - return (object)$serviceStates; + $this->hostStateSummary = $hostStates; + $this->serviceStateSummary = $serviceStates; } /**
icon('service'); ?> translate('Service'); ?>icon('host'); ?> translate('Host'); ?>icon('paste'); ?> translate('Plugin Output'); ?>