mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Added aggregate config option to Billing 95th percentile calculations (#10202)
* Added configuration options to aggregate input and output bits before making 95th percentile billing calculations * Changed aggregate to per-bill instead of global. Added config options for making aggregate the default selected option. Refactored out mres() calls in touched files. Changed to Config::get where appropriate. * Fixed documentation typo * Fixed scope of aggregate default config option to be under billing
This commit is contained in:
@ -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'];
|
||||
|
@ -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
|
||||
|
@ -1,19 +1,17 @@
|
||||
<?php
|
||||
|
||||
use LibreNMS\Config;
|
||||
|
||||
|
||||
function format_bytes_billing($value)
|
||||
{
|
||||
global $config;
|
||||
|
||||
return format_number($value, $config['billing']['base']).'B';
|
||||
return format_number($value, Config::get('billing.base')).'B';
|
||||
}//end format_bytes_billing()
|
||||
|
||||
|
||||
function format_bytes_billing_short($value)
|
||||
{
|
||||
global $config;
|
||||
|
||||
return format_number($value, $config['billing']['base'], 2, 3);
|
||||
return format_number($value, Config::get('billing.base'), 2, 3);
|
||||
}//end format_bytes_billing_short()
|
||||
|
||||
|
||||
@ -75,10 +73,8 @@ function getPredictedUsage($bill_day, $cur_used)
|
||||
|
||||
function getValue($host, $port, $id, $inout)
|
||||
{
|
||||
global $config;
|
||||
|
||||
$oid = 'IF-MIB::ifHC'.$inout.'Octets.'.$id;
|
||||
$device = dbFetchRow("SELECT * from `devices` WHERE `hostname` = '".mres($host)."' LIMIT 1");
|
||||
$device = dbFetchRow("SELECT * from `devices` WHERE `hostname` = ? LIMIT 1", array($host));
|
||||
$value = snmp_get($device, $oid, '-Oqv');
|
||||
|
||||
if (!is_numeric($value)) {
|
||||
@ -123,41 +119,55 @@ function getLastMeasurement($bill_id)
|
||||
return ($return);
|
||||
}//end getLastMeasurement()
|
||||
|
||||
|
||||
function get95thin($bill_id, $datefrom, $dateto)
|
||||
function get95thagg($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 (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()
|
||||
|
||||
|
@ -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()) {
|
||||
|
||||
<?php
|
||||
|
||||
if (Config::get('billing.95th_default_agg') == 1) {
|
||||
$bill_data['dir_95th'] = 'agg';
|
||||
} else {
|
||||
$bill_data['dir_95th'] = 'in';
|
||||
}
|
||||
$bill_data['bill_type'] = 'cdr';
|
||||
$quota = array('select_gb' => ' selected');
|
||||
$cdr = array('select_mbps' => ' selected');
|
||||
|
@ -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'],
|
||||
|
@ -39,6 +39,25 @@
|
||||
<option <?php echo $cdr['select_gbps'] ?> value="Gbps">Gigabits per second (Gbps)</option>
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-4 control-label" for="dir_95th">95th Calculation</label>
|
||||
<div class="col-sm-8">
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="dir_95th" id="dir_95th_inout" value="in"
|
||||
<?php
|
||||
if ($bill_data['dir_95th'] == 'in' || $bill_data['dir_95th'] == 'out') {
|
||||
echo "checked";
|
||||
}
|
||||
?> /> Max In/Out
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="dir_95th" id="dir_95th_agg" value="agg"
|
||||
<?php
|
||||
if ($bill_data['dir_95th'] == 'agg') {
|
||||
echo "checked";
|
||||
}
|
||||
?> /> Aggregate
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="quotaDiv">
|
||||
<label class="col-sm-4 control-label" for="bill_quota">Quota</label>
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user