Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Commit

Permalink
Initial commit of tracking ajax requests
Browse files Browse the repository at this point in the history
  • Loading branch information
avanderhoorn committed Jun 6, 2017
1 parent e4dbcbd commit 77debb3
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 36 deletions.
15 changes: 15 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"files.exclude": {
"**/.git": true,
"**/.archive": true,
"**/.dist": true,
"**/.cache": true
},
"editor.tabSize": 4,
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"prettier.printWidth": 100,
"prettier.tabWidth": 4,
"prettier.singleQuote": true,
"prettier.jsxBracketSameLine": true
}
41 changes: 41 additions & 0 deletions fake/fake-ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const chance = require('./fake-chance').instance;

// proxy event listener to make testing easier
XMLHttpRequest.prototype.addEventListener = function(type, callback) {
if (type == 'readystatechange') {
const currentStatus = chance.httpStatus();

const newThis = {
getResponseHeader: this.getResponseHeader,
readyState: 4,
status: currentStatus.code,
statusText: currentStatus.text
};

callback.call(newThis);
}
};
XMLHttpRequest.prototype.getResponseHeader = function(type) {
if (type === 'Content-Type') {
return chance.httpContentType().type;
}
else if (type === 'X-Glimpse-ContextId') {
return chance.guid();
}
else if (type === 'Content-Length') {
return chance.integerRange(1000, 5000);
}
};
XMLHttpRequest.prototype.send = function() {};

// generate requests on a schedule
function spawnRequest() {
setTimeout(function() {
const httpRequest = new XMLHttpRequest();
httpRequest.open(chance.httpMethod(), chance.httpPath(), true);
httpRequest.send();

spawnRequest();
}, chance.integerRange(1000, 5000));
}
spawnRequest();
47 changes: 47 additions & 0 deletions fake/fake-chance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const Chance = require('chance');

const chance = new Chance();
const urls = [ '/news/latest', '/news/item/123', '/news/item/453', '/news/item/add', '/news/item/remove' ];
const methods = [ 'GET', 'GET', 'GET', 'GET', 'POST', 'POST', 'POST', 'PUT', 'PUSH', 'DELETE' ];
const statuses = [ 100, 200, 200, 200, 200, 200, 200, 404, 404, 403, 403, 500, 304 ];
const statusText = { 200: 'OK', 404: 'Not Found', 500: 'Server Error', 304: 'OK', 403: 'Error' };
const protocols = [ 'http', 'http', 'https' ];

chance.mixin({
'integerRange': (min, max) => {
return chance.integer({ min: min, max: max });
},
'durationRange': (min, max) => {
return chance.floating({ min: min, max: max, fixed: 2 });
},
'dateRange': (min, max) => {
const time = new Date().getTime();
const difference = chance.integerRange(min, max);
const newTime = new Date(time + difference);

return newTime;
},
'httpPath': () => {
return chance.pickone(urls);
},
'httpMethod': () => {
return chance.pickone(methods);
},
'httpStatus': () => {
var code = chance.pickone(statuses);
return {
code: code,
text: statusText[code]
};
},
'httpContentType': () => {
return { type: 'text/html', category: { 'document': true } };
},
'httpProtocol': () => {
return chance.pickone(protocols);
},
});

module.exports = {
instance: chance
};
13 changes: 0 additions & 13 deletions fake/fake-request-service.js

This file was deleted.

4 changes: 1 addition & 3 deletions fake/fake.js
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
'use strict';

require('./fake-request-service');
require('./fake-ajax');
23 changes: 15 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

// DEV TIME CODE
if (FAKE_SERVER) {
require('fake');
Expand All @@ -11,27 +9,36 @@ require('./index.scss');
var versionView = require('./views/version');
var openView = require('./views/open');
var timingView = require('./views/timing');
var ajaxView = require('./views/ajax');

function renderHud(pageLoadTime) {
const versionIcon = versionView.render();
const openIcon = openView.render();
function render() {
const versionComponent = versionView.render();
const openComponent = openView.render();
const timingComponent = timingView.render();
const ajaxComponent = ajaxView.render();

return `
<div class="glimpse-hud">
${versionIcon}
${openIcon}
${versionComponent}
${openComponent}
${timingComponent}
${ajaxComponent}
</div>
`;
}

function postRender() {
ajaxView.postRender();
}

let timeout = 1;
const onTimeout = () => {
if (document.readyState === 'complete') {
const container = document.createElement('div');
container.innerHTML = renderHud();
container.innerHTML = render();
document.body.appendChild(container);

postRender();
}
else {
setTimeout(onTimeout, timeout *= 2);
Expand Down
25 changes: 21 additions & 4 deletions src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,41 @@
color: inherit !important;
}
}
.glimpse-timing {
.glimpse-section {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
padding: 0 15px !important;
background-color: rgba(0, 0, 0, 0.85) !important;
border-left: 1px solid #999 !important;

&:first-child, // NOTE: this should work but isn't
&.glimpse-section--first {
border-left: none !important;
}
}
.glimpse-timing-duration {
.glimpse-section-duration {
position: relative !important;
font-size: 20px !important;
margin-left: 5px !important;
margin-right: 1px !important;
top: -2px !important;
font-weight: 600 !important;
}
.glimpse-timing-label,
.glimpse-timing-suffix {
.glimpse-section-label,
.glimpse-section-suffix {
color: #999 !important;

&.glimpse-section-suffix--text {
padding-left: 2px !important;
}
}
.glimpse-section-value {
transition: color 0.5s ease-in-out;

&.glimpse-section-value--update {
color: #39f !important;
}
}
.glimpse-icon {
display: flex !important;
Expand Down
23 changes: 23 additions & 0 deletions src/lib/dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = {
hasClass: function(el, className) {
return el.classList
? el.classList.contains(className)
: new RegExp('\\b' + className + '\\b').test(el.className);
},
addClass: function(el, className) {
if (el.classList) {
el.classList.add(className);
}
else if (!hasClass(el, className)) {
el.className += ' ' + className;
}
},
removeClass: function(el, className) {
if (el.classList) {
el.classList.remove(className);
}
else {
el.className = el.className.replace(new RegExp('\\b' + className + '\\b', 'g'), '');
}
}
}
6 changes: 4 additions & 2 deletions src/lib/util.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

var UriTemplate = require('uri-templates');
var usedMessageTypes = function() {
return 'environment,user-identification,web-response,web-request,after-action-invoked,after-action-view-invoked,before-execute-command,after-execute-command,after-view-component';
Expand Down Expand Up @@ -34,5 +32,9 @@ module.exports = {

var uri = contextTemplate.replace('{contextId}{&types}', params); // TODO: This should probably be resolved with a URI Template library
return encodeURI(uri);
},
isLocalUri: function(uri) {
return uri && (!(uri.indexOf('http://') == 0 || uri.indexOf('https://') == 0 || uri.indexOf('//') == 0) ||
(uri.substring(uri.indexOf('//') + 2, uri.length) + '/').indexOf(window.location.host + '/') == 0);
}
};
76 changes: 76 additions & 0 deletions src/views/ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const util = require('../lib/util');
const dom = require('../lib/dom');

let count = 0;
let ready = false;
let preRenderCache = [];
let currentTimout = undefined;

function update(method, uri, duration, size, status, statusText, time, contentType, requestId) {
count++;

//manage counter value
var counter = document.getElementById('glimpse-ajax-count');
counter.innerText = count;
dom.addClass(counter, 'glimpse-section-value--update');
if (currentTimout) {
clearTimeout(currentTimout);
}
currentTimout = setTimeout(function() {
dom.removeClass(counter, 'glimpse-section-value--update');
}, 2000);
}

const open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, uri) {
if (util.isLocalUri(uri) && uri.indexOf('/glimpse/') == -1) {
const startTime = new Date().getTime();
this.addEventListener('readystatechange', function() {
if (this.readyState == 4 && this.getResponseHeader('X-Glimpse-ContextId')) {
// if we can render the data do so, otherwise save for later
if (ready) {
listenerNotification(method, uri, startTime, this);
}
else {
const xhrObj = this;
preRenderCache.push(function() {
listenerNotification(method, uri, startTime, xhrObj);
});
}
}
}, false);
}

open.apply(this, arguments);
};

function listenerNotification(method, uri, startTime, xhrObj) {
update(method, uri, new Date().getTime() - startTime, xhrObj.getResponseHeader('Content-Length'), xhrObj.status, xhrObj.statusText, new Date(), xhrObj.getResponseHeader('Content-Type'), xhrObj.getResponseHeader('X-Glimpse-ContextId'));
}

module.exports = {
render: function() {
return `
<div class="glimpse-section glimpse-ajax">
<span class="glimpse-section-label">
Ajax requests
</span>
<span class="glimpse-section-duration glimpse-section-value" id="glimpse-ajax-count">
${count}
</span>
<span class="glimpse-section-suffix glimpse-section-suffix--text">
found
</span>
</div>
`;
},
postRender: function() {
ready = true;

preRenderCache.forEach(function(task) {
task();
});

preRenderCache = undefined;
}
};
2 changes: 1 addition & 1 deletion src/views/open.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var util = require('../lib/util');
const util = require('../lib/util');

const icon = `
<svg class="glimpse-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048">
Expand Down
8 changes: 4 additions & 4 deletions src/views/timing.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ module.exports = {
const timings = getTimings(timingsRaw);

return `
<div class="glimpse-timing">
<span class="glimpse-timing-label">
<div class="glimpse-section glimpse-section--first glimpse-timing">
<span class="glimpse-section-label">
Page load time
</span>
<span class="glimpse-timing-duration">
<span class="glimpse-section-duration glimpse-section-value">
${timings.total}
</span>
<span class="glimpse-timing-suffix">
<span class="glimpse-section-suffix">
ms
</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module.exports = {
plugins: [
new webpack.DefinePlugin({
DIAGNOSTICS: false,
FAKE_SERVER: false
FAKE_SERVER: true
})
],
stats: "normal"
Expand Down

0 comments on commit 77debb3

Please sign in to comment.