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

Offical Documentation

Official Docs: