Adam Stout
ServiceNow Employee

Identifying Impactful Slow Reports

Want to look good and make your users happy? Fix or get rid of the performance hog reports that cause poor UX and then get ready for smiling users.

But how do you figure out which reports are the most impactful to performance? You may have 1,000 reports, you may have 10,000 reports, you may even have 50,000 reports on your instance... where should you focus your attention?

Let’s dig into what we can to track report performance.

[If you are looking to track Dashboard Usage, check out this blog.]

Out of the Box Report Statistics

Report Statistics is a great place to start. Out of the box, the report_stats table gives you a quick way to access how long reports are taking to load, and when the last time they were viewed.

find_real_file.png

The report_stats table is great to be able to identify your long-running reports that have been run recently and have seen a lot of activity in their lifetime. The Report field is a reference to sys_report so you can dot-walk to any report attribute you need (for example, filtering to incident tables or HR tables).

Report Statistics are active by default, and no customization is needed to take advantage of this great resource to help you focus on the reports that need it.

Tracking Individual Views

Report Statistics is a great start, but sometimes we need to know more about the usage of reports. For instance, we want to know not only that a report was run recently, but we want to know who viewed it. We want to know not just that it is run a lot, but how many times it has been run recently.

To track usage at this level, we need to build on the out of the box capabilities to store this info.

Creating a Table

Note: Creating a table may have licensing implications depending on your contract. If you have questions about this, contact your account representative.

I created a scoped application to hold the objects we need named x_snc_aoa. I want to track both report views and Performance Analytics widget, so I created three tables.

  • x_snc_aoa_use – This the base table for my usage tracking
  • x_snc_aoa_report_use – Extends use and tracks the report (and anything specific to reports)
  • x_snc_aoa_widget_use - Extends use and tracks the widgets (and anything specific to widgets)

 find_real_file.png.  find_real_file.png find_real_file.png

Populating the Tables

Now that we have my tables, we need to populate them. To do this, we are taking advantage of the awesomeness of the Now Platform. When reports and widgets are viewed, there is an Event created named “report.view”.

This event gives us:

  • Report (Instance)
  • User (User ID)
  • Load Duration (Param1)
  • Dashboard tab or homepage (Param2)
  • View time (Created time)

find_real_file.png 

To process this event, we need a Script Action. There is already a Script Action to populate the report_stats records so we will add one.

find_real_file.png 

Here is the script I used in my script action.  You may need to adjust to fit your specific requirements.  As always, be sure to test this in your environment before using it.

(function(event) { 
    var userSysId = event.user_id; 
    var executionTimestamp = event.sys_created_on; 
    var executionDuration = event.parm1; 
      
    // homepage and widget sys id are passed in parm2 as <homepage>/<widget>  
    var parm2 = (event.parm2) ? event.parm2.split('/') : []; 
    var homepageSysId = (parm2.length > 0) ? parm2[0] : null;    
    var widgetSysId = (parm2.length > 1) ? parm2[1] : null; 
    var isScheduledRun = (parm2.length > 2) ? parm2[2] : null; 
    var bIsScheduledRun = isScheduledRun != null && isScheduledRun === 'true' ? true :  false; 
   var repLog = null; 
    if(event.table == 'pa_widgets') 
    { 
    repLog = new GlideRecord('x_snc_aoa_widget_use'); 
        repLog.setValue('widget', event.instance); 
    } else { 
    repLog = new GlideRecord('x_snc_aoa_report_use'); 
        repLog.setValue('report', event.instance); 
        repLog.setValue('widget', widgetSysId); 
    } 
    repLog.setValue('user', userSysId); 
    repLog.setValue('load_duration', executionDuration); 
    repLog.setValue('viewed', executionTimestamp); 
    repLog.setValue('homepage', homepageSysId); 
    repLog.setValue('scheduled', bIsScheduledRun); 
    repLog.insert(); 
}(event)); 

Data Hygiene

Depending on the size of your instance, this data can grow quickly. To ensure it doesn’t get out of hand and cause issues on your instance, be sure to create a table cleaner to purge the data.

I created one to remove data over six months. You may need to adjust this setting depending on data volume. Table rotation may be an acceptable option as well.

find_real_file.png

Use the Data

Now that we have the data in our tables, there is a lot we can do. I built a quick dashboard that lets me look at where are the top reports based on any of the report attributes.

find_real_file.png

We can use the attributes from reports and users (I used the user as an example here) to zoom in to what they are viewing.

find_real_file.png 

With this data, we can create reports on:

  • Reports getting slower over time
  • Which departments are viewing specific reports
  • Are users visiting reports at expected intervals
  • Top (specific) report consumers to consult before changes are made
  • Users experiencing long load time (key when some users have different performance profiles)
  • Quite a few more...

Once we have something we want to focus on, we can apply Performance Analytics to this data as well to trend our usage KPIs over time to help us drive greater adoption and performance of our analytics.

Let’s Go!!!

Now that you know how to do this, do it. Start tracking this data as soon as possible. Since we leverage events, you can’t get it historically once the events are deleted from the instance.

What are the key things do you focus on? Leave me a comment about what analytics you built on this data.

6 Comments
Drew Black
Tera Contributor

@Adam Stout 

This looks like a good idea with valuable data. We are trying to implement this in our environment, but finding some issues. Some of it could be that this is a 2 yr old post and some things may have changed in that time. Rome is our target version at the moment.

  • The Report Use screenshot does not indicate that a Widget field should be added, but the code shows a Widget field being populated by the widgetSysId variable.  So far, that field is never populated on my report table.

  • The code processes Parm2 in multiple ways.  One of which is grabbing the homepage and widget ids on a PA Widget.  The event Parm2 would be in this format '<homepage>/<widget>' as stated in the code. However when I look at our events, I am instead getting '/<widget>'.  The event has no homepage id and only displays the widget id. Therefore the homepage is never populated on the Widgets table.

  • When looking at certain dashboards, there may be one or more reports which are captured as having no homepage, even though they are clearly on the dashboard. Position does not seem to matter.

  • Scheduled reports were interesting.  The code is correct when a scheduled report is run vs. running the report manually.  However I was curious about the times. The report returned one row so it was very fast. It has 0 for the time when ran scheduled.  It had a little over 1.1 seconds when I ran the report manually.  Do the times take into account rendering visual elements?

This looks very interesting and I can certainly see some improvements that I would make to it, but until the gaps are filled in, I'm not sure it will be viable for us just yet.

Faisal Shaikh
Tera Contributor

@Adam Stout - Thanks for posting the solution. I'd like to know if this item is part of the roadmap for standard OOTB offering? 

I want to prevent customization in our instance if this item will be rolled out in near future. 

malaisamyj
Tera Contributor

@Adam Stout :

 

This works fine with reports & Widgets.

 

what if dashboard is made of custom components like dynamic content page, UI Widget which contains UI pages likewise

SRB21
Tera Explorer

Great article!

DhanalakshmY
Tera Contributor

Iam able to replicate it.Thanks

Praseena1
Tera Explorer

Where can I create the event? Should it be in the event registry?