feature: Save application metrics to db for alerting (#7828)

* feature: save application metrics to db for alerting
However, alerting will not work because ResolveGlues() is broken.
Can add workaround after state_translations alerting is merged

Does not update all applications yet, not sure if that should be done here or in another PR.

Introduces two handy functions dbDeleteOrphans() and array_by_column().  Will replace those in other locations after this is merged or separate them out if this is not merged.

* remove accidental inclusions

* Add db schema
This commit is contained in:
Tony Murray
2017-12-01 01:53:26 -06:00
committed by Neil Lathwood
parent edf26c1106
commit 4a03e7838e
7 changed files with 104 additions and 4 deletions

View File

@@ -1866,3 +1866,15 @@ function check_file_permissions($file, $mask)
return ($perms & $mask) === $mask;
}
/**
* Index an array by a column
*
* @param array $array
* @param string|int $column
* @return array
*/
function array_by_column($array, $column)
{
return array_combine(array_column($array, $column), $array);
}

View File

@@ -292,6 +292,33 @@ function dbDelete($table, $where = null, $parameters = array())
}//end dbDelete()
/**
* Delete orphaned entries from a table that no longer have a parent in parent_table
*
* @param string $parent_table
* @param string $child_table
* @param string $id_column
* @return bool|int
*/
function dbDeleteOrphans($parent_table, $child_table, $id_column)
{
global $database_link;
$time_start = microtime(true);
$sql = "DELETE C FROM `$child_table` C";
$sql .= " LEFT JOIN `$parent_table` P USING (`$id_column`)";
$sql .= " WHERE P.`$id_column` IS NULL";
$result = dbQuery($sql, array());
recordDbStatistic('delete', $time_start);
if ($result) {
return mysqli_affected_rows($database_link);
} else {
return false;
}
}
/*
* Fetches all of the rows (associatively) from the last performed query.
* Most other retrieval functions build off this

View File

@@ -105,6 +105,9 @@ if ($num > 0) {
}
}
// clean application_metrics
dbDeleteOrphans('applications', 'application_metrics', 'app_id');
echo PHP_EOL;
unset(

View File

@@ -11,7 +11,6 @@ if (!empty($agent_data['app'][$name])) {
$nginx = snmp_get($device, '.1.3.6.1.4.1.8072.1.3.2.3.1.2.5.110.103.105.110.120', '-Ovq');
}
$nginx = trim($nginx, '"');
update_application($app, $nginx);
echo ' nginx';
@@ -36,6 +35,7 @@ $fields = array(
$tags = compact('name', 'app_id', 'rrd_name', 'rrd_def');
data_update($device, 'app', $tags, $fields);
update_application($app, $nginx, '', $fields);
// Unset the variables we set here
unset($nginx, $active, $reading, $writing, $waiting, $req, $rrd_name, $rrd_def, $tags);

View File

@@ -574,9 +574,10 @@ function location_to_latlng($device)
*
* @param array $app app from the db, including app_id
* @param string $response This should be the full output
* @param string $current This is the current value we store in rrd for graphing
* @param string $status This is the current value for alerting
* @param array $metrics an array of additional metrics to store in the database for alerting
*/
function update_application($app, $response, $current = '')
function update_application($app, $response, $status = '', $metrics = array())
{
if (!is_numeric($app['app_id'])) {
d_echo('$app does not contain app_id, could not update');
@@ -585,7 +586,7 @@ function update_application($app, $response, $current = '')
$data = array(
'app_state' => 'UNKNOWN',
'app_status' => $current,
'app_status' => $status,
'timestamp' => array('NOW()'),
);
@@ -603,6 +604,53 @@ function update_application($app, $response, $current = '')
$data['app_state_prev'] = $app['app_state'];
}
dbUpdate($data, 'applications', '`app_id` = ?', array($app['app_id']));
// update metrics
if (!empty($metrics)) {
$db_metrics = dbFetchRows('SELECT * FROM `application_metrics` WHERE app_id=?', array($app['app_id']));
$db_metrics = array_by_column($db_metrics, 'metric');
echo ': ';
foreach ($metrics as $metric_name => $value) {
if (!isset($db_metrics[$metric_name])) {
// insert new metric
dbInsert(
array(
'app_id' => $app['app_id'],
'metric' => $metric_name,
'value' => $value,
),
'application_metrics'
);
echo '+';
} elseif ($value != $db_metrics[$metric_name]['value']) {
dbUpdate(
array(
'value' => $value,
'value_prev' => $db_metrics[$metric_name]['value'],
),
'application_metrics',
'app_id=? && metric=?',
array($app['app_id'], $metric_name)
);
echo 'U';
} else {
echo '.';
}
unset($db_metrics[$metric_name]);
}
// remove no longer existing metrics (generally should not happen
foreach ($db_metrics as $db_metric) {
dbDelete(
'application_metrics',
'app_id=? && metric=?',
array($app['app_id'], $db_metric['metric'])
);
echo '-';
}
}
}
function convert_to_celsius($value)

View File

@@ -133,6 +133,14 @@ applications:
Indexes:
PRIMARY: { Name: PRIMARY, Columns: [app_id], Unique: true, Type: BTREE }
unique_index: { Name: unique_index, Columns: [device_id, app_type], Unique: true, Type: BTREE }
application_metrics:
Columns:
- { Field: app_id, Type: int(11), 'Null': false, Extra: '' }
- { Field: metric, Type: varchar(18), 'Null': false, Extra: '' }
- { Field: value, Type: int(11), 'Null': true, Extra: '' }
- { Field: value_prev, Type: int(11), 'Null': true, Extra: '' }
Indexes:
application_metrics_app_id_metric_uindex: { Name: application_metrics_app_id_metric_uindex, Columns: [app_id, metric], Unique: true, Type: BTREE }
authlog:
Columns:
- { Field: id, Type: int(11), 'Null': false, Extra: auto_increment }

2
sql-schema/219.sql Normal file
View File

@@ -0,0 +1,2 @@
CREATE TABLE application_metrics (app_id INT(11) NOT NULL, metric VARCHAR(18) NOT NULL, value INT(11), value_prev INT(11));
CREATE UNIQUE INDEX application_metrics_app_id_metric_uindex ON application_metrics (app_id, metric);