parent
66c3dd26e5
commit
f5e4331d71
|
@ -87,6 +87,10 @@ url = "monitoring/list/notifications"
|
|||
title = "All Events"
|
||||
url = "monitoring/list/eventhistory?raw_timestamp>=-2+days"
|
||||
|
||||
[History.Timeline]
|
||||
title = "Timeline"
|
||||
url = "monitoring/timeline"
|
||||
|
||||
[System.Process Info]
|
||||
title = "Process Info"
|
||||
url = "monitoring/process/info"
|
||||
|
|
|
@ -30,7 +30,6 @@ namespace Icinga\Util;
|
|||
* Provide functions to change and convert colors.
|
||||
*/
|
||||
class Color {
|
||||
|
||||
/**
|
||||
* Convert a given color string to an rgb-array containing
|
||||
* each color as a decimal value.
|
||||
|
@ -71,7 +70,6 @@ class Color {
|
|||
. (strlen($b) > 1 ? $b : '0' . $b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change the saturation for a given color.
|
||||
*
|
||||
|
@ -85,10 +83,20 @@ class Color {
|
|||
*/
|
||||
public static function changeSaturation($color, $change)
|
||||
{
|
||||
$rgb = self::rgbAsArray($color);
|
||||
$rgb = self::changeRgbSaturation($rgb, $change);
|
||||
$col = self::arrayToRgb($rgb);
|
||||
return $col;
|
||||
return self::arrayToRgb(self::changeRgbSaturation(self::rgbAsArray($color), $change));
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the brightness for a given color
|
||||
*
|
||||
* @param $color string The color to change
|
||||
* @param $change float The change in percent
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function changeBrightness($color, $change)
|
||||
{
|
||||
return self::arrayToRgb(self::changeRgbBrightness(self::rgbAsArray($color), $change));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,4 +123,21 @@ class Color {
|
|||
$rgb[2] = (int)($p + ($b - $p) * $change);
|
||||
return $rgb;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $rgb array The rgb-array to change
|
||||
* @param $change float The factor
|
||||
*
|
||||
* @return array The updated rgb-array
|
||||
*/
|
||||
private static function changeRgbBrightness(array $rgb, $change)
|
||||
{
|
||||
$red = $rgb[0] + (255 * $change);
|
||||
$green = $rgb[1] + (255 * $change);
|
||||
$blue = $rgb[2] + (255 * $change);
|
||||
$rgb[0] = $red < 255 ? (int) $red : 255;
|
||||
$rgb[1] = $green < 255 ? (int) $green : 255;
|
||||
$rgb[2] = $blue < 255 ? (int) $blue : 255;
|
||||
return $rgb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ class Monitoring_TimelineController extends ActionController
|
|||
$this->setupIntervalBox();
|
||||
list($displayRange, $forecastRange) = $this->buildTimeRanges();
|
||||
|
||||
$detailUrl = '/monitoring/list/eventhistory?raw_timestamp<=%s&raw_timestamp>=%s&type=%s';
|
||||
$timeline = new TimeLine(
|
||||
EventHistoryView::fromRequest(
|
||||
$this->getRequest(),
|
||||
|
@ -28,14 +29,39 @@ class Monitoring_TimelineController extends ActionController
|
|||
)
|
||||
),
|
||||
array(
|
||||
'notify' => array('label' => t('Notifications'), 'color' => 'red'),
|
||||
'hard_state' => array('label' => t('Hard state changes'), 'color' => 'green'),
|
||||
'comment' => array('label' => t('Comments'), 'color' => 'blue'),
|
||||
'ack' => array('label' => t('Acknowledgements'), 'color' => 'black'),
|
||||
'dt_start' => array('label' => t('Started downtimes'), 'color' => 'grey'),
|
||||
'dt_end' => array('label' => t('Ended downtimes'), 'color' => 'white')
|
||||
'notify' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Notifications'),
|
||||
'color' => '#3a71ea'
|
||||
),
|
||||
'hard_state' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Hard state changes'),
|
||||
'color' => '#ff7000'
|
||||
),
|
||||
'comment' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Comments'),
|
||||
'color' => '#79bdba'
|
||||
),
|
||||
'ack' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Acknowledgements'),
|
||||
'color' => '#a2721d'
|
||||
),
|
||||
'dt_start' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Started downtimes'),
|
||||
'color' => '#8e8e8e'
|
||||
),
|
||||
'dt_end' => array(
|
||||
'detailUrl' => $detailUrl,
|
||||
'label' => t('Ended downtimes'),
|
||||
'color' => '#d5d6ad'
|
||||
)
|
||||
)
|
||||
);
|
||||
$timeline->setMaximumCircleWidth('6em');
|
||||
$timeline->setDisplayRange($displayRange);
|
||||
$timeline->setForecastRange($forecastRange);
|
||||
$timeline->setSession($this->getWindowSession('timeline'));
|
||||
|
@ -99,13 +125,13 @@ class Monitoring_TimelineController extends ActionController
|
|||
case '1d':
|
||||
return $this->getDateFormat();
|
||||
case '1w':
|
||||
return '\W\e\ek #W \of Y';
|
||||
return '\W\e\ek #W\<b\r\>\of Y';
|
||||
case '1m':
|
||||
return 'F Y';
|
||||
case '1y':
|
||||
return 'Y';
|
||||
default:
|
||||
return $this->getDateFormat() . ' ' . $this->getTimeFormat();
|
||||
return $this->getDateFormat() . '\<b\r\>' . $this->getTimeFormat();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,85 @@
|
|||
<?php if (!$this->compact): ?>
|
||||
<?php
|
||||
use Icinga\Util\Color;
|
||||
|
||||
$groupInfo = $timeline->getGroupInfo();
|
||||
$firstRow = true;
|
||||
?>
|
||||
<div class="controls">
|
||||
<div style="margin: 1em;" class="dontprint">
|
||||
<?= $this->intervalBox; ?>
|
||||
<?= $intervalBox; ?>
|
||||
</div>
|
||||
<div style="margin: 1em;" class="timeline-legend">
|
||||
<h2><?= $this->translate('Legend'); ?></h2>
|
||||
<?php foreach ($groupInfo as $labelAndColor): ?>
|
||||
<span style="background-color: <?= $labelAndColor['color']; ?>;">
|
||||
<span><?= $labelAndColor['label']; ?></span>
|
||||
</span>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<table class="timeline">
|
||||
<tbody>
|
||||
<?php foreach ($timeline as $timeInfo): ?>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="<?= $this->href(
|
||||
'/monitoring/list/eventhistory',
|
||||
array(
|
||||
'raw_timestamp<' => $timeInfo[0]->start->getTimestamp(),
|
||||
'raw_timestamp>' => $timeInfo[0]->end->getTimestamp()
|
||||
)
|
||||
); ?>">
|
||||
<?= $timeInfo[0]->end->format($intervalFormat); ?>
|
||||
</a>
|
||||
</th>
|
||||
<?php foreach ($groupInfo as $groupName => $labelAndColor): ?>
|
||||
<td>
|
||||
<div class="circle-box">
|
||||
<?php if (array_key_exists($groupName, $timeInfo[1])): ?>
|
||||
<?php
|
||||
$circleWidth = $timeline->calculateCircleWidth($timeInfo[1][$groupName], 2);
|
||||
$extrapolatedCircleWidth = $timeline->getExtrapolatedCircleWidth($timeInfo[1][$groupName], 2);
|
||||
?>
|
||||
<?php if ($firstRow && $extrapolatedCircleWidth !== $circleWidth): ?>
|
||||
<?php
|
||||
$inlineStyle = sprintf(
|
||||
'width: %3$s; height: %3$s; background-color: %1$s; margin-top: -%2$s; margin-left: -%2$s;',
|
||||
Color::changeBrightness($timeInfo[1][$groupName]->getColor(), 0.25),
|
||||
((float) substr($extrapolatedCircleWidth, 0, -2) / 2) . 'em',
|
||||
$extrapolatedCircleWidth
|
||||
);
|
||||
?>
|
||||
<div class="outer-circle extrapolated" style="<?= $inlineStyle; ?>">
|
||||
<?php else: ?>
|
||||
<div class="outer-circle">
|
||||
<?php endif ?>
|
||||
<?= $this->timeline->buildTimeline(); ?>
|
||||
<?php
|
||||
$inlineStyle = sprintf(
|
||||
'width: %3$s; height: %3$s; background-color: %2$s; margin-top: -%1$s; margin-left: -%1$s;',
|
||||
((float) substr($circleWidth, 0, -2) / 2) . 'em',
|
||||
$timeInfo[1][$groupName]->getColor(),
|
||||
$circleWidth
|
||||
);
|
||||
?>
|
||||
<a class="inner-circle" style="<?= $inlineStyle; ?>" href="<?= $this->href(
|
||||
sprintf(
|
||||
$timeInfo[1][$groupName]->getDetailUrl(),
|
||||
$timeInfo[0]->start->getTimestamp(),
|
||||
$timeInfo[0]->end->getTimestamp(),
|
||||
$groupName
|
||||
)
|
||||
); ?>" title="<?= $timeInfo[1][$groupName]->getValue(); ?> <?= $labelAndColor['label']; ?>"></a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</td>
|
||||
<?php endforeach ?>
|
||||
</tr>
|
||||
<?php $firstRow = false; ?>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -162,6 +162,22 @@ class TimeLine implements IteratorAggregate
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all known group types (identifiers) with their respective labels and colors as array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupInfo()
|
||||
{
|
||||
$groupInfo = array();
|
||||
foreach ($this->identifiers as $name => $attributes) {
|
||||
$groupInfo[$name]['label'] = $attributes['label'];
|
||||
$groupInfo[$name]['color'] = $attributes['color'];
|
||||
}
|
||||
|
||||
return $groupInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the circle's diameter for the given event group
|
||||
*
|
||||
|
@ -410,106 +426,4 @@ class TimeLine implements IteratorAggregate
|
|||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the legend
|
||||
*/
|
||||
private function buildLegend()
|
||||
{
|
||||
// TODO: Put this in some sort of dedicated stylesheet
|
||||
$circleStyle = 'width:75px;height:75px;border-radius:50%;box-shadow:4px 4px 8px grey;border:2px solid;margin:auto;';
|
||||
$labelStyle = 'font-size:12px;margin-top:10px;text-align:center;';
|
||||
$titleStyle = 'margin-left:25px;';
|
||||
|
||||
$elements = array();
|
||||
foreach ($this->getGroups() as $groupName => $groupInfo) {
|
||||
$groupColor = $groupInfo['color'] !== null ? $groupInfo['color'] : $this->getRandomCssColor();
|
||||
$elements[] = '' .
|
||||
'<div style="' . $circleStyle . 'background-color: ' . $groupColor . '"></div>' .
|
||||
'<p style="' . $labelStyle . '">' . $groupName . '</p>';
|
||||
}
|
||||
|
||||
$legend = '' .
|
||||
'<h2 style="' . $titleStyle . '">' . t('Shown event groups') . '</h2>' .
|
||||
'<div class="row">' .
|
||||
implode(
|
||||
'',
|
||||
array_map(
|
||||
function ($e) { return '<div class="col-sm-6 col-xs-3 col-md-2 col-lg-1">' . $e . '</div>'; },
|
||||
$elements
|
||||
)
|
||||
) .
|
||||
'</div>';
|
||||
|
||||
return $legend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the timeline
|
||||
*/
|
||||
public function buildTimeline()
|
||||
{
|
||||
$timelineGroups = array();
|
||||
foreach ($this->displayData as $group) {
|
||||
$timestamp = $group->getDateTime()->getTimestamp();
|
||||
|
||||
if (!array_key_exists($timestamp, $timelineGroups)) {
|
||||
$timelineGroups[$timestamp] = array();
|
||||
}
|
||||
|
||||
$timelineGroups[$timestamp][] = $group;
|
||||
}
|
||||
|
||||
$elements = array();
|
||||
foreach ($this->range as $timestamp => $timeframe) {
|
||||
$elementGroups = array();
|
||||
$biggestWidth = 0;
|
||||
|
||||
if (array_key_exists($timestamp, $timelineGroups)) {
|
||||
foreach ($timelineGroups[$timestamp] as $group) {
|
||||
$circleWidth = $this->calculateCircleWidth(
|
||||
empty($elements) ? $this->extrapolateEventCount($group, 4) : $group->getValue()
|
||||
);
|
||||
$groupColor = $group->getColor() !== null ? $group->getColor() : $this->getRandomCssColor();
|
||||
$elementGroups[] = sprintf(
|
||||
'<div class="col-sm-12 col-xs-12 col-md-6 col-lg-3" style="width:%4$s%2$s;margin:10px 10px;float:left;">' .
|
||||
' <a href="%1$s" data-icinga-target="detail">' .
|
||||
' <div style="width:%4$s%2$s;height:%4$s%2$s;border-radius:50%%;' . // TODO: Put this in some sort of dedicated stylesheet
|
||||
'box-shadow:4px 4px 8px grey;border:2px solid black;' .
|
||||
'margin:auto;background-color:%5$s;text-align:center;' .
|
||||
'padding-top:25%%;color:black;">' .
|
||||
' %3$s' .
|
||||
' </div>' .
|
||||
' </a>' .
|
||||
'</div>',
|
||||
$group->getDetailUrl(),
|
||||
$this->diameterUnit,
|
||||
$group->getValue(),
|
||||
$circleWidth,
|
||||
$groupColor
|
||||
);
|
||||
|
||||
if ($circleWidth > $biggestWidth) {
|
||||
$biggestWidth = $circleWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$timeframeUrl = '';/*$this->getRequest()->getBaseUrl() . '/monitoring/list/eventhistory?timestamp<=' .
|
||||
$timeframe->start->getTimestamp() . '×tamp>=' . $timeframe->end->getTimestamp();*/
|
||||
$elements[] = sprintf(
|
||||
'<div class="row" style="height:%3$s%2$s;">%1$s</div>',
|
||||
implode('', $elementGroups),
|
||||
$this->diameterUnit,
|
||||
$biggestWidth
|
||||
);
|
||||
$elements[] = '<br style="clear:all;" />';
|
||||
$elements[] = '<div><a href="' . $timeframeUrl . '" data-icinga-target="detail">' .
|
||||
$timeframe->end->format($this->getIntervalFormat()) . '</a>' .
|
||||
'<hr style="margin-top:0;"></div>';
|
||||
}
|
||||
|
||||
$elements[] = '<span id="TimelineEnd"></span>';
|
||||
return implode('', $elements);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -630,6 +630,101 @@ table.pivot {
|
|||
|
||||
/* End of monitoring pivot table styles */
|
||||
|
||||
/* Monitoring timeline styles */
|
||||
|
||||
div.timeline-legend {
|
||||
float: left;
|
||||
padding: 0.5em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 0.5em;
|
||||
background-color: #eee;
|
||||
|
||||
&:after {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
margin-left: 0.5em;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
& > span {
|
||||
display: inline-block;
|
||||
padding: 0.5em;
|
||||
margin: 0.5em;
|
||||
border-radius: 0.5em;
|
||||
|
||||
span {
|
||||
color: white;
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.timeline {
|
||||
th {
|
||||
padding-right: 1.5em;
|
||||
|
||||
a {
|
||||
color: black;
|
||||
font-size: 0.8em;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.5em;
|
||||
|
||||
div.circle-box {
|
||||
width: 6em;
|
||||
height: 6em;
|
||||
position: relative;
|
||||
|
||||
div.outer-circle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
|
||||
&.extrapolated {
|
||||
// width: inline-style;
|
||||
// height: inline-style;
|
||||
top: 49%; // Compensate border
|
||||
left: 49%; // Compensate border
|
||||
// margin-top: inline-style;
|
||||
// margin-left: inline-style;
|
||||
border: 1px dashed #666;
|
||||
border-radius: 100%;
|
||||
// background-color: inline-style;
|
||||
}
|
||||
|
||||
a.inner-circle {
|
||||
// width: inline-style;
|
||||
// height: inline-style;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 49%; // Compensate border
|
||||
left: 49%; // Compensate border
|
||||
// margin-top: inline-style;
|
||||
// margin-left: inline-style;
|
||||
border: 1px solid black;
|
||||
border-radius: 100%;
|
||||
// background-color: inline-style;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* End of monitoring timeline styles */
|
||||
|
||||
.controls {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue