Troubleshooting SLAs
/* * @Description - This script speeds up the information gathering process * about an existing task_sla. It outputs information about the * contract_sla (SLA Definition), task (Incident, Problem, etc.), task_sla * (running SLA), wf_context (Running Workflow) and wf_history (History * of the running Workflow). First it outputs information about the * definitions of the above items and then it compiles the history of * changes to each item and orders them by timestamp so that you can piece * together expected vs. actual behavior. See bottom of script for usage * information. */function newDCheck() {return {//Specify sys_id of the SLA definition//@param fld {string} field of SLA Definition to query//@param value {string} value to match agains fld//@param filters {array} array of objects in format [{field:"",op:"",value:""},...]getLatestByDefinition : function(fld, value, test, filters) {if (typeof tests == "undefined")tests = 3;//number of sla's to testvar out = ["NOTE: All times in GMT\n"];var sld = new GlideRecord("contract_sla");sld.addQuery(fld, value);sld.query();while (sld.next()) {//Print conditions from SLA definitionout.push(this.printSlaDefinition(sld));//Pull out the field namesvar flds = this.getSlaConditions(sld);out.push("fields from conditions: " + flds.join());//Print information about the SLA schedule SKIPPED//Get group of task_sla recordsvar slt = new GlideRecord("task_sla");slt.addQuery("sla",sld.sys_id+"");slt.addQuery("sys_created_on","<",gs.daysAgoStart(1));if (filters)for (var iz = 0; iz < filters.length; iz++)slt.addQuery(filters[iz].field, filters[iz].operator, filters[iz].value);slt.orderByDesc("sys_created_on");slt.setLimit(tests);slt.query();//For each task_slaid = 0;while(slt.next()) {out.push("\n*******" + ++id + "*******");out.push(this.getSlaTimeline(slt, flds));}}return out.join("\n");},
printSlaDefinition : function(contract) {var out = [];var sldFlds = ['name', 'workflow', 'collection', 'duration', 'duration_type', 'retroactive', 'set_start_to', 'schedule', 'timezone', 'type', 'start_condition', 'stop_condition', 'pause_condition', 'reset_condition'];for (var ia = 0; ia < sldFlds.length; ia++)out.push("contract_sla." + sldFlds[ia] + ": " + contract[sldFlds[ia]]);return out.join("\n");},
getSlaConditions : function(contract) {var conds = ['start_condition', 'stop_condition', 'pause_condition', 'reset_condition'];var flds = [];for (var ib = 0; ib < conds.length; ib++) {var cond = contract[conds[ib]].split("");for (var ic = 0; ic < cond.length; ic++) {var fld = cond[ic].split(/[a-z_]/)[0];if (fld) flds.push(fld);}}return flds;},timeline : {_timeline : [],sort : function() {return this._timeline.sort();},push : function(value) {var i = this._timeline.length;
while(i--) if (this._timeline === value) return;this._timeline.push(value);},join : function(delim) {return this._timeline.join(delim);},reset : function() {this._timeline = new Array();}},getSlaTimeline : function(sla, condFlds) {//var timeline = [];var fields = [];if (typeof sla == "string") {var sltask = new GlideRecord("task_sla");sltask.get(sla);sla = sltask;fields.push(this.printSlaDefinition(sla.sla));} else if (!sla) return;if (!condFlds) condFlds = this.getSlaConditions(sla.sla);//Print task information (retroactive value, any field in conditions...)if (sla.task) {var taskRec = new GlideRecord("task");taskRec.addQuery("sys_id",sla.task+"");taskRec.query();if (taskRec.next()) {var tFlds = ['sys_id','number',sla.sla.set_start_to];for (var ih = 0; ih < tFlds.length; ih++)fields.push("task." + tFlds[ih] + ": " + sla.task[tFlds[ih]]);//Add task information to timeline (sys_created_on, sys_updated_on...)for (var ii = 0; ii < condFlds.length; ii++) {//Query audit tables for all field names from the conditions list ordered by Created Onvar aud = new GlideRecord("sys_audit");aud.addQuery("documentkey",sla.task.sys_id+"");aud.addQuery("fieldname",condFlds[ii]);aud.orderBy("sys_created_on");aud.query();if (aud.getRowCount() == 0) this.timeline.push(sla.task.sys_created_on + " Orig " + condFlds[ii] + ": " + sla.task[condFlds[ii]]);while(aud.next()) {this.timeline.push(aud.sys_created_on + " Task " + aud.fieldname + " old:" + aud.oldvalue + " new:" + aud.newvalue);}//Add audit information to timeline}} else {//bad referencefields.push("ERROR: task is a bad reference");}}//Print task_sla informationvar sFlds = ['sys_id','task','start_time', 'end_time', 'planned_end_time', 'duration', 'percentage', 'pause_time', 'pause_duration', 'stage', 'has_breached', 'sys_created_on', 'sys_updated_on'];for (var ie = 0; ie < sFlds.length; ie++)fields.push("task_sla."+sFlds[ie] + ": " + sla[sFlds[ie]]);//Add task_sla information to timeline (start_time, end_time, planned_end)var tlFlds = ['start_time', 'end_time', 'pause_time', 'planned_end_time', 'sys_created_on', 'sys_updated_on'];for (var ig = 0; ig < tlFlds.length; ig++)this.timeline.push(sla[tlFlds[ig]] + " SLA " + tlFlds[ig]);//Query wf_context for this task_slavar wf = new GlideRecord("wf_context");//Print wf_context infowf.addQuery("id",sla.sys_id+"");wf.query();//Query all Activities in the wf_contextwhile(wf.next()) {fields.push("wf_context.name: " + wf.name);fields.push("wf_context.started: " + wf.started);fields.push("wf_context.ended: " + wf.ended);//Add Activity start/end to timelinevar wfe = new GlideRecord("wf_history");wfe.addQuery("context",wf.sys_id+"");wfe.query();while(wfe.next()) {this.timeline.push(wfe.started + " WF " + wfe.activity.name + " (activity) began");this.timeline.push(wfe.ended + " WF " + wfe.activity.name + " (activity) ended");}}var slaTimeline = fields.join("\n") + "\n**Timeline (GMT)**\n" + this.timeline.sort().join("\n");this.timeline.reset();return slaTimeline;}}}
NOTE: I've also attached this as a file to this blog post for download
Gotcha's
Here's a collection of some of the most common mistakes I see.
Duplicate Workflows
SLA Workflows get kicked off when Conditions from the SLA Definition (contract_sla table) match. This means you don't need to have the workflow set up to Run If... If you do set up the Workflow to Run If then you'll get duplicate Active Workflow Contexts.
Retroactive Start Time set to Weird Values
Setting a Retroactive Start time means that at the time of Task SLA (task_sla) creation the Start Time field will be set to some field from the Task record. Task SLAs get started when a Task gets Updated. So if you set the Retroactive Start time to Updated On then you might as well not set it to anything! Also, retroactive start time has some caveats. Check out the Wiki's explanation of prior pause time. In June there were also issues discovered with workflow timers not working correctly with retroactive SLAs and Schedules.
Relative Duration
The biggest thing here is to understand that Relative Duration does not work with Pause Time. To avoid confusion we now hide the Pause Condition field on Relative Duration SLA Definitions. The next biggest thing to understand is the the "current" object is not supported in the scripted section of a Relative Duration. If you use it you will get results, but they will not be consistent. This means that you can not use Relative Duration SLAs to design an SLA that will have a different duration depending on some value on the Task record.
Calculate on Display
I already mentioned this earlier, but it's worth repeating. Setting the Calculate on Display Property means that every time a user views a Task record the calculations of the SLAs in the Related List will be updated. It does NOT mean that every time a Task SLA record is viewed it's calculations will be updated.
Regards, Matthew Watkins
* ServiceNow tracks most customizations to configuration records in your system. During the next upgrade, any changes that would otherwise be applied to configuration records that have been altered will be SKIPPED. You should make sure to check the Upgrade History module to see if any updates have been skipped and merge or overwrite the custom code with the new ServiceNow changes. If you want to know more about this, check the following WIKI articles:
Tracked Customizations in Update Sets
What about you? What are some techniques you use to troubleshoot SLAs? What are some gotchas you've discovered?
https://www.servicenow.com/community/in-other-news/troubleshooting-slas/ba-p/2293703