Name
sn_em_ai.EvtMgmtLogAnalyticsMetricData
Description
No description available
Script
var EvtMgmtLogAnalyticsMetricData = Class.create();
EvtMgmtLogAnalyticsMetricData.prototype = {
initialize: function() {
this.errMessage = "";
},
getMetricPoints: function(additionalInfo, start, end) {
//Validate table existance. if not return empty state
var tgr = new GlideRecord("sn_occ_metric");
if (!tgr.isValid()) {
this.errMessage = gs.getMessage("Occultus plugin is not installed");
gs.error("EvtMgmtLogAnalyticsMetricData: Occultus plugin is not installed, sn_occ_metric table does not exist. returning empty state");
return this.errorResponse(this.errMessage);
}
if (!this.isValidTag(additionalInfo, 'sn_detection_type') ||
!this.isValidTag(additionalInfo, 'sn_metric_subject') ||
!this.isValidTag(additionalInfo, 'sn_metric_dimension')) {
this.errMessage = gs.getMessage("Missing fields in the additional info");
gs.error("EvtMgmtLogAnalyticsMetricData: Missing fields in the additional info, please check existance and validity of sn_detection_type, sn_metric_subject and sn_metric_dimension. returning empty state");
return this.errorResponse(this.errMessage);
}
additionalInfo.sn_anomaly_change_percentage = this.percentageAbsoluteVal(additionalInfo.sn_anomaly_change_percentage);
//setting all numerical params to be maximum 2 digits after the point
additionalInfo.sn_anomaly_change_percentage = this.formatTwo(additionalInfo.sn_anomaly_change_percentage);
var detectionType = additionalInfo.sn_detection_type;
var detectionTypeData = this.getDetectionTypeData(detectionType, additionalInfo);
var subject = additionalInfo.sn_metric_subject;
var dimensionFull = additionalInfo.sn_metric_dimension;
var dimensionParts = dimensionFull.split('|');
var dimension = dimensionParts[1];
var currentPoints = [];
if (detectionTypeData.getData != 0)
currentPoints = this.getPoints(subject, dimension, start, end, start, end);
//get expected metric points
var compareTime = detectionTypeData.compare;
var expectedStart = new GlideDateTime(start);
expectedStart.addSeconds(compareTime * -1);
var expectedEnd = new GlideDateTime(end);
expectedEnd.addSeconds(compareTime * -1);
var expectedPoints = [];
if (detectionTypeData.compare != 0)
expectedPoints = this.getPoints(subject, dimension, expectedStart, expectedEnd, start, end);
var thresholdPoints = [];
if (detectionType == "CUSTOM")
thresholdPoints = [{
value: parseInt(additionalInfo.sn_custom_threshold, 10)
}];
//build Json to return to UI
var countValue;
var expectedValue;
var expectedType;
var expectedTooltipType;
var countType;
//in case getPoints returned error
if (this.isValidTag(currentPoints, 'expected')) {
countValue = null;
expectedType = currentPoints.expected.type;
expectedTooltipType = detectionTypeData.expectedTooltipType;
expectedValue = currentPoints.expected.value;
currentPoints = [];
} else {
countValue = detectionTypeData.currentValue;
expectedValue = detectionTypeData.expectedValue;
expectedType = detectionTypeData.expectedType;
expectedTooltipType = detectionTypeData.expectedTooltipType;
countType = detectionTypeData.countType;
}
result = {
detectionType: detectionType,
tooltip: detectionTypeData.toolTip,
count: {
value: countValue,
type: detectionTypeData.countType
},
expected: {
value: expectedValue,
type: expectedType,
tooltipType: expectedTooltipType
},
metrics: [{
type: "RAW",
data: currentPoints
},
{
type: "EXPECTED",
data: expectedPoints
},
{
type: "AVERAGE",
data: thresholdPoints
}
]
};
return result;
},
getDetectionTypeData: function(detectionType, additionalInfo) {
var detectionTypeData = {};
detectionTypeData.countType = 'Events per minute';
var percentageText = additionalInfo.sn_anomaly_change_percentage <= 1000 ? gs.getMessage("{0}", [additionalInfo.sn_anomaly_change_percentage]) : gs.getMessage("above 1000");
switch (detectionType) {
case ('SIGNAL_ALIVE'):
detectionTypeData.compare = 0;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("This low-volume log appears more frequently");
if (additionalInfo.sn_metric_type == "RawMetric")
detectionTypeData.toolTip = gs.getMessage("This low-volume metric appears more frequently");
detectionTypeData.expectedType = gs.getMessage("Typically inactive");
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.expectedValue = null;
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
break;
case ('ANOMALY_BASELINE_REFERENCE_INCREASE'):
detectionTypeData.compare = 168 * 3600;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected in this hour as compared to the same hour last week");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
var anomalyIncreasedDiffValue = additionalInfo.sn_anomaly_current - additionalInfo.sn_anomaly_expected;
percentageText = this.formatTwo(((additionalInfo.sn_anomaly_current / anomalyIncreasedDiffValue) * 100) - 100);
if (additionalInfo.sn_metric_specific_type == 'GAUGE') {
detectionTypeData.countType = 'Avg. baseline value';
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% increase)", [this.formatTwo(anomalyIncreasedDiffValue), percentageText]);
} else {
detectionTypeData.expectedValue = gs.getMessage("{0} Events ({1}% increase)", [this.formatTwo(anomalyIncreasedDiffValue), percentageText]);
}
detectionTypeData.expectedType = gs.getMessage("Same hour - one week earlier:");
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
break;
case ('ANOMALY_BASELINE_REFERENCE_DECREASE'):
detectionTypeData.compare = 168 * 3600;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected in this hour as compared to the same hour last week");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
var anomalyDecreasedDiffValue = additionalInfo.sn_anomaly_current - additionalInfo.sn_anomaly_expected;
percentageText = this.formatTwo(((additionalInfo.sn_anomaly_current / anomalyDecreasedDiffValue) * 100) - 100);
if (additionalInfo.sn_metric_specific_type == 'GAUGE') {
detectionTypeData.countType = 'Avg. baseline value';
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% decrease)", [this.formatTwo(anomalyDecreasedDiffValue), percentageText]);
} else {
detectionTypeData.expectedValue = gs.getMessage("{0} Events ({1}% decrease)", [this.formatTwo(anomalyDecreasedDiffValue), percentageText]);
}
detectionTypeData.expectedType = gs.getMessage("Same hour - one week earlier:");
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
break;
case ('ANOMALY_STEEP_INCREASE'):
case ('ANOMALY_ABOVE_AVERAGE'):
detectionTypeData.compare = 24 * 3600;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected as compared to past behavior");
if (additionalInfo.sn_metric_specific_type == 'TIMELESSGAUGE') {
detectionTypeData.countType = 'Value of Anomaly';
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
detectionTypeData.expectedType = gs.getMessage("Avg. of last measurements:");
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% increase)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
} else if (additionalInfo.sn_metric_specific_type == 'GAUGE') {
detectionTypeData.countType = 'Value of Anomaly';
detectionTypeData.expectedType = gs.getMessage("Avg. of last hour:");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected) * 60));
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current) * 60);
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% increase)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = gs.getMessage("Same hour - one day earlier");
} else {
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected) * 60));
detectionTypeData.expectedType = gs.getMessage("Last hour:");
detectionTypeData.expectedValue = gs.getMessage("{0} Events ({1}% increase)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = gs.getMessage("Same hour - one day earlier");
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current) * 60);
}
additionalInfo.sn_anomaly_expected = additionalInfo.sn_anomaly_expected == 0? "0.0" : additionalInfo.sn_anomaly_expected;
break;
case ('ANOMALY_STEEP_DECREASE'):
case ('ANOMALY_BELOW_AVERAGE'):
detectionTypeData.compare = 24 * 3600;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected as compared to past behavior");
if (additionalInfo.sn_metric_specific_type == 'TIMELESSGAUGE') {
detectionTypeData.countType = 'Value of Anomaly';
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
detectionTypeData.expectedType = gs.getMessage("Avg. of last measurements:");
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% decrease)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
} else if (additionalInfo.sn_metric_specific_type == 'GAUGE') {
detectionTypeData.countType = 'Value of Anomaly';
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected) * 60));
detectionTypeData.expectedType = gs.getMessage("Avg. of last hour:");
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% decrease)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = gs.getMessage("Same hour - one day earlier");
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current) * 60);
} else {
detectionTypeData.expectedType = gs.getMessage("Last hour:");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected) * 60));
detectionTypeData.expectedValue = gs.getMessage("{0} Events ({1}% decrease)", [additionalInfo.sn_anomaly_expected, percentageText]);
detectionTypeData.expectedTooltipType = gs.getMessage("Same hour - one day earlier");
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current) * 60);
}
additionalInfo.sn_anomaly_expected = additionalInfo.sn_anomaly_expected == 0? "0.0" : additionalInfo.sn_anomaly_expected;
break;
case ('TIMELESS_TREND_INCREASE'):
detectionTypeData.countType = 'Value of Anomaly';
detectionTypeData.compare = additionalInfo.sn_recent_events_period_seconds;
detectionTypeData.getData = 1;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected for this metric, when compared to past behavior");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% increase)", [detectionTypeData.expectedValue, percentageText]);
detectionTypeData.expectedType = gs.getMessage("Avg. of last {0} measurements", additionalInfo.sn_points_in_timeless_trend);
break;
case ('TIMELESS_TREND_DECREASE'):
detectionTypeData.countType = 'Value of Anomaly';
detectionTypeData.compare = additionalInfo.sn_recent_events_period_seconds;
detectionTypeData.toolTip = gs.getMessage("Anomalous behavior detected for this metric, when compared to past behavior");
additionalInfo.sn_anomaly_expected = this.formatTwo((parseFloat(additionalInfo.sn_anomaly_expected)));
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
detectionTypeData.expectedValue = gs.getMessage("{0} ({1}% decrease)", [detectionTypeData.expectedValue, percentageText]);
detectionTypeData.expectedType = gs.getMessage("Avg. of last {0} measurements", additionalInfo.sn_points_in_timeless_trend);
break;
case ('NEW_SIGNAL'):
detectionTypeData.compare = 0; // no metricpoints to compare
detectionTypeData.getData = 0;
detectionTypeData.toolTip = gs.getMessage("First appearance of this pattern in {0}", additionalInfo.sn_component);
detectionTypeData.expectedType = gs.getMessage("New behavior");
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.expectedValue = gs.getMessage("No data to display at the moment");
break;
case ('SIGNAL_DEAD'):
detectionTypeData.compare = 0; // no metricpoints to compare
detectionTypeData.getData = 0;
detectionTypeData.toolTip = gs.getMessage("No data is streaming from {0}", additionalInfo.sn_component);
detectionTypeData.expectedType = gs.getMessage("Signal dead");
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.expectedValue = gs.getMessage("Data stopped streaming");
break;
case ("CUSTOM"):
detectionTypeData.countType = gs.getMessage("Log Entries in the course of {0} {1}", [additionalInfo.sn_custom_number, additionalInfo.sn_custom_time]);
detectionTypeData.getData = 1;
detectionTypeData.compare = 0; // no metricpoints to compare
detectionTypeData.toolTip = gs.getMessage("Manually defined threshold for this metric has been crossed");
detectionTypeData.currentValue = this.formatTwo(parseFloat(additionalInfo.sn_anomaly_current));
var definedThreshold = additionalInfo.sn_custom_threshold;
detectionTypeData.expectedType = gs.getMessage("{0} ", detectionTypeData.currentValue);
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.expectedValue = gs.getMessage("{0} {1} (defined threshold)", [additionalInfo.sn_operator, definedThreshold]);
break;
default:
detectionTypeData.compare = 0; //no metricpoints to compare
detectionTypeData.getData = 0;
detectionTypeData.toolTip = gs.getMessage("Unrecognized detection type");
detectionTypeData.expectedType = null;
detectionTypeData.expectedTooltipType = detectionTypeData.expectedType;
detectionTypeData.expectedValue = gs.getMessage("Unrecognized detection type");
break;
}
return detectionTypeData;
},
// check if the JSON tag/key is valid
isValidTag: function(element, tag) {
var val = element.hasOwnProperty(tag);
return val;
},
getPoints: function(subject, dimension, start, end, originalStart, originalEnd, type) {
var result = {};
var gr = new GlideRecord("sn_occ_metric");
gr.addQuery('name', subject);
gr.query();
if (gr.next()) {
try {
var selector = new sn_clotho.DataSelector(gr)
.addMetric(dimension).label(dimension);
var data = new sn_clotho.Client().transform(selector, start, end);
for (var key in data) {
if (data.hasOwnProperty(key)) {
result["start_time"] = data[key].getStart() + '';
result["end_time"] = data[key].getEnd() + '';
result["points"] = (data[key].getValues());
}
}
} catch (err) {
var errMsg = err + '';
if (errMsg.indexOf('No valid metric') != -1) {
gs.error("EvtMgmtLogAnalyticsMetricData: Failed retrieving metric points. need to check that subject or dimension are defined properly. returning empty state");
result["start_time"] = start + '';
result["end_time"] = end + '';
result["points"] = [];
} else {
gs.error("EvtMgmtLogAnalyticsMetricData: Failed retrieving metric points, " + errMsg);
return this.errorResponse(this.errMessage);
}
}
} else { // subject does not exist in the sn_occ_table
this.errMessage = gs.getMessage("Failed retrieving metric points");
gs.error("EvtMgmtLogAnalyticsMetricData: Failed retrieving metric points: subject {0} does not exist in the sn_occ_table - returning empty state", subject);
result["start_time"] = start + '';
result["end_time"] = end + '';
result["points"] = [];
}
// going to arrange the metric points int API format
return this.setResponse(result, originalStart, start, end);
},
setResponse: function(result, originalStart, start, end) {
var timeStamp = new GlideDateTime(originalStart);
var pointsStartTime = new GlideDateTime(result["start_time"]);
var comparedTimeStamp = new GlideDateTime(originalStart);
if (comparedTimeStamp > pointsStartTime)
comparedTimeStamp = new GlideDateTime(start);
var points = result["points"];
var parsedResult = [];
for (; comparedTimeStamp < pointsStartTime; comparedTimeStamp.addSeconds(60)) {
parsedResult.push({
x: timeStamp.getNumericValue(),
y: 0
});
timeStamp.addSeconds(60);
}
for (var k in points) {
//in some cases the server return NaN instead of null we want to make sure we always send null in case of missing point
if (isNaN(points[k]))
points[k] = 0;
parsedResult.push({
x: timeStamp.getNumericValue(),
y: points[k]
});
timeStamp.addSeconds(60);
comparedTimeStamp.addSeconds(60);
}
for (; comparedTimeStamp < end; comparedTimeStamp.addSeconds(60)) {
parsedResult.push({
x: timeStamp.getNumericValue(),
y: 0
});
timeStamp.addSeconds(60);
}
return parsedResult;
},
percentageAbsoluteVal: function(changePercentage) {
if (!changePercentage)
return 0;
var changePercentageVal = Number(changePercentage);
if (changePercentageVal < 0)
changePercentageVal *= -1;
// if there is only 0 after the point we want to present a whole number
if (changePercentageVal - parseInt(changePercentageVal, 10) == 0)
return changePercentageVal.toFixed();
return changePercentageVal;
},
formatTwo: function(val) {
if (!val)
return "";
var x = parseInt(Math.round(val * 100), 10);
return (x / 100).toString();
},
errorResponse: function(errMessage) {
return {
"count": null,
"expected": {
"value": errMessage,
"type": "Error"
},
metrics: []
};
},
type: 'EvtMgmtLogAnalyticsMetricData'
};
Sys ID
73a10e7853531010cf0addeeff7b12d6