This program collects Navigation Timing API data and Javascript errors and forwards the information along to the specified recorders (like StatsD or Logstash).
The JSON structure the /nav-timing
endpoint expects is:
{
"page-uri": "/foo/bar",
"nav-timing": {
"dns":1,
"connect":2,
"ttfb":3,
"basePage":4,
"frontEnd":5
}
}
Javascript that will send this information can be as simple as the following:
<script type="text/javascript">
window.onload = function() {
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
if (window.performance && window.performance.timing) {
var timing = window.performance.timing;
var stats = {
'page-uri': window.location.pathname,
'nav-timing': {
dns: timing.domainLookupEnd - timing.domainLookupStart,
connect: timing.connectEnd - timing.connectStart,
ttfb: timing.responseStart - timing.connectEnd,
basePage: timing.responseEnd - timing.responseStart,
frontEnd: timing.loadEventStart - timing.responseEnd
}
};
if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST", window.location.origin+"/nav-timing", true);
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.send(JSON.stringify(stats));
}
}
};
</script>
The page-uri
will be converted into the appropriate format for the recorder and the stat pushed to that recorder.
The JSON structure the /js-error
endpoint expects is:
{
"page-uri": "fizz/buzz",
"query-string": "param=value&other=not",
"js-error": {
"error-type": "ReferenceError",
"description": "func is not defined"
}
}
Javascript that collects and sends this information can be as simple as the following:
<script type="text/javascript">
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
window.onerror = function globalErrorHandler( errorMessage, url, lineNumber, charPos, errorObj ) {
var errorStats = {
'page-uri': window.location.pathname,
'query-string': window.location.search,
'js-error': {
'error-type': errorObj.name,
'description': errorObj.message
}
};
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", window.location.origin+"/js-error", true);
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.send(JSON.stringify(errorStats));
}
return false;
};
</script>
This will run tests as well.
make all
make run
If you want to test the running system, you'll need to send it some stats. Send it this for Navigation Timing:
curl -d '{"page-uri": "/foo/bar", "nav-timing":{"dns":1,"connect":2,"ttfb":3,"basePage":4,"frontEnd":5}}' -H "X-Real-Ip: 192.168.0.1" http://localhost:8080/nav-timing
And this for JS Error reporting:
curl -d '{"page-uri": "/foo/bar", "query-string": "?param=true", "js-error":{"error-type": "ReferenceError", "description": "func is not defined"}}' -H "X-Real-Ip: 192.168.0.1" http://localhost:8080/js-error
make cover
- Create ability to specify a whitelist nav-timing page-uris
- Write regex for StatsD validStat