From b18bc644404e02b57635bfcc8258e85abb141146 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:44:46 +0200 Subject: Adding upstream version 1.1.1. Signed-off-by: Daniel Baumann --- .../Icingadb/ProvidedHook/Reporting/SlaReport.php | 297 +++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 library/Icingadb/ProvidedHook/Reporting/SlaReport.php (limited to 'library/Icingadb/ProvidedHook/Reporting/SlaReport.php') diff --git a/library/Icingadb/ProvidedHook/Reporting/SlaReport.php b/library/Icingadb/ProvidedHook/Reporting/SlaReport.php new file mode 100644 index 0000000..8dcc64e --- /dev/null +++ b/library/Icingadb/ProvidedHook/Reporting/SlaReport.php @@ -0,0 +1,297 @@ +createReportData(); + $rows = []; + + $filter = trim((string) $config['filter']) ?: '*'; + $filter = $filter !== '*' ? QueryString::parse($filter) : null; + + $interval = null; + $boundary = null; + $format = null; + if (isset($config['breakdown']) && $config['breakdown'] !== 'none') { + switch ($config['breakdown']) { + case 'hour': + $interval = new DateInterval('PT1H'); + $format = 'H:i:s'; + $boundary = '+1 hour'; + + break; + case 'day': + $interval = new DateInterval('P1D'); + $format = 'Y-m-d'; + $boundary = 'tomorrow midnight'; + + break; + case 'week': + $interval = new DateInterval('P1W'); + $format = 'Y-\WW'; + $boundary = 'monday next week midnight'; + + break; + case 'month': + $interval = new DateInterval('P1M'); + $format = 'Y-m'; + $boundary = 'first day of next month midnight'; + + break; + } + + $dimensions = $rd->getDimensions(); + $dimensions[] = ucfirst($config['breakdown']); + $rd->setDimensions($dimensions); + + foreach ($this->yieldTimerange($timerange, $interval, $boundary) as list($start, $end)) { + foreach ($this->fetchSla(new Timerange($start, $end), $filter) as $row) { + $row = $this->createReportRow($row); + + if ($row === null) { + continue; + } + + $dimensions = $row->getDimensions(); + $dimensions[] = $start->format($format); + $row->setDimensions($dimensions); + + $rows[] = $row; + } + } + } else { + foreach ($this->fetchSla($timerange, $filter) as $row) { + $rows[] = $this->createReportRow($row); + } + } + + $rd->setRows($rows); + + return $rd; + } + + /** + * Yield start and end times that recur at the specified interval over the given time range + * + * @param Timerange $timerange + * @param DateInterval $interval + * @param string|null $boundary English text datetime description for calculating bounds to get + * calendar days, weeks or months instead of relative times according to interval + * + * @return \Generator + */ + protected function yieldTimerange(Timerange $timerange, DateInterval $interval, $boundary = null) + { + $start = clone $timerange->getStart(); + $end = clone $timerange->getEnd(); + $oneSecond = new DateInterval('PT1S'); + + if ($boundary !== null) { + $intermediate = (clone $start)->modify($boundary); + if ($intermediate < $end) { + yield [clone $start, $intermediate->sub($oneSecond)]; + + $start->modify($boundary); + } + } + + $period = new DatePeriod($start, $interval, $end, DatePeriod::EXCLUDE_START_DATE); + + foreach ($period as $date) { + /** @var \DateTime $date */ + yield [$start, (clone $date)->sub($oneSecond)]; + + $start = $date; + } + + yield [$start, $end]; + } + + public function initConfigForm(Form $form) + { + $form->addElement('text', 'filter', [ + 'label' => t('Filter') + ]); + + $form->addElement('select', 'breakdown', [ + 'label' => t('Breakdown'), + 'options' => [ + 'none' => t('None', 'SLA Report Breakdown'), + 'hour' => t('Hour'), + 'day' => t('Day'), + 'week' => t('Week'), + 'month' => t('Month') + ] + ]); + + $form->addElement('number', 'threshold', [ + 'label' => t('Threshold'), + 'placeholder' => static::DEFAULT_THRESHOLD, + 'step' => '0.01', + 'min' => '1', + 'max' => '100' + ]); + + $form->addElement('number', 'sla_precision', [ + 'label' => t('Amount Decimal Places'), + 'placeholder' => static::DEFAULT_REPORT_PRECISION, + 'min' => '1', + 'max' => '12' + ]); + + $form->addElement('checkbox', 'export_total', [ + 'label' => t('Export Total Averages'), + 'description' => t('Export total averages to CSV and JSON'), + // Instead of y/n, 0/1 can be implicitly cast to bool which is done where the config is actually used. + 'checkedValue' => '1', + 'uncheckedValue' => '0' + ]); + } + + public function getData(Timerange $timerange, array $config = null) + { + return $this->fetchReportData($timerange, $config); + } + + public function getHtml(Timerange $timerange, array $config = null) + { + $data = $this->getData($timerange, $config); + + if (! count($data)) { + return new EmptyState(t('No data found.')); + } + + $threshold = isset($config['threshold']) ? (float) $config['threshold'] : static::DEFAULT_THRESHOLD; + + $tableHeaderCells = []; + + foreach ($data->getDimensions() as $dimension) { + $tableHeaderCells[] = Html::tag('th', null, $dimension); + } + + foreach ($data->getValues() as $value) { + $tableHeaderCells[] = Html::tag('th', null, $value); + } + + $tableRows = []; + $precision = $config['sla_precision'] ?? static::DEFAULT_REPORT_PRECISION; + + foreach ($data->getRows() as $row) { + $cells = []; + + foreach ($row->getDimensions() as $dimension) { + $cells[] = Html::tag('td', null, $dimension); + } + + // We only have one metric + $sla = $row->getValues()[0]; + + if ($sla < $threshold) { + $slaClass = 'nok'; + } else { + $slaClass = 'ok'; + } + + $cells[] = Html::tag('td', ['class' => "sla-column $slaClass"], round($sla, $precision)); + + $tableRows[] = Html::tag('tr', null, $cells); + } + + // We only have one average + $average = $data->getAverages()[0]; + + if ($average < $threshold) { + $slaClass = 'nok'; + } else { + $slaClass = 'ok'; + } + + $total = $this instanceof HostSlaReport + ? sprintf(t('Total (%d Hosts)'), $data->count()) + : sprintf(t('Total (%d Services)'), $data->count()); + + $tableRows[] = Html::tag('tr', null, [ + Html::tag('td', ['colspan' => count($data->getDimensions())], $total), + Html::tag('td', ['class' => "sla-column $slaClass"], round($average, $precision)) + ]); + + $table = Html::tag( + 'table', + ['class' => 'common-table sla-table'], + [ + Html::tag( + 'thead', + null, + Html::tag( + 'tr', + null, + $tableHeaderCells + ) + ), + Html::tag('tbody', null, $tableRows) + ] + ); + + return $table; + } +} -- cgit v1.2.3