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