parent
58248c34a9
commit
71f4b6960b
|
@ -41,6 +41,11 @@ title = "Services"
|
||||||
url = "monitoring/list/services"
|
url = "monitoring/list/services"
|
||||||
priority = 50
|
priority = 50
|
||||||
|
|
||||||
|
[Overview.Servicematrix]
|
||||||
|
title = "Servicematrix"
|
||||||
|
url = "monitoring/list/servicematrix"
|
||||||
|
priority = 51
|
||||||
|
|
||||||
[Overview.Servicegroups]
|
[Overview.Servicegroups]
|
||||||
title = "Servicegroups"
|
title = "Servicegroups"
|
||||||
url = "monitoring/list/servicegroups"
|
url = "monitoring/list/servicegroups"
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
namespace Icinga\Data;
|
namespace Icinga\Data;
|
||||||
|
|
||||||
|
use \stdClass;
|
||||||
|
use Icinga\Data\BaseQuery;
|
||||||
|
|
||||||
class PivotTable
|
class PivotTable
|
||||||
{
|
{
|
||||||
protected $query;
|
protected $query;
|
||||||
|
|
||||||
protected $verticalColumn;
|
protected $xAxisColumn;
|
||||||
|
|
||||||
protected $horizontalColumn;
|
protected $yAxisColumn;
|
||||||
|
|
||||||
protected $limit;
|
protected $limit;
|
||||||
|
|
||||||
|
@ -18,11 +23,18 @@ class PivotTable
|
||||||
|
|
||||||
protected $horizontalLimit;
|
protected $horizontalLimit;
|
||||||
|
|
||||||
public function __construct(QueryInterface $query, $verticalColumn, $horizontalColumn)
|
/**
|
||||||
|
* Create a new pivot table
|
||||||
|
*
|
||||||
|
* @param BaseQuery $query The query to fetch as pivot table
|
||||||
|
* @param string $xAxisColumn The column to use for the x axis
|
||||||
|
* @param string $yAxisColumn The column to use for the y axis
|
||||||
|
*/
|
||||||
|
public function __construct(BaseQuery $query, $xAxisColumn, $yAxisColumn)
|
||||||
{
|
{
|
||||||
$this->query = $query;
|
$this->query = $query;
|
||||||
$this->verticalColumn = $verticalColumn;
|
$this->xAxisColumn = $xAxisColumn;
|
||||||
$this->horizontalColumn = $horizontalColumn;
|
$this->yAxisColumn = $yAxisColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function limit($limit = null, $offset = null)
|
public function limit($limit = null, $offset = null)
|
||||||
|
@ -85,51 +97,59 @@ class PivotTable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all columns
|
* Fetch the values to label the x axis with
|
||||||
*/
|
*/
|
||||||
public function fetchAll()
|
protected function fetchXAxis()
|
||||||
{
|
{
|
||||||
$xcol = $this->horizontalColumn;
|
$queryClass = get_class($this->query);
|
||||||
$ycol = $this->verticalColumn;
|
$query = new $queryClass($this->query->getDatasource(), array($this->xAxisColumn));
|
||||||
$queryX = clone($this->query);
|
return $query->fetchColumn();
|
||||||
$queryX->columns($xcol);
|
}
|
||||||
if ($this->limit !== null) {
|
|
||||||
$queryX->limit($this->getLimit(), $this->getOffset());
|
|
||||||
}
|
|
||||||
$queryX->limit(40);
|
|
||||||
$listX = $queryX->fetchColumn();
|
|
||||||
$queryY = clone($this->query);
|
|
||||||
|
|
||||||
$queryY->columns($ycol);
|
/**
|
||||||
if ($this->verticalLimit !== null) {
|
* Fetch the values to label the y axis with
|
||||||
$queryY->limit($this->getVerticalLimit(), $this->getVerticalOffset());
|
*/
|
||||||
}
|
protected function fetchYAxis()
|
||||||
$queryY->limit(50);
|
{
|
||||||
$listY = $queryY->fetchColumn();
|
$queryClass = get_class($this->query);
|
||||||
|
$query = new $queryClass($this->query->getDatasource(), array($this->yAxisColumn));
|
||||||
|
return $query->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the pivot table as array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
$xAxis = $this->fetchXAxis();
|
||||||
|
$yAxis = $this->fetchYAxis();
|
||||||
|
|
||||||
|
$this->query->where($this->xAxisColumn, $xAxis)->where($this->yAxisColumn, $yAxis);
|
||||||
|
if (!$this->query->hasOrder()) {
|
||||||
|
$this->query->order($this->xAxisColumn)->order($this->yAxisColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
$emptyrow = new stdClass();
|
||||||
|
foreach ($this->query->getColumns() as $col) {
|
||||||
|
$emptyrow->{$col} = null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: resetOrder
|
|
||||||
$this->query
|
|
||||||
->where($ycol, $listY)
|
|
||||||
->where($xcol, $listX)
|
|
||||||
->order($ycol)
|
|
||||||
->order($xcol);
|
|
||||||
$pivot = array();
|
$pivot = array();
|
||||||
$emptyrow = (object) array();
|
foreach ($xAxis as $x) {
|
||||||
foreach ($this->query->listColumns() as $col) {
|
foreach ($yAxis as $y) {
|
||||||
$emptyrow->$col = null;
|
|
||||||
}
|
|
||||||
foreach ($listY as $y) {
|
|
||||||
foreach ($listX as $x) {
|
|
||||||
$row = clone($emptyrow);
|
$row = clone($emptyrow);
|
||||||
$row->$xcol = $x;
|
$row->{$this->xAxisColumn} = $x;
|
||||||
$row->$ycol = $y;
|
$row->{$this->yAxisColumn} = $y;
|
||||||
$pivot[$y][$x] = $row;
|
$pivot[$y][$x] = $row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->query->fetchAll() as $row) {
|
foreach ($this->query->fetchAll() as $row) {
|
||||||
$pivot[$row->$ycol][$row->$xcol] = $row;
|
$pivot[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $pivot;
|
return $pivot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,6 +458,33 @@ class Monitoring_ListController extends Controller
|
||||||
$this->view->history = $query->paginate();
|
$this->view->history = $query->paginate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function servicematrixAction()
|
||||||
|
{
|
||||||
|
$this->view->title = 'Servicematrix';
|
||||||
|
$this->addTitleTab('servicematrix');
|
||||||
|
$dataview = ServiceStatusView::fromRequest(
|
||||||
|
$this->getRequest(),
|
||||||
|
array(
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'service_state',
|
||||||
|
'service_output',
|
||||||
|
'service_handled'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setupFilterControl($dataview, 'servicematrix');
|
||||||
|
$this->setupSortControl(
|
||||||
|
array(
|
||||||
|
'service_state' => 'Service status',
|
||||||
|
'service_description' => 'Service description',
|
||||||
|
'host_name' => 'Hostname'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->view->matrix = $dataview->pivot('service_description', 'host_name')->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply current users monitoring/filter restrictions to the given query
|
* Apply current users monitoring/filter restrictions to the given query
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php if (!$this->compact): ?>
|
||||||
|
<div class="controls">
|
||||||
|
<?= $this->tabs; ?>
|
||||||
|
<div style="margin: 1em;" class="dontprint">
|
||||||
|
<!--<?= $this->filterBox; ?>-->Sort by <?= $this->sortControl->render($this); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
<div class="content" data-base-target="_next">
|
||||||
|
<table class="pivot servicestates">
|
||||||
|
<?php $hasHeader = false; ?>
|
||||||
|
<?php foreach ($this->matrix as $host_name => $serviceStates): ?>
|
||||||
|
<?php if (!$hasHeader): ?>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<?php foreach (array_keys($serviceStates) as $service_description): ?>
|
||||||
|
<th><span><?= $service_description; ?></span></th>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $hasHeader = true; ?>
|
||||||
|
<?php endif ?>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="<?= $this->href('monitoring/show/host', array('host' => $host_name)); ?>">
|
||||||
|
<?= $host_name; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<?php foreach (array_values($serviceStates) as $service): ?>
|
||||||
|
<?php if ($service->service_state !== null): ?>
|
||||||
|
<td class="state_<?= $this->monitoringState($service, 'service'); ?> <?= $service->service_handled ? 'handled' : ''; ?>">
|
||||||
|
<a href="<?= $this->href(
|
||||||
|
'monitoring/show/service',
|
||||||
|
array(
|
||||||
|
'host' => $service->host_name,
|
||||||
|
'service' => $service->service_description
|
||||||
|
)
|
||||||
|
); ?>" title="<?= $this->escape($service->service_output); ?>"></a>
|
||||||
|
<?php else: ?>
|
||||||
|
<td>
|
||||||
|
·
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
|
@ -30,6 +30,7 @@
|
||||||
namespace Icinga\Module\Monitoring\DataView;
|
namespace Icinga\Module\Monitoring\DataView;
|
||||||
|
|
||||||
use Icinga\Data\BaseQuery;
|
use Icinga\Data\BaseQuery;
|
||||||
|
use Icinga\Data\PivotTable;
|
||||||
use Icinga\Filter\Filterable;
|
use Icinga\Filter\Filterable;
|
||||||
use Icinga\Filter\Query\Tree;
|
use Icinga\Filter\Query\Tree;
|
||||||
use Icinga\Module\Monitoring\Backend;
|
use Icinga\Module\Monitoring\Backend;
|
||||||
|
@ -167,6 +168,19 @@ abstract class DataView implements Filterable
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a pivot table for the given columns based on the current query
|
||||||
|
*
|
||||||
|
* @param string $xAxisColumn The column to use for the x axis
|
||||||
|
* @param string $yAxisColumn The column to use for the y axis
|
||||||
|
*
|
||||||
|
* @return PivotTable
|
||||||
|
*/
|
||||||
|
public function pivot($xAxisColumn, $yAxisColumn)
|
||||||
|
{
|
||||||
|
return new PivotTable($this->query, $xAxisColumn, $yAxisColumn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the rows, according to the specified sort column and order
|
* Sort the rows, according to the specified sort column and order
|
||||||
*
|
*
|
||||||
|
|
|
@ -501,6 +501,112 @@ div.box.contactgroup div.box.entry p {
|
||||||
/* End of monitoring box element styles */
|
/* End of monitoring box element styles */
|
||||||
|
|
||||||
|
|
||||||
|
/* Monitoring pivot table styles */
|
||||||
|
|
||||||
|
table.pivot {
|
||||||
|
width: 100%;
|
||||||
|
table-layout: fixed;
|
||||||
|
border-spacing: 0.2em;
|
||||||
|
border-collapse: separate;
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
width: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
th {
|
||||||
|
height: 6em;
|
||||||
|
padding: 0 0 1em 1.4em;
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
width: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 2.4em;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
transform-origin: bottom left;
|
||||||
|
-o-transform: rotate(-45deg);
|
||||||
|
-o-transform-origin: bottom left;
|
||||||
|
-ms-transform: rotate(-45deg);
|
||||||
|
-ms-transform-origin: bottom left;
|
||||||
|
-moz-transform: rotate(-45deg);
|
||||||
|
-moz-transform-origin: bottom left;
|
||||||
|
-webkit-transform: rotate(-45deg);
|
||||||
|
-webkit-transform-origin: bottom left;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
th {
|
||||||
|
width: 4em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 2.2em;
|
||||||
|
padding-right: 1.2em;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding: 20% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state_ok {
|
||||||
|
background-color: @colorOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state_pending {
|
||||||
|
background-color: @colorPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state_warning {
|
||||||
|
background-color: @colorWarning;
|
||||||
|
|
||||||
|
&.handled {
|
||||||
|
background-color: @colorWarningHandled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state_critical {
|
||||||
|
background-color: @colorCritical;
|
||||||
|
|
||||||
|
&.handled {
|
||||||
|
background-color: @colorCriticalHandled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state_unknown {
|
||||||
|
background-color: @colorUnknown;
|
||||||
|
|
||||||
|
&.handled {
|
||||||
|
background-color: @colorUnknownHandled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of monitoring pivot table styles */
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue