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

Offical Documentation

Official Docs: