Name
sn_app_insights.MetricConditionUtils
Description
No description available
Script
var MetricConditionUtils = Class.create();
MetricConditionUtils.prototype = {
initialize: function() {
this.JOB_ID = '8eccc01723612010fb0c949e27bf6594';
},
evaluateInnerCondition: function (innerCondition) {
var results = {};
//Using the example above, an inner condition would be [[a], [b, c]] or [[d], [e]]
//All items in the inner condition must pass for the innerCondition to pass since it is an AND
for (var i = 0; i < innerCondition.length; ++i) {
var childCondition = innerCondition[i];
//Again using the example, one childCondition might be [b, c]
//Only one item in the child condition needs to pass, because it is an OR
for (var j = 0; j < childCondition.length; ++j) {
var trigger = new GlideRecord('sn_app_insights_metric_trigger');
if (trigger.get(childCondition[j])) {
var result = this._evaluateTrigger(trigger);
if (result.evaluation) {
result.metric_id = trigger.getValue('metric');
delete result.evaluation;
//Assign to dictionary to prevent duplicate logs
results[result.metric_id] = result;
break;
}
}
}
if (Object.keys(results).length === 0)
return { evaluation: false };
}
//Put all log objects into an array for easy retrieval
var finalResult = [];
for (var key in results)
finalResult.push(results[key]);
return { result: true, records: finalResult };
},
_evaluateTrigger: function (triggerGr) {
var job = new GlideRecord('sysauto_script');
job.get(this.JOB_ID);
var end = new GlideDateTime();
var start = new GlideDateTime();
var sustained = new GlideDateTime(triggerGr.getValue('sustained_for'));
var period = new GlideDateTime(job.getValue('run_period'));
var tableGr = new GlideRecord(triggerGr.metric.name);
tableGr.query();
var transformer = new sn_clotho.Transformer(tableGr);
var resultArray;
var operation = triggerGr.getValue('operation');
if (sustained.getNumericValue() == 0) {
//If sustained_for is 0, no need for resampling. Get every point of data since the last run period
transformer.metric(triggerGr.metric.element);
start.subtract(period.getNumericValue());
resultArray = transformer.execute(start, end).toArray();
} else {
/*
Determine the range of sampling.
Take the larger of the script's run period and the metric's "sustained for" value.
*/
if (period.after(sustained)) {
var periodMillis = period.getNumericValue();
var sustainedMillis = sustained.getNumericValue();
/*
If sustained_for does not fit neatly into the run period of the job
(e.g. 7 minute sustained for, 10 minute run period)
Lengthen the range of data to pull to ensure an even split (instead of 10 minutes, make it 14)
*/
if (periodMillis % sustainedMillis != 0) {
var calculatedStart = (periodMillis / sustainedMillis + 1) * sustainedMillis;
start.subtract(calculatedStart);
} else
start.subtract(periodMillis);
} else
start.subtract(sustained.getNumericValue());
var operand = '';
if (operation.startsWith('<'))
operand = 'MAX';
else
operand = 'MIN';
transformer
.metric(triggerGr.metric.element)
.resample(
operand,
new GlideDateTime(triggerGr.getValue('sustained_for')).getNumericValue()
);
resultArray = transformer.execute(start, end).toArray();
}
var threshold = parseFloat(triggerGr.getValue('threshold'));
for (var i = 0; i < resultArray.length; ++i) {
var vals = resultArray[i].getValues();
for (var j = 0; j < vals.length; ++j) {
var evaluation = false;
var value = parseFloat(vals[j]);
switch (operation) {
case 'lt':
evaluation = value < threshold;
break;
case 'lte':
evaluation = value <= threshold;
break;
case 'gt':
evaluation = value > threshold;
break;
case 'gte':
evaluation = value >= threshold;
break;
default:
return false;
}
if (evaluation) {
return {
evaluation: true,
record_table: resultArray[i].getTableName(),
record_id: resultArray[i].getSubject(),
value: value
};
}
}
}
return {evaluation: false};
},
parseCondition: function (thresholdGr) {
var condition = thresholdGr.getValue('condition');
var ids = condition.split(/\^/);
var parsedCondition = [];
var currentCondition = [];
/*
parsedCondition is a computer readable version of the trigger's condition string
in the form of an array
Example:
The condition string is 'a^b^ORc^NQd^e' where a, b, c, d, e are triggers.
This condition can be re-written as (a && (b || c)) || (d && e).
parsedCondition will be [[[a], [b,c]], [[d], [e]]]
*/
for (var i = 0; i < ids.length; ++i) {
var val = ids[i];
if (val.startsWith('OR')) {
currentCondition[currentCondition.length - 1].push(val.replace('OR', ''));
continue;
}
if (val.startsWith('NQ')) {
parsedCondition.push(currentCondition);
currentCondition = [];
}
currentCondition.push([]);
currentCondition[currentCondition.length - 1].push(val.replace('NQ', ''));
}
parsedCondition.push(currentCondition);
return parsedCondition;
},
/*
Returns an object of triggers that is readable by the Thresholds UI.
Instead of an array that is easy to parse quickly, this object is easily displayed to the user
Example:
The condition string is 'a^b^ORc^NQd^e' where a, b, c, d, e are triggers.
Each of the triggers would become its own object with a condition (>, <, <=, etc..), id, and other attributes
Each of these objects represents a line in the UI (e.g. <metric> greater than <threshold> <sustained_for>)
*/
parseConditionExternal: function (thresholdGr) {
var condition = thresholdGr.getValue('condition');
var ids = condition.split(/\^/);
var triggers = [];
for (var i = 0; i < ids.length; ++i) {
var trigger = {};
var id = ids[i];
if (id.startsWith('OR'))
trigger.condition = '^OR';
else if (id.startsWith('NQ'))
trigger.condition = '^NQ';
else if (i != 0)
trigger.condition = '^';
id = id.replace(/^[A-Z]*/, '');
trigger.id = id;
triggers.push(trigger);
}
return triggers;
},
type: 'MetricConditionUtils'
};
Sys ID
8088e390ff432010fb0cffb0653bf1ac