Name

sn_em_arm.EvtMgmtAlertMgmtJob

Description

Common alert management job

Script

gs.include('EvtMgmtCommons');
gs.include('SlowStepJSManager');
gs.include('EvtMgmtAlertMgmtMediator');
gs.include('EvtMgmtAlertMgmtCommons');
gs.include('EvtMgmtAlertMgmtProcess');
gs.include('EvtMgmtAlertMgmtUtils');

var EvtMgmtAlertMgmtJob = Class.create();
EvtMgmtAlertMgmtJob.prototype = {

  type: 'EvtMgmtAlertMgmtJob',

  initialize: function(slowStepManager, lastArmJobHash, lastQueryJobRunHash, lastCreatedTimeHash, waitForGrouping, lastSimultaneousAlert) {
      this.ALERT_MANAGEMENT_DELAY = "evt_mgmt.alert_rule_delay";
      this.evtMgmtCommons = new global.EvtMgmtCommons();
      this.evtMgmtAlertMgmtCommons = new EvtMgmtAlertMgmtCommons();
      this.evtMgmtAlertMgmtUtils = new EvtMgmtAlertMgmtUtils();
      this.evtMgmtAlertMgmtMediator = new global.EvtMgmtAlertMgmtMediator();
      this.slowStepsManager = slowStepManager;
      this.lastArmJobHash = lastArmJobHash;
      this.lastQueryJobRunHash = lastQueryJobRunHash;
      this.lastCreatedTimeHash = lastCreatedTimeHash;
      this.waitForGrouping = waitForGrouping;
      this.evtMgmtAlertMgmtProcess = new EvtMgmtAlertMgmtProcess(this.slowStepsManager);
      this.CHUNK_SIZE_PROPERTY = 'evt_mgmt.alert.management.chunk_size';
      this.chunkSize = gs.getProperty(this.CHUNK_SIZE_PROPERTY, 10000);
      this.DISABLE_CHUNK_OVERFLOW_HANDLING_PROPERTY = 'evt_mgmt.alert.management.disable_chunk_overflow_handling';
      this.disableChunkOverflowHandling = gs.getProperty(this.DISABLE_CHUNK_OVERFLOW_HANDLING_PROPERTY, 'false') == 'true';
      this.lastSimultaneousAlert = lastSimultaneousAlert;
      // if the hash value of the lastSimultaenousAlert is non-nil, then we are in the corner case where we are only processing
      // alerts exactly at the current processing time, and we take a different code path than the normal.
      this.chunkSizeOverflowCase = !this.disableChunkOverflowHandling && !gs.nil(lastSimultaneousAlert.hash);
      this.NUM_OF_PROCESS_JOBS = gs.getProperty('sn_em_arm.alert_management.num_of_jobs', 1);
  },

  evaluateAlerts: function() {
      var evtMgmtAlertMgmtWrapper = new EvtMgmtAlertMgmtJobWrapper();
      evtMgmtAlertMgmtWrapper.execute();
  },

  evaluateAlertsCalc: function(jobNum) {
      var multiJobProcess = false;
     // in case the jobNum is empty - we are working in no-scale mode - only one job.
     // in case the jobNum is not empty scale mode is on
      if (jobNum != null) {
          multiJobProcess = true;
      }
      
      this.slowStepsManager.setTopic("Alert Management");
      this.slowStepsManager.startStep(this.getScriptName() + ": Start job");

      var startTimeForPerformence = new Date().getTime();
      var alertCount = 0;
      var lastAlertNumber = '';
      var perfCounters = {};
      perfCounters.remediationsCount = 0;
      perfCounters.subFlowsCount = 0;
      perfCounters.sroAlertsCount = 0;
      perfCounters.maxAlertProcessingDuration = {
          value: 0,
          alert: undefined
      };
      perfCounters.maxDurationGlideFilterRule = {
          value: 0,
          alert: undefined,
          ruleName: undefined
      };
      perfCounters.maxDurationEvaluateRuleScript = {
          value: 0,
          alert: undefined,
          ruleName: undefined
      };

      if (gs.getProperty('evt_mgmt.alert.management.activated', false) === 'true') {


          var startTime = this.getStartTime(); //get last calculated timestamp
          var inProgressEndTime = this.getInProgressTime();

          if (startTime != inProgressEndTime) {
              this.evtMgmtCommons.addDebugMessage(this.getScriptName() +' job:  time range for alerts retrieval is:  ' + startTime + '-' + inProgressEndTime);
              
              this.slowStepsManager.startStep(this.getScriptName() + ": Get domain");

              var originalSessionID = this.evtMgmtCommons.getCurrentDomainID();

              this.slowStepsManager.startStep(this.getScriptName() + ": Get Alert");
              // if we are in the chunk overflow case, then we only want the next batch of alerts from this second. 
              // Otherwise, continue with the regular flow.
              var alertsGR;
              if(multiJobProcess) {
                   alertsGR = this.chunkSizeOverflowCase ?
                  this.getAlertsThisSecond(startTime, this.lastSimultaneousAlert.hash, jobNum) :
                  this.getAlerts(startTime, inProgressEndTime, jobNum);
              } else {
                  alertsGR = this.chunkSizeOverflowCase ?
                  this.getAlertsThisSecond(startTime, this.lastSimultaneousAlert.hash) :
                  this.getAlerts(startTime, inProgressEndTime);
              }
             
              this.slowStepsManager.startStep(this.getScriptName() + ": Get Alert SysIds");
              var alertsGRSysIds = this.evtMgmtAlertMgmtMediator.getAlertsSysIds(alertsGR);

              if (alertsGRSysIds) {
                  this.slowStepsManager.startStep(this.getScriptName() + ": Get Alert Execution Map");
                  var map = this.evtMgmtAlertMgmtCommons.getAlertRuleExecutionMap(alertsGRSysIds);
                  var startTimeinMillis = (new Date()).getMilliseconds();
                  var updatedTime;
                  this.slowStepsManager.startStep(this.getScriptName() + ": Run for Alert");
                  while (alertsGR.next()) {
                      this.evtMgmtCommons.addDebugMessage(this.getScriptName() + '  EvtMgmtAlertMgmtJob.evaluateAlertsCalc - alerts to process: ' + alertsGR.getValue('number') + ' ' + alertsGR.getValue('sys_id') + ', created = ' + alertsGR.getValue('sys_created_on') + ', updated = ' + alertsGR.getValue('sys_updated_on') + ', severity= ' + alertsGR.getValue('severity'));
                      
                      this.slowStepsManager.startStep(this.getScriptName() + ": Iterate over Alerts");
                      alertCount = alertCount + 1;
                      lastAlertNumber = alertsGR.number;
                      updatedTime = this.getLastGrTime(alertsGR);

                      // Take time before processing an alert
                      var t1 = new Date();

                      this.evtMgmtAlertMgmtProcess.runForAlert(alertsGR, false, false, {
                          retrieveSubflows: true,
                          retrieveLaunchApplications: false,
                          retrieveRemediations: true
                      }, map, perfCounters);

                      // Take time after processing the alert
                      var t2 = new Date();

                      // Save the max time of processed alert and its related alert number
                      if (perfCounters && (t2 - t1 >= perfCounters.maxAlertProcessingDuration.value)) {
                          perfCounters.maxAlertProcessingDuration.value = t2 - t1;
                          perfCounters.maxAlertProcessingDuration.alert = alertsGR.getValue('number');
                      }

                      this.slowStepsManager.startStep(this.getScriptName() + ": End Loop- before alertsGR.next())");
                  }

                  this.slowStepsManager.startStep(this.getScriptName() + ": Finished Run for Alert");

                  var reachLimit = false;
                  if (alertCount >= this.chunkSize) {
                      // if there are more unprocessed alerts left, save in sa_hash the sys_updated_on of the most recent alert 
                      inProgressEndTime = new GlideDateTime(updatedTime);
                      reachLimit = true;
                  }
                  var endTimeinMillis = (new Date()).getMilliseconds();
                  var logStatistices = gs.getProperty("evt_mgmt.alert_mgmt_collect_perf_data", false);
                  if (logStatistices) {
                      var processDuration = (endTimeinMillis - startTimeinMillis);
                      if (processDuration > 0) {
                          var averageTime = (alertCount * 1000) / processDuration; //1000 is to set it to seconds rate
                          gs.debug("==amf== Alert Management Performance (in seconds)" + averageTime + "(count: " + alertCount + ")");
                      }
                  }

                  this.slowStepsManager.startStep(this.getScriptName() + ": changeDomain");

                  //return domain to original
                  this.evtMgmtCommons.changeDomain(originalSessionID);
              }

              this.slowStepsManager.startStep(this.getScriptName() + ": update hash");
              if (alertCount >= this.chunkSize) {
                  // there are more alerts to process, so check if we might need to start or continue handling the chunk size overflow corner case
                  if (this.chunkSizeOverflowCase) {
                      // we are already in the corner case, now need to set the last simultaneous alert number to the last alert processed for next loop
                      this.lastSimultaneousAlert.hash = lastAlertNumber;
                      this.lastSimultaneousAlert.update();
                      gs.info("ARM: Processed " + alertCount + " alerts from exactly " + startTime.getTime() + ", ending at " + lastAlertNumber);
                  } else {
                      startTime = new GlideDateTime(startTime);
                      var diffInSeconds = (inProgressEndTime.getNumericValue() / 1000 | 0) - (startTime.getNumericValue() / 1000 | 0);
                      if (diffInSeconds == 0) {
                          if (this.disableChunkOverflowHandling) {
                              // abort processing more alerts from this second and move on to the next second.
                              gs.error("ARM: More than " + alertCount + " alerts were updated in the same second: " + startTime + ".\n" +
                                  "Since Chunk Overflow Handling is disabled, some alerts may not have had rules executed for them.\n" +
                                  "See properties: " + this.CHUNK_SIZE_PROPERTY + ", " + this.DISABLE_CHUNK_OVERFLOW_HANDLING_PROPERTY);
                              inProgressEndTime.addSeconds(1);
                          } else {
                              // this means we have overflowed the batch size, and need to enter the "chunkSizeOverflowCase" corner case flow.
                              gs.info("ARM: More than " + alertCount + " alerts were updated in the same second: " + startTime + ".\n" +
                                  "This means we will reprocess all alerts from this time in order of number.\n" +
                                  "See property: " + this.CHUNK_SIZE_PROPERTY);
                              // Set the lastSimultaneousAlert hash to "START" to signal that on our next loop we must enter the corner case flow
                              this.lastSimultaneousAlert.hash = this.evtMgmtAlertMgmtUtils.START_SIMULTANEOUS_LOOP;
                              this.lastSimultaneousAlert.update();
                              this.chunkSizeOverflowCase = true; // need this so we don't update the "inProgressEndTime" hash below
                          }
                      }
                  }
              } else if (this.chunkSizeOverflowCase) {
                  gs.info("ARM: Finished processing alerts from this second; now returning to normal flow.");
                  // we have just finished handling our overflow case, so clear the hash and let's move on.
                  this.lastSimultaneousAlert.hash = '';
                  this.lastSimultaneousAlert.update();
                  inProgressEndTime = new GlideDateTime(startTime);
                  inProgressEndTime.addSeconds(1);

                  this.chunkSizeOverflowCase = false; // allow the "inProgressEndTime" hash to update below
              }

              if (!this.chunkSizeOverflowCase) {
                  this.updateHash(inProgressEndTime);
              }
          }
      }
      else {
          this.evtMgmtCommons.addDebugMessage(this.getScriptName() +' evaluateAlertsCalc: startTime == inProgressEndTime : ' + startTime);
      }
      var enableLog = gs.getProperty('evt_mgmt.log_alert_sysid_and_time', 'false') == 'true';
      var perfJson = {};
      perfJson.scriptName = this.getScriptName();
      perfJson.processedAlerts = alertCount;
      perfJson.remediationsCount = perfCounters.remediationsCount + "";
      perfJson.subFlowsCount = perfCounters.subFlowsCount + "";
      perfJson.sroAlertsCount = perfCounters.sroAlertsCount;
      perfJson.maxDurationGlideFilterRule = perfCounters.maxDurationGlideFilterRule;
      perfJson.maxDurationEvaluateRuleScript = perfCounters.maxDurationEvaluateRuleScript;
      perfJson.maxAlertProcessingDuration = perfCounters.maxAlertProcessingDuration;
      perfJson.startTime = startTime;
      perfJson.endTime = updatedTime ? updatedTime : inProgressEndTime + '';
      if(multiJobProcess)
          perfJson.jobNum = jobNum;
      if (enableLog) {
          if (alertsGRSysIds) {
              perfJson.alertSysIds = alertsGRSysIds;
          }
      }
      if (reachLimit) {
          perfJson.reachLimitInProgressTime = inProgressEndTime + "";
      }
      var duration = (new Date().getTime()) - startTimeForPerformence;
      this.evtMgmtCommons.writeToPerfTable("evtMgmtAlertManagementJob", alertCount, duration, perfJson);

  },

  addProtectTimeForQuery: function(recentAlerts) {
      var lastArmJobHash = this.getHash('analytics_trigger');
      var analyticsTime = this.getStartTime(lastArmJobHash); //get last calculated timestamp
      var analyticsDT = new GlideDateTime(analyticsTime);
      var now = new GlideDateTime();
      now.subtract(1000 * 60 * 5);
      if (analyticsDT.after(now)) {
          recentAlerts.addQuery("grouping_state", "1");
      }
  },
  
  getLastGrTime: function(gr) {
      //implement in inheritance
  },

  getStartTime: function() {
      //implement in inheritance
  },

  getInProgressTime: function() {
      //implement in inheritance
  },

  getAlerts: function(startTime, endTime) {
      //implement in inheritance
  },

  // This function returns all alerts from the exact time specified, with a bookmark of which was the last alert thus processed
  getAlertsThisSecond: function(exactTime, lastSimultaneousAlertNumber) {
      //implement in inheritance
  },

  updateHash: function(inProgressEndTime) {
      //implement in inheritance
  },

  getScriptName: function() {
      return this.type;
  },

};

Sys ID

e5cd09eeb79920107c038229ce11a9c7

Offical Documentation

Official Docs: