librenms/LibreNMS/Device/Availability.php

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

142 lines
4.5 KiB
PHP
Raw Permalink Normal View History

<?php
/**
* Availability.php
*
* Availability calculation
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
2021-09-10 18:09:53 +00:00
*
* @copyright 2020 Thomas Berberich
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
*/
namespace LibreNMS\Device;
use App\Models\Device;
use App\Models\DeviceOutage;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use LibreNMS\Util\Number;
class Availability
{
/*
* 1 day 1 * 24 * 60 * 60 = 86400
* 1 week 7 * 24 * 60 * 60 = 604800
* 1 month 30 * 24 * 60 * 60 = 2592000
* 1 year 365 * 24 * 60 * 60 = 31536000
*/
public static function day(Device $device, int $precision = 3): float
{
$duration = 86400;
return self::availability($device, $duration, $precision);
}
public static function week(Device $device, int $precision = 3): float
{
$duration = 604800;
return self::availability($device, $duration, $precision);
}
public static function month(Device $device, int $precision = 3): float
{
$duration = 2592000;
return self::availability($device, $duration, $precision);
}
public static function year(Device $device, int $precision = 3): float
{
$duration = 31536000;
return self::availability($device, $duration, $precision);
}
2020-06-28 11:47:26 +00:00
/**
* addition of all recorded outages in seconds
*
* @param Collection<DeviceOutage> $found_outages filtered database object with all recorded outages
2021-09-08 21:35:56 +00:00
* @param int $duration time period to calculate for
* @param int $now timestamp for 'now'
* @return int sum of all matching outages in seconds
2020-06-28 11:47:26 +00:00
*/
protected static function outageSummary(Collection $found_outages, int $duration, int $now): int
2020-06-28 11:47:26 +00:00
{
// sum up time period of all outages
$outage_sum = 0;
foreach ($found_outages as $outage) {
// if device is still down, outage goes till $now
$up_again = $outage->up_again ?: $now;
if ($outage->going_down >= ($now - $duration)) {
// outage complete in duration period
$going_down = $outage->going_down;
} else {
// outage partial in duration period, so consider only relevant part
$going_down = $now - $duration;
}
$outage_sum += ($up_again - $going_down);
}
2020-06-28 11:47:26 +00:00
return $outage_sum;
}
/**
* Get the availability (decreasing) of this device
* means, starting with 100% as default
* substracts recorded outages
*
* @param Device $device device to be looked at
2021-09-08 21:35:56 +00:00
* @param int $duration time period to calculate for
* @param int $precision float precision for calculated availability
2020-06-28 11:47:26 +00:00
* @return float calculated availability
*/
public static function availability(Device $device, int $duration, int $precision = 3): float
2020-06-28 11:47:26 +00:00
{
$now = time();
$found_outages = $device->outages()->where('up_again', '>=', $now - $duration)
->orderBy('going_down')->get();
2020-06-28 11:47:26 +00:00
// no recorded outages found, so use current status
if ($found_outages->isEmpty()) {
return $device->status ? 100 : 0;
}
2020-06-28 11:47:26 +00:00
// don't calculate for time when the device didn't exist
if ($device->inserted) {
$duration = min($duration, $device->inserted->diffInSeconds());
2020-06-28 11:47:26 +00:00
}
2020-06-28 12:28:07 +00:00
$outage_summary = self::outageSummary($found_outages, $duration, $now);
2020-06-28 11:47:26 +00:00
$percent = Number::calculatePercent($duration - $outage_summary, $duration, $precision);
if ($percent < 0) {
Log::debug("Invalid availability calculation ($percent), normalizing to 0");
$percent = 0;
}
if ($percent > 100) {
Log::debug("Invalid availability calculation ($percent), normalizing to 100");
$percent = 100;
}
return $percent;
}
}