✏️ 正在编辑: CServicesSlaCalculator.php
路径:
/usr/share/zabbix/include/classes/services/CServicesSlaCalculator.php
提示:
您可以编辑任何文件(包括二进制文件),但请注意不当修改可能导致文件损坏。
<?php /* ** Zabbix ** Copyright (C) 2001-2021 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ /** * A class with SLA calculation logic. * * Class CServicesSlaCalculator */ class CServicesSlaCalculator { /** * Calculates the SLA for the given service during the given period. * * Returns the following information: * - ok - the percentage of time the service was in OK state; * - problem - the percentage of time the service was in problem state; * - okTime - the time the service was in OK state, in seconds; * - problemTime - the time the service was in problem state, in seconds; * - downtimeTime - the time the service was down, in seconds; * - dt; * - ut. * * @param array $service_alarms * @param array $service_times * @param int $period_start * @param int $period_end * @param int $start_value the value of the last service alarm * * @return array */ public function calculateSla(array $service_alarms, array $service_times, $period_start, $period_end, $start_value) { /** * structure of "$data": * - alarm - on/off status (0,1 - off; >1 - on) * - dt_s - count of downtime starts * - dt_e - count of downtime ends * - ut_s - count of uptime starts * - ut_e - count of uptime ends * - clock - time stamp * * Key in $data array contains unique value to sort by. */ $data = []; $latest = 0; // Timestamp of last database record. foreach ($service_alarms as $alarm) { if ($alarm['clock'] >= $period_start && $alarm['clock'] <= $period_end) { $data[$alarm['servicealarmid']] = [ 'alarm' => $alarm['value'], 'clock' => $alarm['clock'] ]; if ($alarm['clock'] > $latest) { $latest = $alarm['clock']; } } } if ($period_end != $latest) { $data[] = ['clock' => $period_end]; } $unmarkedPeriodType = 'ut'; $service_time_data = []; foreach ($service_times as $time) { if ($time['type'] == SERVICE_TIME_TYPE_UPTIME) { $this->expandPeriodicalTimes($service_time_data, $period_start, $period_end, $time['ts_from'], $time['ts_to'], 'ut' ); // if an uptime period exists - unmarked time is downtime $unmarkedPeriodType = 'dt'; } elseif ($time['type'] == SERVICE_TIME_TYPE_DOWNTIME) { $this->expandPeriodicalTimes($service_time_data, $period_start, $period_end, $time['ts_from'], $time['ts_to'], 'dt' ); } elseif ($time['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME && $time['ts_to'] >= $period_start && $time['ts_from'] <= $period_end) { if ($time['ts_from'] < $period_start) { $time['ts_from'] = $period_start; } if ($time['ts_to'] > $period_end) { $time['ts_to'] = $period_end; } if (isset($service_time_data[$time['ts_from']]['dt_s'])) { $service_time_data[$time['ts_from']]['dt_s']++; } else { $service_time_data[$time['ts_from']]['dt_s'] = 1; } if (isset($service_time_data[$time['ts_to']]['dt_e'])) { $service_time_data[$time['ts_to']]['dt_e']++; } else { $service_time_data[$time['ts_to']]['dt_e'] = 1; } } } if ($service_time_data) { ksort($service_time_data); /* * If 'downtime' service time is active at moment of $period_start and service is in problem state, move * $start_value to moment when service time ends. */ if ($start_value > 1) { $first_service_time_start_time = key($service_time_data); $first_service_time = $service_time_data[$first_service_time_start_time]; if ($period_start == $first_service_time_start_time && array_key_exists('dt_s', $first_service_time)) { foreach (array_keys($service_time_data) as $service_time_ts) { if (array_key_exists('dt_e', $service_time_data[$service_time_ts])) { $data[] = [ 'alarm' => $start_value, 'clock' => $service_time_ts ]; $start_value = 0; break; } } } } /* * For next foreach we need incrementally increasing keys (starting with n > 0) but entries still need to * be sorted by 'clock'. */ CArrayHelper::sort($data, [['field' => 'clock', 'order' => ZBX_SORT_UP]]); $data = array_combine(range(1, count($data)), array_values($data)); // Put service times between alarms at right positions. $prev_time = $period_start; $prev_alarmid = 0; foreach ($data as $alarmid => $val) { /** * Search what service times was in force during the alarm interval and put selected services right * before the end of service alarm interval. */ $service_times = CArrayHelper::getByKeysRange($service_time_data, $prev_time, $val['clock']); foreach ($service_times as $ts => $service_time) { $data[$prev_alarmid.'.'.$ts] = $service_time + ['clock' => $ts]; } $prev_time = $val['clock'] + 1; // Next range begins in next second. $prev_alarmid = $alarmid; } } // Sort chronologically. ksort($data); // calculate times $dtCnt = 0; $utCnt = 0; $slaTime = [ 'dt' => ['problemTime' => 0, 'okTime' => 0], 'ut' => ['problemTime' => 0, 'okTime' => 0] ]; $prevTime = $period_start; // Count active uptimes/downtimes at the beginning of calculated period. foreach ($data as $val) { if ($period_start != $val['clock']) { continue; } if (array_key_exists('ut_s', $val)) { $utCnt += $val['ut_s']; } if (array_key_exists('ut_e', $val)) { $utCnt -= $val['ut_e']; } if (array_key_exists('dt_s', $val)) { $dtCnt += $val['dt_s']; } if (array_key_exists('dt_e', $val)) { $dtCnt -= $val['dt_e']; } break; } foreach ($data as $val) { // skip first data [already read] if ($val['clock'] == $period_start) { continue; } if ($dtCnt > 0) { $periodType = 'dt'; } elseif ($utCnt > 0) { $periodType = 'ut'; } else { $periodType = $unmarkedPeriodType; } // Calculate the duration of current state. Negative durations are ignored. $duration = max($val['clock'] - $prevTime, 0); // state=0,1 [OK] (1 - information severity of trigger), >1 [PROBLEMS] (trigger severity) if ($start_value > 1) { $slaTime[$periodType]['problemTime'] += $duration; } else { $slaTime[$periodType]['okTime'] += $duration; } if (isset($val['ut_s'])) { $utCnt += $val['ut_s']; } if (isset($val['ut_e'])) { $utCnt -= $val['ut_e']; } if (isset($val['dt_s'])) { $dtCnt += $val['dt_s']; } if (isset($val['dt_e'])) { $dtCnt -= $val['dt_e']; } if (isset($val['alarm'])) { $start_value = $val['alarm']; } $prevTime = $val['clock']; } $slaTime['problemTime'] = &$slaTime['ut']['problemTime']; $slaTime['okTime'] = &$slaTime['ut']['okTime']; $slaTime['downtimeTime'] = $slaTime['dt']['okTime'] + $slaTime['dt']['problemTime']; $fullTime = $slaTime['problemTime'] + $slaTime['okTime']; if ($fullTime > 0) { $slaTime['problem'] = 100 * $slaTime['problemTime'] / $fullTime; $slaTime['ok'] = 100 * $slaTime['okTime'] / $fullTime; } else { $slaTime['problem'] = 100; $slaTime['ok'] = 100; } return $slaTime; } /** * Adds information about a weekly scheduled uptime or downtime to the $data array. * * @param array $data * @param int $period_start start of the SLA calculation period * @param int $period_end end of the SLA calculation period * @param int $ts_from start of the scheduled uptime or downtime * @param int $ts_to end of the scheduled uptime or downtime * @param string $type "ut" for uptime and "dt" for downtime */ protected function expandPeriodicalTimes(array &$data, $period_start, $period_end, $ts_from, $ts_to, $type) { $weekStartDate = new DateTime(); $weekStartDate->setTimestamp($period_start); $days = $weekStartDate->format('w'); $hours = $weekStartDate->format('H'); $minutes = $weekStartDate->format('i'); $seconds = $weekStartDate->format('s'); $weekStartDate->modify('-'.$days.' day -'.$hours.' hour -'.$minutes.' minute -'.$seconds.' second'); $weekStartTimestamp = $weekStartDate->getTimestamp(); for (; $weekStartTimestamp < $period_end; $weekStartTimestamp += $this->secondsPerNextWeek($weekStartTimestamp)) { $weekStartDate->setTimestamp($weekStartTimestamp); $weekStartDate->modify('+'.$ts_from.' second'); $_s = $weekStartDate->getTimestamp(); $weekStartDate->setTimestamp($weekStartTimestamp); $weekStartDate->modify('+'.$ts_to.' second'); $_e = $weekStartDate->getTimestamp(); if ($period_end < $_s || $period_start >= $_e) { continue; } if ($_s < $period_start) { $_s = $period_start; } if ($_e > $period_end) { $_e = $period_end; } if (isset($data[$_s][$type.'_s'])) { $data[$_s][$type.'_s']++; } else { $data[$_s][$type.'_s'] = 1; } if (isset($data[$_e][$type.'_e'])) { $data[$_e][$type.'_e']++; } else { $data[$_e][$type.'_e'] = 1; } } } /** * Return seconds in next week relative to given week start timestamp. * * @param int $currentWeekStartTimestamp * * @return int */ protected function secondsPerNextWeek($currentWeekStartTimestamp) { $currentWeekStartDate = new DateTime(); $currentWeekStartDate->setTimestamp($currentWeekStartTimestamp); $currentWeekStartDate->modify('+7 day'); $result = $currentWeekStartDate->getTimestamp() - $currentWeekStartTimestamp; return $result; } }
💾 保存文件
← 返回文件管理器