diff --git a/billing-calculate.php b/billing-calculate.php index ddf075bae0..80c4ef45ea 100755 --- a/billing-calculate.php +++ b/billing-calculate.php @@ -39,8 +39,11 @@ foreach (dbFetchRows('SELECT * FROM `bills` ORDER BY `bill_id`') as $bill) { $date_updated = str_replace('-', '', str_replace(':', '', str_replace(' ', '', $check['updated']))); + // Send the current dir_95th to the getRates function so it knows to aggregate or return the max in/out value and highest direction + $dir_95th = $bill['dir_95th']; + if ($period > 0 && $dateto > $date_updated) { - $rate_data = getRates($bill['bill_id'], $datefrom, $dateto); + $rate_data = getRates($bill['bill_id'], $datefrom, $dateto, $dir_95th); $rate_95th = $rate_data['rate_95th']; $dir_95th = $rate_data['dir_95th']; $total_data = $rate_data['total_data']; diff --git a/doc/Extensions/Billing-Module.md b/doc/Extensions/Billing-Module.md index 1e24047793..ef7b8c135c 100644 --- a/doc/Extensions/Billing-Module.md +++ b/doc/Extensions/Billing-Module.md @@ -23,7 +23,7 @@ Edit `/etc/cron.d/librenms` and add the following: Create billing graphs as required. -## Options +## Data Retention Billing data is stored in the MySQL database, and you may wish to purge the detailed stats for old data (per-month totals will always be kept). To enable this, add the @@ -36,3 +36,21 @@ $config['billing_data_purge'] = 12; // Number of months to retain Data for the last complete billing cycle will always be retained - only data older than this by the configured number of months will be removed. This task is performed in the daily cleanup tasks. + +## 95th Percentile Calculation + +For 95th Percentile billing, the default behavior is to use the highest of the input +or output 95th Percentile calculation. + +To instead use the combined total of inout + output to derive the 95th percentile, +This can be changed on a per bill basis by setting 95th Calculation to "Aggregate". + +To change the default option to Aggregate, +add the following the `config.php`: + +```php +$config['billing']['95th_default_agg'] = 1; // Set aggregate 95th as default +``` + +This configuration setting is cosmetic and only changes the default selected option +when adding a new bill diff --git a/includes/billing.php b/includes/billing.php index 6066326ae6..56ac500084 100644 --- a/includes/billing.php +++ b/includes/billing.php @@ -1,19 +1,17 @@ '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."'"; - $measurements = dbFetchCell($mq_sql); + $mq_sql = "SELECT count(delta) FROM bill_data WHERE bill_id = ?"; + $mq_sql .= " AND timestamp > ? AND timestamp <= ?"; + $measurements = dbFetchCell($mq_sql, array($bill_id, $datefrom, $dateto)); $measurement_95th = (round(($measurements / 100 * 95)) - 1); - $q_95_sql = "SELECT (in_delta / period * 8) AS rate FROM bill_data WHERE bill_id = '".mres($bill_id)."'"; - $q_95_sql .= " AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."' ORDER BY rate ASC"; - $a_95th = dbFetchColumn($q_95_sql); + $q_95_sql = "SELECT (delta / period * 8) AS rate FROM bill_data WHERE bill_id = ?"; + $q_95_sql .= " AND timestamp > ? AND timestamp <= ? ORDER BY rate ASC"; + $a_95th = dbFetchColumn($q_95_sql, array($bill_id, $datefrom, $dateto)); $m_95th = $a_95th[$measurement_95th]; return (round($m_95th, 2)); -}//end get95thin() +}//end get95thagg() + + +function get95thIn($bill_id, $datefrom, $dateto) +{ + $mq_sql = "SELECT count(delta) FROM bill_data WHERE bill_id = ?"; + $mq_sql .= " AND timestamp > ? AND timestamp <= ?"; + $measurements = dbFetchCell($mq_sql, array($bill_id, $datefrom, $dateto)); + $measurement_95th = (round(($measurements / 100 * 95)) - 1); + + $q_95_sql = "SELECT (in_delta / period * 8) AS rate FROM bill_data WHERE bill_id = ?"; + $q_95_sql .= " AND timestamp > ? AND timestamp <= ? ORDER BY rate ASC"; + $a_95th = dbFetchColumn($q_95_sql, array($bill_id, $datefrom, $dateto)); + $m_95th = $a_95th[$measurement_95th]; + + return (round($m_95th, 2)); +}//end get95thIn() function get95thout($bill_id, $datefrom, $dateto) { - $mq_sql = "SELECT count(delta) FROM bill_data WHERE bill_id = '".mres($bill_id)."'"; - $mq_sql .= " AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."'"; - $measurements = dbFetchCell($mq_sql); + $mq_sql = "SELECT count(delta) FROM bill_data WHERE bill_id = ?"; + $mq_sql .= " AND timestamp > ? AND timestamp <= ?"; + $measurements = dbFetchCell($mq_sql, array($bill_id, $datefrom, $dateto)); $measurement_95th = (round(($measurements / 100 * 95)) - 1); - $q_95_sql = "SELECT (out_delta / period * 8) AS rate FROM bill_data WHERE bill_id = '".mres($bill_id)."'"; - $q_95_sql .= " AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."' ORDER BY rate ASC"; - - $a_95th = dbFetchColumn($q_95_sql); - $m_95th = $a_95th[$measurement_95th]; + $q_95_sql = "SELECT (out_delta / period * 8) AS rate FROM bill_data WHERE bill_id = ?"; + $q_95_sql .= " AND timestamp > ? AND timestamp <= ? ORDER BY rate ASC"; + $a_95th = dbFetchColumn($q_95_sql, array($bill_id, $datefrom, $dateto)); + $m_95th = $a_95th[$measurement_95th]; return (round($m_95th, 2)); }//end get95thout() -function getRates($bill_id, $datefrom, $dateto) +function getRates($bill_id, $datefrom, $dateto, $dir_95th) { $data = []; @@ -168,14 +178,19 @@ function getRates($bill_id, $datefrom, $dateto) $ptot = $sum_data['period']; $data['rate_95th_in'] = get95thIn($bill_id, $datefrom, $dateto); - $data['rate_95th_out'] = get95thOut($bill_id, $datefrom, $dateto); + $data['rate_95th_out'] = get95thout($bill_id, $datefrom, $dateto); - if ($data['rate_95th_out'] > $data['rate_95th_in']) { - $data['rate_95th'] = $data['rate_95th_out']; - $data['dir_95th'] = 'out'; + if ($dir_95th == 'agg') { + $data['rate_95th'] = get95thagg($bill_id, $datefrom, $dateto); + $data['dir_95th'] = 'agg'; } else { - $data['rate_95th'] = $data['rate_95th_in']; - $data['dir_95th'] = 'in'; + if ($data['rate_95th_out'] > $data['rate_95th_in']) { + $data['rate_95th'] = $data['rate_95th_out']; + $data['dir_95th'] = 'out'; + } else { + $data['rate_95th'] = $data['rate_95th_in']; + $data['dir_95th'] = 'in'; + } } $data['total_data'] = $mtot; @@ -192,21 +207,21 @@ function getRates($bill_id, $datefrom, $dateto) function getTotal($bill_id, $datefrom, $dateto) { - $mtot = dbFetchCell("SELECT SUM(delta) FROM bill_data WHERE bill_id = '".mres($bill_id)."' AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."'"); + $mtot = dbFetchCell("SELECT SUM(delta) FROM bill_data WHERE bill_id = ? AND timestamp > ? AND timestamp <= ?", array($bill_id, $datefrom, $dateto)); return ($mtot); }//end getTotal() function getSum($bill_id, $datefrom, $dateto) { - $sum = dbFetchRow("SELECT SUM(period) as period, SUM(delta) as total, SUM(in_delta) as inbound, SUM(out_delta) as outbound FROM bill_data WHERE bill_id = '".mres($bill_id)."' AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."'"); + $sum = dbFetchRow("SELECT SUM(period) as period, SUM(delta) as total, SUM(in_delta) as inbound, SUM(out_delta) as outbound FROM bill_data WHERE bill_id = ? AND timestamp > ? AND timestamp <= ?", array($bill_id, $datefrom, $dateto)); return ($sum); }//end getSum() function getPeriod($bill_id, $datefrom, $dateto) { - $ptot = dbFetchCell("SELECT SUM(period) FROM bill_data WHERE bill_id = '".mres($bill_id)."' AND timestamp > '".mres($datefrom)."' AND timestamp <= '".mres($dateto)."'"); + $ptot = dbFetchCell("SELECT SUM(period) FROM bill_data WHERE bill_id = ? AND timestamp > ? AND timestamp <= ?", array($bill_id, $datefrom, $dateto)); return ($ptot); }//end getPeriod() diff --git a/includes/html/modal/new_bill.inc.php b/includes/html/modal/new_bill.inc.php index 4a76ced989..190392fb41 100644 --- a/includes/html/modal/new_bill.inc.php +++ b/includes/html/modal/new_bill.inc.php @@ -12,6 +12,7 @@ */ use LibreNMS\Authentication\LegacyAuth; +use LibreNMS\Config; if (LegacyAuth::user()->hasGlobalAdmin()) { require 'includes/html/javascript-interfacepicker.inc.php'; @@ -73,6 +74,11 @@ if (LegacyAuth::user()->hasGlobalAdmin()) { ' selected'); $cdr = array('select_mbps' => ' selected'); diff --git a/includes/html/pages/bill/actions.inc.php b/includes/html/pages/bill/actions.inc.php index b2824560bf..e1f5a597a0 100644 --- a/includes/html/pages/bill/actions.inc.php +++ b/includes/html/pages/bill/actions.inc.php @@ -84,6 +84,7 @@ if ($_POST['action'] == 'update_bill') { 'bill_quota' => (string)$bill_quota, 'bill_cdr' => (string)$bill_cdr, 'bill_type' => $_POST['bill_type'], + 'dir_95th' => $_POST['dir_95th'], 'bill_custid' => $_POST['bill_custid'], 'bill_ref' => $_POST['bill_ref'], 'bill_notes' => $_POST['bill_notes'], diff --git a/includes/html/pages/bill/addoreditbill.inc.php b/includes/html/pages/bill/addoreditbill.inc.php index e255555557..c1d9b91638 100644 --- a/includes/html/pages/bill/addoreditbill.inc.php +++ b/includes/html/pages/bill/addoreditbill.inc.php @@ -39,6 +39,25 @@ + +
+ + +
diff --git a/includes/html/pages/bills.inc.php b/includes/html/pages/bills.inc.php index 46b0d820fe..84398ad839 100644 --- a/includes/html/pages/bills.inc.php +++ b/includes/html/pages/bills.inc.php @@ -64,7 +64,7 @@ if ($_POST['addbill'] == 'yes') { 'rate_95th_in' => 0, 'rate_95th_out' => 0, 'rate_95th' => 0, - 'dir_95th' => 'in', + 'dir_95th' => $_POST['dir_95th'], 'total_data' => 0, 'total_data_in' => 0, 'total_data_out' => 0,