Skip to content

lanyonm/http-stats-collector

Repository files navigation

http-stats-collector Build Status Coverage Status

This program collects Navigation Timing API data and Javascript errors and forwards the information along to the specified recorders (like StatsD or Logstash).

Navigation Timing

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.

Javascript Errors

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>

Building

This will run tests as well.

make all

Running

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

Test Coverage

make cover

TODO

  • Create ability to specify a whitelist nav-timing page-uris
  • Write regex for StatsD validStat