“Great things are done by a series of small things brought together.”
— Vincent Van Gogh
The one property of a ServiceNow Event that we virtually skipped over last time was the additional_info property. This is pretty much a catch-all for any other thing that you might want to record along with the Event itself. The additional_info property is stored in the database as a JSON-formatted string, which you can instantiate in use and then access like any other Javascript object. By leveraging the additional_info property, we can inject standard elements into the Event so that the reporting module does not have to include the code to provide that information. One such bit of info could be details on the currently logged on user. Another might be a Stack Trace containing the details of how we arrived at the point of an Event occurring.
The one thing that we would not want to do, however, would be to overlay any information that the reporting entity has provided, so it will be important to first check for the presence of any data in the additional_info object before we set any values of our own. The first thing that we would have to do would be to check to see if an additional_info value was even provided, and that it was an object to which we could add additional values. Here is one way to approach such a check:
if (additional_info) {
if (typeof additional_info != 'object') {
additional_info = {info: additional_info};
}
} else {
additional_info = {};
}
This ensures that we have an object, and that we have preserved whatever non-object (string, boolean, number,etc.) values that may have been provided instead of an object. Once we know we have an object to work with, then we can check the object for other properties, and if not already provided, provide a standard value. For example, here is how we could potentially include the various details on the user:
if (!additional_info.user) {
additional_info.user = {};
additional_info.user.sys_id = gs.getUserID();
additional_info.user.id = gs.getUserName();
additional_info.user.name = gs.getUserDisplayName();
}
Injecting a Stack Trace could be handled in a similar fashion:
if (!additional_info.stackTrace) {
additional_info.stackTrace = this.getStackTrace();
}
Of course, a server side Stack Trace is of little value if your issue is a client side Event, so you would probably want to snag a client side Stack Trace while you were on the client side, before you sent everything over to the server side to be reported. We can steal some of the code from our server side counterpart to enhance the client side function and turn it into something like this:
logEvent: function(source, resource, metric_name, severity, description, additional_info) {
if (additional_info) {
if (typeof additional_info != 'object') {
additional_info = {info: additional_info};
}
} else {
additional_info = {};
}
if (!additional_info.stackTrace) {
additional_info.stackTrace = this.getStackTrace();
}
var ga = new GlideAjax('ServerEventUtil');
ga.addParam('sysparm_name', 'logClientEvent');
ga.addParam('sysparm_source', source);
ga.addParam('sysparm_resource', resource);
ga.addParam('sysparm_metric_name', metric_name);
ga.addParam('sysparm_severity', severity);
ga.addParam('sysparm_description', description);
ga.addParam('sysparm_additional_info', JSON.stringify(additional_info));
ga.getXML();
}
By creating a common Event reporting utility function and leveraging the additional_info property for specific selected values, virtually all of the Events reported by ServiceNow components can share a common set of properties. This creates opportunities for common Event processing scripts and generic reporting possibilities that would not exist if everyone were simply following their own unique approach to reporting Events. And once you establish an organizational standard for common values stored in the additional_info property, adding additional items of interest at a future point in time is simply a matter of updating the common routine that everyone calls to report Events.
We still need to put together that testing page that we talked about last time out, but at this point, I think that will have to be a project for another day …
Update: There is an even better version here.