Add Instrumentation
Configuration
The 'Add Instrumentation' filter is enabled by specifying:
- Apache:
ModPagespeedEnableFilters add_instrumentation
- Nginx:
pagespeed EnableFilters add_instrumentation;
in the configuration file.
Description
The 'Add Instrumentation' filter injects two small blocks of JavaScript into every HTML page. These blocks measure the time the client spends loading and rendering the page, and report that measurement back to the server.
Operation
An empty HTML file passed through the add_instrumentation filter will come out like this (the inserted whitespace is for documentation readability):
<html> <head> <script type='text/javascript'> window.mod_pagespeed_start = Number(new Date()); </script> </head> <body> <script type='text/javascript'> function g(){ new Image().src = '/mod_pagespeed_beacon?ets=load:' + (Number(new Date())-window.mod_pagespeed_start); }; var f = window.addEventListener; if (f) { f('load',g,false); } else { f=window.attachEvent; if (f) { f('onload',g); } } </script> </body> </html>
Example
You can see the filter in action at www.modpagespeed.com
on this
example.
Methodology
The first script tag is inserted at the beginning of the document's
<head>
. It simply records the current time in a global
variable. This is placed as early in the document as possible in order to
best approximate the beginning of the page load.
The second script tag is inserted at the end of the document's
<body>
, so as to minimally interfere with page rendering.
It registers a listener for the page's onLoad event; this listener computes
the total time since the first script tag ran, and sends the result back
to the server asynchronously by using a fake Image object. This technique
should work on most modern browsers.
[1].
The add_instrumentation filter sends a beacon after the page onload
handler is called. The user might navigate to a new URL before this. If you
enable the following directive, the beacon is sent as part of an
onbeforeunload
handler, for pages where navigation happens before
the onload
event.
- Apache:
ModPagespeedReportUnloadTime on
- Nginx:
pagespeed ReportUnloadTime on;
"/mod_pagespeed_beacon"
(Apache)
or "/ngx_pagespeed_beacon"
(Nginx). PageSpeed handles these
results itself and simply returns "204 No Content"
which should
cause minimal disruption for the client. It also records the number of
callbacks, and the total of their onLoad times, in the statistics
"page_load_count"
and "total_page_load_ms"
. These are
visible on the PageSpeed statistics page (which, by default, is only viewable
from the server's localhost). You can divide
total_page_load_ms
by page_load_count
to get the
average onLoad time for your site.
You can change the location of the beacon to a different path (or even a
different server) using the BeaconUrl
directive. For example:
- Apache:
ModPagespeedBeaconUrl "/my/path/to/beacon"
- Nginx:
pagespeed BeaconUrl "/my/path/to/beacon";
Or, if you want to set up your own beacon server somewhere else, you can use:
- Apache:
ModPagespeedBeaconUrl "http://my.other.server/my_beacon"
- Nginx:
pagespeed BeaconUrl "http://my.other.server/my_beacon";
If you want to set an https beacon URL that is different from the http beacon URL (for example a different machine as shown below, or a non-default port), you can do so by separating the http and https URLs with a space. You don't need to do this if the beacon URLs only differ in protocol (http versus https):
- Apache:
ModPagespeedBeaconUrl "http://insecure.server/my_beacon https://secure.server/my_beacon"
- Nginx:
pagespeed BeaconUrl "http://insecure.server/my_beacon https://secure.server/my_beacon";
Note that the BeaconUrl used to require that custom beacon URLs end
with "?ets="
. Appending the query param to the custom URL is no
longer required and should be removed if present.
If you want more detailed information about client load time (e.g. averages for different pages and different browsers, median times, historical behavior, etc.) you can get this information from your webserver logs. Every beacon load will be in your access.log along with the timestamp, referer, IP address, and user-agent—which tell you when, where, and by whom the onLoad measurement was taken. There are some existing tools to collect and analyze these data; one such example is Jiffy.
Requirements
The "Add Instrumentation" filter requires the "Add Head" filter, and will enable it automatically.
Risks
This filter could break pages if they include JavaScript which depends on
knowing the first child of the <head>
or the last child
of the <body>
.
The injected JavaScript is very lightweight, and should cause only a very tiny (though nonzero) amount of extra load on the client.
If you already have a client-side latency measurement system in place (such as Jiffy, Episodes, or Boomerang), you probably don't need this filter.
Note that the data reported by this filter is only approximate and does not include time the client spends resolving your domain, opening a connection, and waiting for the first few bytes of HTML.
References
- Zakas, Nicholas C., High Performance JavaScript. O'Reilly, 2010, p133.