Event Management for ServiceNow
Event Management consolidates events from monitoring tools, correlates them, and creates actionable alerts.
Event Flow
Monitoring Tools (Nagios, SCOM, etc.) ↓ Events (em_event) ↓ Event Rules Alerts (em_alert) ↓ Alert Management Rules Incidents/Changes
Key Tables
Table Purpose
em_event
Raw events from sources
em_alert
Processed alerts
em_event_rule
Event processing rules
em_alert_correlation_rule
Alert correlation
em_connector
Event source connectors
Events (ES5)
Create Event Programmatically
// Create event (ES5 ONLY!) var event = new GlideRecord("em_event") event.initialize()
// Required fields event.setValue("source", "Custom Monitor") event.setValue("node", "server01.example.com") event.setValue("type", "CPU High") event.setValue("severity", 3) // 1=Critical, 2=Major, 3=Minor, 4=Warning, 5=OK
// Event key for deduplication event.setValue("event_class", "performance") event.setValue("message_key", "cpu_high_server01")
// Description event.setValue("description", "CPU usage exceeded 90% threshold") event.setValue( "additional_info", JSON.stringify({ cpu_percent: 95, process: "java", duration: "5 minutes", }), )
// CI binding event.setValue("cmdb_ci", getCISysId("server01"))
// Resource and metric event.setValue("resource", "CPU") event.setValue("metric_name", "cpu_usage")
event.insert()
Event via REST API
// Push event via REST (External script - ES5 ONLY!) var request = { records: [ { source: "External Monitor", node: "app-server-01", type: "Application Error", severity: "2", message_key: "app_error_" + Date.now(), description: "Application threw critical exception", additional_info: '{"error_code": "E500", "module": "payment"}', }, ], }
// POST to: /api/global/em/jsonv2
Event Rules (ES5)
Event Processing Rule
// Create event rule (ES5 ONLY!) var rule = new GlideRecord("em_event_rule") rule.initialize()
// Rule identification rule.setValue("name", "High CPU Alert") rule.setValue("description", "Create alert for high CPU events") rule.setValue("order", 100) rule.setValue("active", true)
// Event filter (which events to process) rule.setValue("filter", "type=CPU High^severity<=3")
// Actions rule.setValue("create_alert", true) rule.setValue("alert_severity", 3)
// Transform settings rule.setValue("transform_type", true) rule.setValue("new_type", "Performance - CPU")
// CI binding rule.setValue("ci_binding_type", "node")
rule.insert()
Event Rule Script (ES5)
// Event rule advanced script (ES5 ONLY!) // Table: em_event_rule, field: script
;(function runRule(event, rule) { // Get additional info var addInfo = {} try { addInfo = JSON.parse(event.additional_info) } catch (e) { addInfo = {} }
// Set severity based on CPU percentage var cpuPercent = parseFloat(addInfo.cpu_percent) || 0
if (cpuPercent >= 95) { event.severity = 1 // Critical } else if (cpuPercent >= 90) { event.severity = 2 // Major } else if (cpuPercent >= 80) { event.severity = 3 // Minor }
// Enrich description event.description = event.description + " (Current: " + cpuPercent + "%)"
// Set time to clear (auto-close if OK event not received) event.u_time_to_clear = 900 // 15 minutes
return true // Continue processing })(event, rule)
Alerts (ES5)
Alert Lifecycle
Open ↓ Acknowledge Acknowledged ↓ Investigate In Progress ↓ Resolution Resolved ↓ Close Closed
Flapping ← Multiple severity changes
Alert Management Rule
// Create alert management rule (ES5 ONLY!) var amRule = new GlideRecord("em_alert_management_rule") amRule.initialize()
amRule.setValue("name", "Auto-create Incident for Critical Alerts") amRule.setValue("description", "Create P1 incident for critical alerts on production CIs") amRule.setValue("order", 100) amRule.setValue("active", true)
// Alert filter amRule.setValue("filter", "severity=1^cmdb_ci.u_environment=production")
// Action: Create incident amRule.setValue("create_incident", true) amRule.setValue("incident_priority", 1) amRule.setValue("incident_assignment_group", getGroupSysId("NOC"))
amRule.insert()
Manual Alert Processing (ES5)
// Process alert manually (ES5 ONLY!) function acknowledgeAlert(alertSysId, notes) { var alert = new GlideRecord("em_alert") if (!alert.get(alertSysId)) { return { success: false, message: "Alert not found" } }
// Validate state if (alert.getValue("state") !== "Open") { return { success: false, message: "Alert is not in Open state" } }
// Acknowledge alert.setValue("state", "Acknowledged") alert.setValue("acknowledged_by", gs.getUserID()) alert.setValue("acknowledged_at", new GlideDateTime())
// Add notes if (notes) { alert.work_notes = "Acknowledged: " + notes }
alert.update()
return { success: true, number: alert.getValue("number") } }
Alert Correlation (ES5)
Correlation Rule
// Create correlation rule (ES5 ONLY!) var corrRule = new GlideRecord("em_alert_correlation_rule") corrRule.initialize()
corrRule.setValue("name", "Server Down Correlation") corrRule.setValue("description", "Correlate all alerts when a server goes down") corrRule.setValue("active", true)
// Parent alert filter corrRule.setValue("parent_filter", "type=Server Down^severity=1")
// Child alert filter corrRule.setValue("child_filter", "cmdb_ci.u_hosted_on=javascript:parent.cmdb_ci")
// Correlation window corrRule.setValue("time_window", 300) // 5 minutes
// Action corrRule.setValue("set_child_severity", true) corrRule.setValue("new_child_severity", 4) // Warning
corrRule.insert()
Custom Correlation Script (ES5)
// Alert correlation script (ES5 ONLY!) // Correlate database alerts with application alerts
var AlertCorrelation = Class.create() AlertCorrelation.prototype = { initialize: function () {},
/**
- Find related alerts for correlation */ findRelatedAlerts: function (parentAlertSysId) { var parent = new GlideRecord("em_alert") if (!parent.get(parentAlertSysId)) { return [] }
var relatedAlerts = []
var parentCI = parent.getValue("cmdb_ci")
var parentTime = new GlideDateTime(parent.getValue("sys_created_on"))
// Time window: 5 minutes before/after parent
var windowStart = new GlideDateTime(parentTime)
windowStart.addSeconds(-300)
var windowEnd = new GlideDateTime(parentTime)
windowEnd.addSeconds(300)
// Find alerts on dependent CIs
var dependents = this._getDependentCIs(parentCI)
var alert = new GlideRecord("em_alert")
alert.addQuery("cmdb_ci", "IN", dependents.join(","))
alert.addQuery("sys_created_on", ">=", windowStart)
alert.addQuery("sys_created_on", "<=", windowEnd)
alert.addQuery("sys_id", "!=", parentAlertSysId)
alert.addQuery("parent_alert", "") // Not already correlated
alert.query()
while (alert.next()) {
relatedAlerts.push({
sys_id: alert.getUniqueValue(),
number: alert.getValue("number"),
cmdb_ci: alert.cmdb_ci.getDisplayValue(),
severity: alert.getValue("severity"),
})
}
return relatedAlerts
},
_getDependentCIs: function (parentCISysId) { var dependents = []
var rel = new GlideRecord("cmdb_rel_ci")
rel.addQuery("parent", parentCISysId)
rel.addQuery("type.name", "Depends on::Used by")
rel.query()
while (rel.next()) {
dependents.push(rel.getValue("child"))
}
return dependents
},
/**
- Correlate alerts under parent */ correlate: function (parentAlertSysId, childAlertSysIds) { for (var i = 0; i < childAlertSysIds.length; i++) { var child = new GlideRecord("em_alert") if (child.get(childAlertSysIds[i])) { child.setValue("parent_alert", parentAlertSysId) child.work_notes = "Correlated with parent alert" child.update() } } },
type: "AlertCorrelation", }
Metrics (ES5)
Create Metric Event
// Create metric event for threshold monitoring (ES5 ONLY!) function createMetricEvent(ciSysId, metricName, value, thresholds) { var severity = 5 // OK by default
// Determine severity based on thresholds if (value >= thresholds.critical) { severity = 1 } else if (value >= thresholds.major) { severity = 2 } else if (value >= thresholds.minor) { severity = 3 } else if (value >= thresholds.warning) { severity = 4 }
// Only create event if not OK if (severity < 5) { var event = new GlideRecord("em_event") event.initialize() event.setValue("source", "Metric Monitor") event.setValue("cmdb_ci", ciSysId) event.setValue("type", metricName + " Threshold") event.setValue("severity", severity) event.setValue("metric_name", metricName) event.setValue("message_key", metricName + "_" + ciSysId) event.setValue("description", metricName + " is at " + value + " (Threshold: " + getThresholdName(severity) + ")") event.insert() }
return severity }
function getThresholdName(severity) { var names = { 1: "Critical", 2: "Major", 3: "Minor", 4: "Warning", 5: "OK" } return names[severity] }
MCP Tool Integration
Available Tools
Tool Purpose
snow_query_table
Query events and alerts
snow_find_artifact
Find event rules
snow_execute_script_with_output
Test event scripts
snow_create_event
Trigger system events
Example Workflow
// 1. Query open alerts await snow_query_table({ table: "em_alert", query: "state=Open^severity<=2", fields: "number,description,cmdb_ci,severity,source", })
// 2. Find unprocessed events await snow_query_table({ table: "em_event", query: "state=Ready", fields: "source,node,type,severity,description", })
// 3. Create test event
await snow_execute_script_with_output({
script: var event = new GlideRecord('em_event'); event.initialize(); event.source = 'Test'; event.type = 'Test Event'; event.severity = 4; event.node = 'test-server'; gs.info('Created: ' + event.insert()); ,
})
Best Practices
-
Event Deduplication - Use message_key properly
-
CI Binding - Bind events to CIs for impact
-
Severity Mapping - Consistent severity levels
-
Correlation - Reduce alert noise
-
Time Windows - Configure appropriate windows
-
Auto-closure - Set time-to-clear for transient issues
-
Monitoring - Track event processing health
-
ES5 Only - No modern JavaScript syntax