From 34163703fbb39f629c6852b0e33c741ccd95a603 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Wed, 24 Aug 2022 14:01:54 -0500 Subject: [PATCH] Percentage calculation helper (#14235) * Percentage calculation helper Helper function to prevent divide by zero mistakes Replace all percent calculations * style --- LibreNMS/Device/Availability.php | 3 ++- LibreNMS/Modules/PrinterSupplies.php | 3 ++- LibreNMS/OS/Epmp.php | 5 +++-- LibreNMS/Util/Number.php | 17 ++++++++++++++++ billing-calculate.php | 4 ++-- includes/html/api_functions.inc.php | 19 +++++++++--------- includes/html/pages/bill.inc.php | 12 ++++++----- includes/html/pages/bill/transfer.inc.php | 12 ++++++----- .../pages/device/overview/mempools.inc.php | 2 +- .../html/pages/device/routing/mpls.inc.php | 4 +++- includes/html/pages/routing/mpls.inc.php | 4 +++- includes/html/print-interface.inc.php | 4 ++-- includes/html/table/bills.inc.php | 20 ++++++++++--------- includes/polling/ports.inc.php | 4 ++-- includes/polling/storage.inc.php | 8 ++------ .../polling/wireless/cambium-epmp.inc.php | 6 ++++-- 16 files changed, 78 insertions(+), 49 deletions(-) diff --git a/LibreNMS/Device/Availability.php b/LibreNMS/Device/Availability.php index 2017615b5b..018bc09809 100644 --- a/LibreNMS/Device/Availability.php +++ b/LibreNMS/Device/Availability.php @@ -26,6 +26,7 @@ namespace LibreNMS\Device; use App\Models\DeviceOutage; +use LibreNMS\Util\Number; class Availability { @@ -126,6 +127,6 @@ class Availability $outage_summary = self::outageSummary($found_outages, $duration, $now); - return round(100 * ($duration - $outage_summary) / $duration, $precision); + return Number::calculatePercent($duration - $outage_summary, $duration, $precision); } } diff --git a/LibreNMS/Modules/PrinterSupplies.php b/LibreNMS/Modules/PrinterSupplies.php index 29ac505127..07b5065c27 100644 --- a/LibreNMS/Modules/PrinterSupplies.php +++ b/LibreNMS/Modules/PrinterSupplies.php @@ -29,6 +29,7 @@ use LibreNMS\Enum\Alert; use LibreNMS\Interfaces\Module; use LibreNMS\OS; use LibreNMS\RRD\RrdDefinition; +use LibreNMS\Util\Number; use Log; class PrinterSupplies implements Module @@ -276,7 +277,7 @@ class PrinterSupplies implements Module } } - return round($raw_value / $capacity * 100); + return Number::calculatePercent($raw_value, $capacity, 0); } /** diff --git a/LibreNMS/OS/Epmp.php b/LibreNMS/OS/Epmp.php index 14c26c930e..f63b733cca 100644 --- a/LibreNMS/OS/Epmp.php +++ b/LibreNMS/OS/Epmp.php @@ -34,6 +34,7 @@ use LibreNMS\Interfaces\Discovery\Sensors\WirelessSnrDiscovery; use LibreNMS\Interfaces\Polling\OSPolling; use LibreNMS\OS; use LibreNMS\RRD\RrdDefinition; +use LibreNMS\Util\Number; class Epmp extends OS implements OSPolling, @@ -121,8 +122,8 @@ class Epmp extends OS implements $dlWLanTotalUsedFrameTimePerSecond = $multi_get_array[0]['CAMBIUM-PMP80211-MIB::dlWLanTotalUsedFrameTimePerSecond'] ?? null; if (is_numeric($ulWLanTotalAvailableFrameTimePerSecond) && is_numeric($ulWLanTotalUsedFrameTimePerSecond) && $ulWLanTotalAvailableFrameTimePerSecond && $ulWLanTotalUsedFrameTimePerSecond) { - $ulWlanFrameUtilization = round(($ulWLanTotalUsedFrameTimePerSecond / $ulWLanTotalAvailableFrameTimePerSecond) * 100, 2); - $dlWlanFrameUtilization = round(($dlWLanTotalUsedFrameTimePerSecond / $dlWLanTotalAvailableFrameTimePerSecond) * 100, 2); + $ulWlanFrameUtilization = Number::calculatePercent($ulWLanTotalUsedFrameTimePerSecond, $ulWLanTotalAvailableFrameTimePerSecond); + $dlWlanFrameUtilization = Number::calculatePercent($dlWLanTotalUsedFrameTimePerSecond, $dlWLanTotalAvailableFrameTimePerSecond); d_echo($dlWlanFrameUtilization); d_echo($ulWlanFrameUtilization); $rrd_def = RrdDefinition::make() diff --git a/LibreNMS/Util/Number.php b/LibreNMS/Util/Number.php index 7957537440..04065aed80 100644 --- a/LibreNMS/Util/Number.php +++ b/LibreNMS/Util/Number.php @@ -108,4 +108,21 @@ class Number return $float == $int ? $int : $float; } + + /** + * Calculate a percent, but make sure to not divide by zero. In that case, return 0. + * + * @param int|float $part + * @param int|float $total + * @param int $precision + * @return float + */ + public static function calculatePercent($part, $total, int $precision = 2): float + { + if ($total == 0) { + return 0; + } + + return round($part / $total * 100, $precision); + } } diff --git a/billing-calculate.php b/billing-calculate.php index 3cd4c05785..dd6f024d0d 100755 --- a/billing-calculate.php +++ b/billing-calculate.php @@ -57,7 +57,7 @@ foreach (dbFetchRows('SELECT * FROM `bills` ORDER BY `bill_id`') as $bill) { $used_text = Number::formatSi($used, 2, 3, 'bps'); $overuse = ($used - $allowed); $overuse = (($overuse <= 0) ? '0' : $overuse); - $percent = round((($rate_data['rate_95th'] / $bill['bill_cdr']) * 100), 2); + $percent = Number::calculatePercent($rate_data['rate_95th'], $bill['bill_cdr']); } elseif ($bill['bill_type'] == 'quota') { $type = 'Quota'; $allowed = $bill['bill_quota']; @@ -66,7 +66,7 @@ foreach (dbFetchRows('SELECT * FROM `bills` ORDER BY `bill_id`') as $bill) { $used_text = format_bytes_billing($used); $overuse = ($used - $allowed); $overuse = (($overuse <= 0) ? '0' : $overuse); - $percent = round((($rate_data['total_data'] / $bill['bill_quota']) * 100), 2); + $percent = Number::calculatePercent($rate_data['total_data'], $bill['bill_quota']); } echo strftime('%x @ %X', strtotime($datefrom)) . ' to ' . strftime('%x @ %X', strtotime($dateto)) . ' ' . str_pad($type, 8) . ' ' . str_pad($allowed_text, 10) . ' ' . str_pad($used_text, 10) . ' ' . $percent . '%'; diff --git a/includes/html/api_functions.inc.php b/includes/html/api_functions.inc.php index 2e6e78265e..851e2f99f9 100644 --- a/includes/html/api_functions.inc.php +++ b/includes/html/api_functions.inc.php @@ -37,6 +37,7 @@ use LibreNMS\Data\Store\Datastore; use LibreNMS\Exceptions\InvalidIpException; use LibreNMS\Util\IP; use LibreNMS\Util\IPv4; +use LibreNMS\Util\Number; use LibreNMS\Util\Rewrite; function api_success($result, $result_name, $message = null, $code = 200, $count = null, $extra = null) @@ -191,12 +192,12 @@ function get_port_stats_by_port_hostname(Illuminate\Http\Request $request) return check_port_permission($port['port_id'], $device_id, function () use ($request, $port) { $in_rate = $port['ifInOctets_rate'] * 8; $out_rate = $port['ifOutOctets_rate'] * 8; - $port['in_rate'] = \LibreNMS\Util\Number::formatSi($in_rate, 2, 3, 'bps'); - $port['out_rate'] = \LibreNMS\Util\Number::formatSi($out_rate, 2, 3, 'bps'); + $port['in_rate'] = Number::formatSi($in_rate, 2, 3, 'bps'); + $port['out_rate'] = Number::formatSi($out_rate, 2, 3, 'bps'); $port['in_perc'] = number_format($in_rate / $port['ifSpeed'] * 100, 2, '.', ''); $port['out_perc'] = number_format($out_rate / $port['ifSpeed'] * 100, 2, '.', ''); - $port['in_pps'] = \LibreNMS\Util\Number::formatBi($port['ifInUcastPkts_rate'], 2, 3, ''); - $port['out_pps'] = \LibreNMS\Util\Number::formatBi($port['ifOutUcastPkts_rate'], 2, 3, ''); + $port['in_pps'] = Number::formatBi($port['ifInUcastPkts_rate'], 2, 3, ''); + $port['out_pps'] = Number::formatBi($port['ifOutUcastPkts_rate'], 2, 3, ''); //only return requested columns if ($request->has('columns')) { @@ -1583,20 +1584,20 @@ function list_bills(Illuminate\Http\Request $request) $overuse = ''; if (strtolower($bill['bill_type']) == 'cdr') { - $allowed = \LibreNMS\Util\Number::formatSi($bill['bill_cdr'], 2, 3, '') . 'bps'; - $used = \LibreNMS\Util\Number::formatSi($rate_data['rate_95th'], 2, 3, '') . 'bps'; + $allowed = Number::formatSi($bill['bill_cdr'], 2, 3, '') . 'bps'; + $used = Number::formatSi($rate_data['rate_95th'], 2, 3, '') . 'bps'; if ($bill['bill_cdr'] > 0) { - $percent = round(($rate_data['rate_95th'] / $bill['bill_cdr']) * 100, 2); + $percent = Number::calculatePercent($rate_data['rate_95th'], $bill['bill_cdr']); } else { $percent = '-'; } $overuse = $rate_data['rate_95th'] - $bill['bill_cdr']; - $overuse = (($overuse <= 0) ? '-' : \LibreNMS\Util\Number::formatSi($overuse, 2, 3, '')); + $overuse = (($overuse <= 0) ? '-' : Number::formatSi($overuse, 2, 3, '')); } elseif (strtolower($bill['bill_type']) == 'quota') { $allowed = format_bytes_billing($bill['bill_quota']); $used = format_bytes_billing($rate_data['total_data']); if ($bill['bill_quota'] > 0) { - $percent = round(($rate_data['total_data'] / ($bill['bill_quota'])) * 100, 2); + $percent = Number::calculatePercent($rate_data['total_data'], $bill['bill_quota']); } else { $percent = '-'; } diff --git a/includes/html/pages/bill.inc.php b/includes/html/pages/bill.inc.php index ad0af5ad60..b168249068 100644 --- a/includes/html/pages/bill.inc.php +++ b/includes/html/pages/bill.inc.php @@ -1,5 +1,7 @@ hasGlobalAdmin()) { @@ -158,14 +160,14 @@ if (bill_permitted($bill_id)) { of - - Average rate + - Average rate @@ -180,11 +182,11 @@ if (bill_permitted($bill_id)) { $unit = 'kbps'; $cdr = $bill_data['bill_cdr']; $rate_95th = round($rate_95th, 2); - $percent = round((($rate_95th) / $cdr * 100), 2); + $percent = Number::calculatePercent($rate_95th, $cdr); $background = \LibreNMS\Util\Color::percentage($percent, null); $type = '&95th=yes'; ?> - of (95th%ile) + of (95th%ile) @@ -193,7 +195,7 @@ if (bill_permitted($bill_id)) { + echo 'Predicted usage: ' . Number::formatSi(getPredictedUsage($bill_data['bill_day'], $bill_data['rate_95th']), 2, 3, '') . 'bps'; ?> isNotEmpty()) { $buffers = $mempools->firstWhere('mempool_class', '=', 'buffers'); $cached = $mempools->firstWhere('mempool_class', '=', 'cached'); - $available_used_all = $mempool->mempool_total ? round(($mempool->mempool_used + $buffers->mempool_used + $cached->mempool_used) / $mempool->mempool_total * 100) : 0; + $available_used_all = Number::calculatePercent($mempool->mempool_used + $buffers->mempool_used + $cached->mempool_used, $mempool->mempool_total, 0); } $total = Number::formatBi($mempool->mempool_total); diff --git a/includes/html/pages/device/routing/mpls.inc.php b/includes/html/pages/device/routing/mpls.inc.php index 211c084f82..5688f6f6c8 100644 --- a/includes/html/pages/device/routing/mpls.inc.php +++ b/includes/html/pages/device/routing/mpls.inc.php @@ -1,5 +1,7 @@ " . Number::formatSi($port['in_rate'], 2, 3, 'bps') . "
" . Number::formatSi($port['out_rate'], 2, 3, 'bps') . "
" . Number::formatBi($port['ifInUcastPkts_rate'], 2, 3, 'pps') . "

diff --git a/includes/html/table/bills.inc.php b/includes/html/table/bills.inc.php index 3ece884267..e51e4147de 100644 --- a/includes/html/table/bills.inc.php +++ b/includes/html/table/bills.inc.php @@ -1,6 +1,8 @@ 'bill', 'bill_id' => $bill['bill_id']]); - $used95th = \LibreNMS\Util\Number::formatSi($bill['rate_95th'], 2, 3, '') . 'bps'; + $used95th = Number::formatSi($bill['rate_95th'], 2, 3, '') . 'bps'; $notes = $bill['bill_notes']; if ($prev) { @@ -102,15 +104,15 @@ foreach (dbFetchRows($sql, $param) as $bill) { if (strtolower($bill['bill_type']) == 'cdr') { $type = 'CDR'; - $allowed = \LibreNMS\Util\Number::formatSi($bill['bill_allowed'], 2, 3, '') . 'bps'; - $in = \LibreNMS\Util\Number::formatSi($bill['rate_95th_in'], 2, 3, '') . 'bps'; - $out = \LibreNMS\Util\Number::formatSi($bill['rate_95th_out'], 2, 3, '') . 'bps'; + $allowed = Number::formatSi($bill['bill_allowed'], 2, 3, '') . 'bps'; + $in = Number::formatSi($bill['rate_95th_in'], 2, 3, '') . 'bps'; + $out = Number::formatSi($bill['rate_95th_out'], 2, 3, '') . 'bps'; if (! $prev) { - $percent = round((($bill['rate_95th'] / $bill['bill_allowed']) * 100), 2); + $percent = Number::calculatePercent($bill['rate_95th'], $bill['bill_allowed']); $overuse = ($bill['rate_95th'] - $bill['bill_allowed']); } - $overuse_formatted = \LibreNMS\Util\Number::formatSi($overuse, 2, 3, '') . 'bps'; + $overuse_formatted = Number::formatSi($overuse, 2, 3, '') . 'bps'; $used = $rate_95th; $tmp_used = $bill['rate_95th']; $rate_95th = "$rate_95th"; @@ -125,7 +127,7 @@ foreach (dbFetchRows($sql, $param) as $bill) { $out = format_bytes_billing($bill['total_data_out']); } if (! $prev) { - $percent = round((($bill['total_data'] / ($bill['bill_allowed'])) * 100), 2); + $percent = Number::calculatePercent($bill['total_data'], $bill['bill_allowed']); $overuse = ($bill['total_data'] - $bill['bill_allowed']); } @@ -150,7 +152,7 @@ foreach (dbFetchRows($sql, $param) as $bill) { "'> Edit "; } if (strtolower($bill['bill_type']) == 'cdr') { - $predicted = \LibreNMS\Util\Number::formatSi(getPredictedUsage($bill['bill_day'], $tmp_used), 2, 3, '') . 'bps'; + $predicted = Number::formatSi(getPredictedUsage($bill['bill_day'], $tmp_used), 2, 3, '') . 'bps'; } elseif (strtolower($bill['bill_type']) == 'quota') { $predicted = format_bytes_billing(getPredictedUsage($bill['bill_day'], $tmp_used)); } diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index 7560af0a3c..920ca5cef1 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -821,8 +821,8 @@ foreach ($ports as $port) { // If we have a valid ifSpeed we should populate the stats for checking if (is_numeric($this_port['ifSpeed']) && $this_port['ifSpeed'] > 0) { - $port['stats']['ifInBits_perc'] = round(($port['stats']['ifInBits_rate'] / $this_port['ifSpeed'] * 100)); - $port['stats']['ifOutBits_perc'] = round(($port['stats']['ifOutBits_rate'] / $this_port['ifSpeed'] * 100)); + $port['stats']['ifInBits_perc'] = Number::calculatePercent($port['stats']['ifInBits_rate'], $this_port['ifSpeed'], 0); + $port['stats']['ifOutBits_perc'] = Number::calculatePercent($port['stats']['ifOutBits_rate'], $this_port['ifSpeed'], 0); } echo 'bps(' . Number::formatSi($port['stats']['ifInBits_rate'], 2, 3, 'bps') . '/' . Number::formatSi($port['stats']['ifOutBits_rate'], 2, 3, 'bps') . ')'; diff --git a/includes/polling/storage.inc.php b/includes/polling/storage.inc.php index e6ad6d1169..03d76b60b1 100644 --- a/includes/polling/storage.inc.php +++ b/includes/polling/storage.inc.php @@ -1,6 +1,7 @@