Name
sn_app_insights.P1Model
Description
Script to predict P1 incidents periodically.
Script
var P1Model = Class.create();
P1Model.prototype = {
initialize: function() {
},
predict: function() {
var timeSeriesLength = 60;
var metrics = ['semaphores', 'sys_load'];
var minutesAgoStart = timeSeriesLength + 1; // add one because sometimes the last minute is cut off
var end = new GlideDateTime();
var start = new GlideDateTime(end);
start.addSeconds(-1 * minutesAgoStart * 60);
// query subject records
var grTable = new GlideRecord('sys_cluster_state');
grTable.query();
var grInsert = new GlideRecord('sn_app_insights_p1_predict');
grInsert.initialize();
var index = 0;
// load each metric time series into GlideRecord
for (key in metrics) {
metric = metrics[key];
index = this._getData(start, end, grTable, grInsert, metric, index, gs.getProperty('sn_app_insights.p1_predict_factor.' + metric), timeSeriesLength);
}
// If there is not sufficient data for a prediction we do nothing
if (index == metrics.length * timeSeriesLength) {
var sys_id = grInsert.insert();
this._predict(sys_id);
}
},
_getData: function(start, end, grTable, grInsert, metric, index, normalizer, length) {
// build transform, included below is fix for bug in metricbase
var resamplePeriodDuration;
var scheduledJob = new GlideRecord("sysauto_script");
scheduledJob.get("8509fd6cc7852010ff7667617ec26038");
resamplePeriodDuration = new GlideDuration(scheduledJob.run_period.dateNumericValue());
var transformer = new sn_clotho.Transformer(grTable);
transformer.metric(metric).resample("AVG", resamplePeriodDuration).avg();
// execute and return result for prediction
var data = transformer.execute(start, end).getData().getValues();
var validArray = data.filter(function(value) {
return !(isNaN(value) || value == null);
});
i = index;
for (var key in validArray) {
if (validArray.hasOwnProperty(key)) {
if (i == 0)
grInsert['u_' + i] = validArray[key] / normalizer;
else if (i - index < length)
grInsert['u_' + i + '_0'] = validArray[key] / normalizer;
else
break;
i++;
}
}
return i;
},
_predict: function(sys_id) {
if (sys_id !== null) {
var grPredict = new GlideRecord('sn_app_insights_p1_predict');
grPredict.get(sys_id);
var options = {};
var threshold = gs.getProperty('sn_app_insights.p1_predict_threshold', 90);
options.top_n = 1;
options.apply_threshold = false;
var predictionObject = JSON.parse(sn_ml.ClassificationSolutionStore.get('ml_x_global_global_p1_predict_script').getLatestVersion().predict(grPredict, options));
var prediction = predictionObject[grPredict.sys_id][0].predictedValue;
var confidence = parseFloat(predictionObject[grPredict.sys_id][0].confidence);
var maxCoolDown = gs.getProperty('sn_app_insights.p1_predict_max_cooldown', 5);
var state = this._getState(maxCoolDown);
if (prediction === "true" && confidence >= threshold) {
if (state === false) {
var currentTime = new GlideDateTime();
var enterMessage = gs.getMessage("Entering a p1 alert state. We predicted a p1 might occur within 20 minutes with a confidence of {0}%. It might be due to exhaustion in the default semaphore set and/or an unusually high number of transactions.", Math.round(confidence));
gs.warn(enterMessage);
var grEnter = new GlideRecord("diagnostic_event");
grEnter.initialize();
grEnter.setValue('name', "P1 Predicted");
grEnter.setValue('detail', enterMessage);
grEnter.setValue('severity', "Warning");
grEnter.setValue('status', "Open");
grEnter.setValue('reported_on', currentTime);
grEnter.insert();
var ongoingMessage = gs.getMessage("Ongoing P1 alert state.");
gs.info(ongoingMessage);
var grOngoing = new GlideRecord("diagnostic_event");
grOngoing.initialize();
grOngoing.setValue('name', "P1 Predicted");
grOngoing.setValue('severity', "Warning");
grOngoing.setValue('detail', ongoingMessage);
grOngoing.setValue('status', "Information");
grOngoing.setValue('reported_on', currentTime);
grOngoing.insert();
// Log P1 Prediction in GCF
var sm = new GCFSampleMap();
// GCFSampleMap can sometimes recognize currentTime.getValue as a Java Object rather than a string, needs casting
sm.put('start', String(currentTime.getValue()));
GCFCollector.recordUsageEvent('custom_metric', 'app_insights_usage', 'p1_predicted', sm);
} else
this._setState(state, true);
} else
this._setState(state, false);
grPredict.deleteRecord();
}
},
_getState: function(maxCoolDown) {
// Get most recent P1 Predict diagnostic event
var isPastCoolDown = false;
var gr = new GlideRecord('diagnostic_event');
gr.addQuery('name', "P1 Predicted");
gr.addQuery('status', "Information");
gr.orderByDesc('sys_created_on');
gr.query();
// If there is no information record, the state remains false
if (gr.next()) {
var lastAlert = new GlideDateTime(gr.getValue('reported_on'));
var cooldown = new GlideDateTime();
cooldown.addSeconds(-1 * maxCoolDown * 60);
isPastCoolDown = cooldown.before(lastAlert);
}
return isPastCoolDown;
},
_setState: function(state, resetState) {
var gr = new GlideRecord('diagnostic_event');
gr.addQuery('name', "P1 Predicted");
gr.addQuery('status', "Information");
gr.orderByDesc('sys_created_on');
gr.query();
if (gr.next()) {
if (!state) {
gr.setValue('detail', gs.getMessage("Ending current p1 alert state. We no longer predict a p1 might occur."));
gr.setValue('status', "Closed");
gr.setValue('reported_on', new GlideDateTime());
}
if (resetState)
gr.setValue('reported_on', new GlideDateTime());
gr.update();
}
},
type: 'P1Model'
};
Sys ID
83d8e239c7602010ff7667617ec2604e