Logmatic.io Blog

Practical RUM Website Monitoring
using W3C Performance API

Our step-by-step tutorial for website Real User Monitoring

This post is part of the Real User Monitoring series on our blog. Read more on how to build your RUM strategy, web app performance with Boomerang.js library or our User tracking day-to-day use cases if you’re interested in further Real User Monitoring specifics.

When talking about app performance monitoring, two separate areas will emerge. Some metrics are application-related while others are users-related, or RUM. Classic application monitoring is about the first one, trying to get a global view of your application performance, usually from your own server side perspective. RUM has a more detailed approach that aims to capture and analyze every transaction from every real end user of your application. Real User Monitoring can help you answer two categories of questions: application performance and usability.

Application performance metrics answer questions such as the following.

  • How long do the assets of my web pages take to load? Which ones exactly are responsible for the slowness experienced by users? Are there any script slowing down my website? (like ad banners for instance)
  • What profiles (browser, geography, …) impact your application to load more slowly?

Before diving in all these Real User Monitoring questions, keep in mind that both RUM and more classical monitoring are important when you want to understand how your application (or business) perform!

As I’ve been working on a Real User Monitoring project for the last couple of weeks, I will share here how to collect and track the most important metrics for a healthy RUM foundation for the application performance category. It’s really about getting the basics right, and the answers to questions that I believe every developer should be able to answer in minutes.

rum geomap

They are actually different ways to extract the data we’re interested in from client browsers. As for myself, I’ve been working on integrating RUM library (called Boomerang.js) with Logmatic.io – more about it in the blogpost Smashing Web App Performance. But to serve a more general purpose, I’ve chosen to detail here the more generic way to grab metrics & KPIs by using the browser’s native API.

Let’s get coding.

I. RUM metrics with W3C Performance API

1) W3C Timing API: retrieve web page load time

The timing API enables us to answer our first RUM questions “How long do the assets of my web pages take to load?” and “Which ones exactly are responsible for the slowness experienced by users?”. It describes in great details page loading. You will be able to know how long network redirection, dns resolution or page rendering time took. By taking “LoadEventEnd” minus ”navigationStart” you get the total load time. Indeed “LoadEventEnd” means your page has been entirely loaded and rendered, and that each callback attached to the “domLoaded” event has been processed.

Want to have a look at it? Copy paste the following code to your browser console:


var timing = performance.timing;
var bench = timing.loadEventEnd – timing.navigationStart
console.debug(“Page processed in ” + bench + ” ms”);

It’s a good start! We’ve just computed the main RUM performance metric: you know how long it takes to load any page on your webapp our websites. (We still don’t know how to ship it to you but that comes later). Now you’re probably asking yourself “how can I explain why those pages are slow?” That’s where the getEntries() function comes in.

2) Entries API: find your slowest web page assets

The timing API has been augmented with the Entries API for detailed reporting of each asset load time. So now, you’re actually able to answer to the question and which are the assets responsible for slowness.
Copy the following into any of your webpage’s console to have a look at it:


var entries = performance.getEntries();
// sort by duration (DESC)
entriesSorted = entries.sort(
function (a,b) {
a.realDuration = a.responseEnd – a.startTime;
b.realDuration = b.responseEnd – b.startTime;
return b.realDuration – a.realDuration
});
var toString = function(entry) {


var prettyString = “Asset ‘” + entry.name;
prettyString += “‘ (” + entry.initiatorType;
prettyString += “) processed in ” + entry.realDuration + ” ms”;
return prettyString;
}
entriesSorted.forEach(function(entry) {
console.debug(toString(entry))//, entry);
});

And here is what you should get:

rum code

Still fancy some more information? Ok… You probably have specific needs. And that’s something the W3C though about: add your own timers with the User Timing API.

3) User Timing API: insert custom web page timers

The Use Timing API simplifies timers management and lets you insert some markers in your code to measure time elapsed. The ‘mark()’ method is its main function and can store both a timestamp and label for you. Calling mark() at various places in your application lets you instrumentalize the behavior and the actions of users.

For example, set a mark when the application is fully loaded – including some async call:

performance.mark(‘app_loaded’);

Setting a label (‘app_loaded’) for the mark allows you to do measures. So, once you’ve set a bunch of marks, use the ‘measure()’ method to retrieve timers. The measure(,,) method calculates the elapsed time between marks. It can also measure time elapsed between your mark and any of the well-known event names in the Performance Timing API.

When you call the measure method, its result is stored to be re-used later. Storing away times as your application runs allows for your application to remains responsive. Once your application has finished its work, you can dump all the times data and consume resources while they’re not needed anymore.

Want to have a try? Let’s measure how fast google.com answers. Simply copy paste the following code into your console browser:


var xhr = new XMLHttpRequest();
xhr.open(‘GET’, “https://google.com”, true);
xhr.onload = function(e) {
performance.mark(‘track_end_xhr_google’);
performance.measure(‘measure_xhr_google’, ‘track_start_xhr_google’, ‘track_end_xhr_google’);
console.debug(performance.getEntriesByName(“measure_xhr_google”));
}


performance.mark(‘track_start_xhr_google’);
xhr.send();

The result came up with 285.004 milliseconds for me:

rum results

Now that your application is monitored and a bunch of marks have been added, you can retrieve your timers by simply using the ‘getEntriesByType()’ or ‘getEntriesByName()’ methods.

If you want to get markers, use:

performance.getEntriesByType(‘mark’);

As for measures, use:

performance.getEntriesByType(‘measure’);

And, sure you get a specific marker or the measure directly by its label:


performance.getEntriesByName(‘app_loaded’);

At this point you are able to track the main performance metrics from any webpage, plus technically speaking, it can run over all your users browsers. Now you need a way to ship them back to you with some context.

II. Ship RUM metrics back to you

1) Navigator API : gather your contextual attributes

Before actually going into shipping details, get some context information, such as username or email (if you have some), user-agent, ip address, and other information useful to you.

The Navigator API can help you with some of this contextual information. Just try to type in a browser console:
console.debug(navigator);

Don’t underestimate this API. It’s actually fantastic: you can retrieve geolocation, screen size, battery level, etc… So I’m pretty sure you’ll find what you’re looking for here.

2) Ship your RUM web page events: a bounty of options

They are plenty of options to ship these events back to you. The important thing to know is: you need to find a way to store them and analyze them easily if you want to really get to the value out of your data. Of course, we have our own solution to deal with it at Logmatic.io. Our logmatic-js project on Github has been designed to solve this shipping issue. You can have a quick look but here is how it works:

  • You add the minified script on your pages (available on bower.io or NPM)
  • You initialize it and tell it where you want your events to go
  • You replace all your console.log by logmatic.log(,)
  • You get context information as JSON objects that will be attached with the main messages
  • You get events batched together so it minimizes the number of calls to your server

Once in Logmatic.io you’re able to explore all this data and do all the analytics you want. And have the beautiful and clickable dashboards you are dreaming of.

Let’s conclude!

I hope you learnt some basics about the main performance routines you have for free in any modern browser. By the way, here are the compatibility table as everything I said above is only true if it is present:

rum browser

Next time, I am going to focus on the Boomerang.js to see how we can handle single page application performances (Angular.js, Backbone.js, etc..).

Cheers!

Related Posts