Name
sn_app_insights.MetricAggregateUtil
Description
No description available
Script
var MetricAggregateUtil = Class.create();
MetricAggregateUtil.prototype = {
initialize: function() {
this.SYS_METRIC = "sys_metric";
this.ECC_QUEUE_STATS_BY_ECC_AGENT = "ecc_queue_stats_by_ecc_agent";
this.SYS_CLUSTER_STATE = "sys_cluster_state";
},
/**
*
* @param tableNames An array of table names where metrics come from to generate aggregates
* from. For example, sys_cluster_state for nodes or ecc_queue_stats_by_ecc_agent for ECC agents
*
* @returns A JSON object that contains a key for each passed in table name. For each key, there is
* an array of JSON objects that represents a set a aggregates for a single metric subject.
* For example, if the input was an array of ['sys_cluster_state', 'ecc_queue_stats_by_ecc_agent']
* and the instance has two nodes and two ecc agents, the output would be the following
{
"ecc_queue_stats_by_ecc_agent": [
{
"sys_id": "64d965cdb70220107f5622988e11a9d5",
"metric_name": "current_count_processed_input_metric",
"display_value": "test2",
"average": "128.0",
"median": "126.0",
"u_95th_percentile": "239.0"
},
{
"sys_id": "d5d9a5cdb70220107f5622988e11a931",
"metric_name": "current_count_processed_input_metric",
"display_value": "test5",
"average": "133.7",
"median": "135.0",
"u_95th_percentile": "239.0"
}
],
"sys_cluster_state": [
{
"sys_id": "86ab5c916edd18fa9bd13445e217961c",
"metric_name": "events_processed",
"display_value": "192.168.1.5:paris",
"average": "15.7",
"median": "0",
"u_95th_percentile": "41.0"
},
{
"sys_id": "86ab5c916edd18fa9bd13445e217961c",
"metric_name": "event_logs",
"display_value": "192.168.1.5:paris",
"average": "15.7",
"median": "0",
"u_95th_percentile": "41.2"
}
]
}
*/
getAggregates: function(tableNames) {
// 1 day default time period
var minutesAgoStart = 1440;
var end = new GlideDateTime();
var start = new GlideDateTime(end);
start.addSeconds(-1 * minutesAgoStart * 60);
var tableAggregatesObj = {};
// for each table name
for (var j = 0; j < tableNames.length; j++) {
var tableName = tableNames[j];
// query records for specified table
var metricSubjects = new GlideRecord(tableName);
if (tableName == this.SYS_CLUSTER_STATE)
metricSubjects.addQuery("status", "online");
metricSubjects.query();
//metric names
var metricMetadataRecord = new GlideRecord(this.SYS_METRIC);
metricMetadataRecord.addQuery('name', tableName);
metricMetadataRecord.query();
var singleTableAggregatesArray = [];
// for each metric
while (metricMetadataRecord.next()) {
// get metric name
var metricName = metricMetadataRecord.getValue('element');
/**
* There is currently a bug in MetricBase that returns data at a 1 second period
* instead of the period configured in the retention policy. This then makes the
* data array returned by MetricBase filled with a significant number of NaNs. So,
* to workaround this, we resample the data so there's only 1 data point every 5 minutes,
* which is how often we generally retrieve data, so that we don't have to post-process
* the data to remove all the NaNs. Which greatly improves performance.
*/
var transformer = new sn_clotho.Transformer(metricSubjects);
transformer.metric(metricName).resample(Math.round(minutesAgoStart / 5));
// execute and return result for calculations
var metricBaseData = transformer.execute(start, end).toArray();
for (var i = 0; i < metricBaseData.length; i++) {
// get series
var dataArray = metricBaseData[i].getValues();
// remove NaN and null values
var validArray = dataArray.filter(function(value) {
return !(isNaN(value) || value == null);
});
// sort array ascending
validArray.sort(function(a, b) {
return a - b;
});
var ninetyFifthPerc = validArray[Math.floor(validArray.length * 0.95)];
var median = validArray[Math.floor(validArray.length * 0.5)];
var avg = validArray.reduce(function(acc, val) {
return acc + val;
}, 0) / validArray.length;
var displayValue = '';
var grSubject = new GlideRecord(metricBaseData[i].getTableName());
if (grSubject.get(metricBaseData[i].getSubject())) {
if (grSubject.getTableName() == this.ECC_QUEUE_STATS_BY_ECC_AGENT)
displayValue = grSubject.getValue("agent");
else
displayValue = grSubject.getDisplayValue();
}
singleTableAggregatesArray.push(
{
sys_id: grSubject.getUniqueValue(),
metric_name: metricName,
display_value: displayValue,
average: avg ? avg.toFixed(1).toString() : '0',
median: median ? median.toFixed(1).toString() : '0',
u_95th_percentile: ninetyFifthPerc ? ninetyFifthPerc.toFixed(1).toString() : '0',
}
);
}
}
tableAggregatesObj[tableName] = singleTableAggregatesArray;
}
return tableAggregatesObj;
},
reduceArray: function (metric, averageValues) {
// get series
var dataArray = metric.getValues();
// remove NaN and null values
var validArray = dataArray.filter(function(value) {
return !(isNaN(value) || value == null);
});
if (validArray.length == 0)
return validArray;
if(averageValues) {
var sum = validArray.reduce(function(acc, el) {
return acc + el;
}, 0);
var length = validArray.length;
validArray = [sum/length];
} else {
//Get the lowest number in the array
validArray = [validArray.reduce(function(acc, el) {
if (el < acc || isNaN(acc))
return el;
else
return acc;
}, NaN)];
}
return validArray;
},
getGrSubject: function(metricObj, id, tableName) {
var grSubject;
if (!metricObj.hasOwnProperty(id)) {
grSubject = new GlideRecord(tableName);
if (!grSubject.get(id))
return null;
metricObj[id] = {
gr: grSubject,
};
} else
grSubject = metricObj[id].gr;
return grSubject;
},
transformToMinDataArray: function(metricSubjects, metricName, start, end) {
var transformer = new sn_clotho.Transformer(metricSubjects);
transformer.metric(metricName).resample('MIN', 1);
return transformer.execute(start, end).toArray();
},
transformToAvgDataArray: function(metricSubjects, metricName, start, end) {
var transformer = new sn_clotho.Transformer(metricSubjects);
transformer.metric(metricName).resample('AVG', 1);
return transformer.execute(start, end).toArray();
},
type: 'MetricAggregateUtil'
};
Sys ID
642c6d01b74220107f5622988e11a929