Skip to content

Commit

Permalink
first working release
Browse files Browse the repository at this point in the history
  • Loading branch information
capaj committed Aug 21, 2016
1 parent b0a2702 commit 07ccf48
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 300 deletions.
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
### Issues with HTTPS (including Heroku) has been resolved, module is working again
# express-status-monitor
Simple, self-hosted module based on Socket.io and Chart.js to report realtime server metrics for Express-based node servers. More Node frameworks coming soon.
# koa-monitor
Simple, self-hosted module based on Socket.io and Chart.js to report realtime server metrics for koa.js-based node servers.

![Monitoring Page](http://i.imgur.com/AHizEWq.gif "Monitoring Page")

## Installation & setup
1. Run `npm install express-status-monitor --save`
2. Before any other middleware or router add following line:
`app.use(require('express-status-monitor')());`
1. Run `npm install koa-monitor --save`
2. Before any other middleware add following line:
```javascript
const monitor = require('koa-monitor')
// then after
app.use(monitor(server, {path: '/status'}))
```
3. Run server and go to `/status`

## Options

Monitor can be configured by passing options object into `expressMonitor` constructor.
Monitor can be configured by passing options(second argument) object into `monitor` constructor.

Default config:
```
path: '/status',
Expand All @@ -30,6 +33,10 @@ spans: [{
```

For an example koa server, check out `sample/server.js'

## License

[MIT License](https://opensource.org/licenses/MIT) © Rafal Wilinski
[MIT License](https://opensource.org/licenses/MIT) © Jiří Špác

Forked from [express-status-monitor](https://github.com/RafalWilinski/express-status-monitor)
292 changes: 50 additions & 242 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Express Status</title>
<title>Server Status</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.1/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.min.js"></script>
<style>
Expand Down Expand Up @@ -73,253 +73,61 @@
</style>
</head>
<body>
<div style="width: 600px; margin: auto">
<div class="header">
<b>Express Status</b>
<div id="span-controls" class="span-controls">
<div style="width: 600px; margin: auto">
<div class="header">
<b>Server Status</b>
<div id="span-controls" class="span-controls">
</div>
</div>
</div>
<div class="container">
<div class="stats-column">
<h5>CPU Usage</h5>
<h1 id="cpuStat">- %</h1>
</div>
<div class="chart-container">
<canvas id="cpuChart" width="400" height="100"></canvas>
</div>
</div>
<div class="container">
<div class="stats-column">
<h5>Memory Usage</h5>
<h1 id="memStat">- %</h1>
<div class="container">
<div class="stats-column">
<h5>CPU Usage</h5>
<h1 id="cpuStat">- %</h1>
</div>
<div class="chart-container">
<canvas id="cpuChart" width="400" height="100"></canvas>
</div>
</div>
<div class="chart-container">
<canvas id="memChart" width="200" height="100"></canvas>
<div class="container">
<div class="stats-column">
<h5>Memory Usage</h5>
<h1 id="memStat">- %</h1>
</div>
<div class="chart-container">
<canvas id="memChart" width="200" height="100"></canvas>
</div>
</div>
</div>
<div class="container">
<div class="stats-column">
<h5>One Minute Load Avg</h5>
<h1 id="loadStat">-</h1>
<div class="container">
<div class="stats-column">
<h5>One Minute Load Avg</h5>
<h1 id="loadStat">-</h1>
</div>
<div class="chart-container">
<canvas id="loadChart" width="200" height="100"></canvas>
</div>
</div>
<div class="chart-container">
<canvas id="loadChart" width="200" height="100"></canvas>
<div class="container">
<div class="stats-column">
<h5>Response Time</h5>
<h1 id="responseTimeStat">-</h1>
</div>
<div class="chart-container">
<canvas id="responseTimeChart" width="200" height="100"></canvas>
</div>
</div>
</div>
<div class="container">
<div class="stats-column">
<h5>Response Time</h5>
<h1 id="responseTimeStat">-</h1>
<div class="container">
<div class="stats-column">
<h5>Requests per Second</h5>
<h1 id="rpsStat">-</h1>
</div>
<div class="chart-container">
<canvas id="rpsChart" width="200" height="100"></canvas>
</div>
</div>
<div class="chart-container">
<canvas id="responseTimeChart" width="200" height="100"></canvas>
<div class="footer">
<p>Made with &#9829; with Socket.io & Chart.js</p>
</div>
</div>
<div class="container">
<div class="stats-column">
<h5>Requests per Second</h5>
<h1 id="rpsStat">-</h1>
</div>
<div class="chart-container">
<canvas id="rpsChart" width="200" height="100"></canvas>
</div>
</div>
<div class="footer">
<p>Made with &#9829; with Socket.io & Chart.js</p>
</div>
</div>
<script>
Chart.defaults.global.defaultFontSize = 8;
Chart.defaults.global.animation.duration = 500;
Chart.defaults.global.legend.display = false;
Chart.defaults.global.elements.line.backgroundColor = "rgba(0,0,0,0)";
Chart.defaults.global.elements.line.borderColor = "rgba(0,0,0,0.9)";
Chart.defaults.global.elements.line.borderWidth = 2;

var socket = io(location.protocol + '//' + location.hostname + ':' + location.port);
var defaultSpan = 0;
var spans = [];

var defaultDataset = {
label: '',
data: [],
lineTension: 0.2,
pointRadius: 0
};

var defaultOptions = {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
type: 'time',
time: {
unitStepSize: 30
},
gridLines: {
display: false
}
}]
},
tooltips: {
enabled: false
},
responsive: true,
maintainAspectRatio: false,
animation: false
};

var createChart = function (ctx, dataset) {
return new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: dataset
},
options: defaultOptions
});
};

var addTimestamp = function(point) {
return point.timestamp;
};

var cpuDataset = [Object.create(defaultDataset)];
var memDataset = [Object.create(defaultDataset)];
var loadDataset = [Object.create(defaultDataset)];
var responseTimeDataset = [Object.create(defaultDataset)];
var rpsDataset = [Object.create(defaultDataset)];

var cpuStat = document.getElementById('cpuStat');
var memStat = document.getElementById('memStat');
var loadStat = document.getElementById('loadStat');
var responseTimeStat = document.getElementById('responseTimeStat');
var rpsStat = document.getElementById('rpsStat');

var cpuChartCtx = document.getElementById("cpuChart");
var memChartCtx = document.getElementById("memChart");
var loadChartCtx = document.getElementById("loadChart");
var responseTimeChartCtx = document.getElementById("responseTimeChart");
var rpsChartCtx = document.getElementById("rpsChart");

var cpuChart = createChart(cpuChartCtx, cpuDataset);
var memChart = createChart(memChartCtx, memDataset);
var loadChart = createChart(loadChartCtx, loadDataset);
var responseTimeChart = createChart(responseTimeChartCtx, responseTimeDataset);
var rpsChart = createChart(rpsChartCtx, rpsDataset);

var charts = [cpuChart, memChart, loadChart, responseTimeChart, rpsChart];

var onSpanChange = function (e) {
e.target.classList.add('active');
defaultSpan = parseInt(e.target.id);

var otherSpans = document.getElementsByTagName('span');
for (var i = 0; i < otherSpans.length; i++) {
if (otherSpans[i] !== e.target) otherSpans[i].classList.remove('active');
}

socket.emit('change');
};

socket.on('start', function (data) {
// Remove last element of Array because it contains malformed responses data.
// To keep consistency we also remove os data.
data[defaultSpan].responses.pop();
data[defaultSpan].os.pop();

cpuStat.textContent = data[defaultSpan].os[data[defaultSpan].os.length - 1].cpu.toFixed(1) + '%';
cpuChart.data.datasets[0].data = data[defaultSpan].os.map(function (point) {
return point.cpu;
});
cpuChart.data.labels = data[defaultSpan].os.map(addTimestamp);

memStat.textContent = data[defaultSpan].os[data[defaultSpan].os.length - 1].memory.toFixed(1) + 'MB';
memChart.data.datasets[0].data = data[defaultSpan].os.map(function (point) {
return point.memory;
});
memChart.data.labels = data[defaultSpan].os.map(addTimestamp);

loadStat.textContent = data[defaultSpan].os[data[defaultSpan].os.length - 1].load[defaultSpan].toFixed(2);
loadChart.data.datasets[0].data = data[defaultSpan].os.map(function (point) {
return point.load[0];
});
loadChart.data.labels = data[defaultSpan].os.map(addTimestamp);

responseTimeStat.textContent = data[defaultSpan].responses[data[defaultSpan].responses.length - 1].mean.toFixed(2) + 'ms';
responseTimeChart.data.datasets[0].data = data[defaultSpan].responses.map(function (point) {
return point.mean;
});
responseTimeChart.data.labels = data[defaultSpan].responses.map(addTimestamp);

if (data[defaultSpan].responses.length >= 2) {
var deltaTime = data[defaultSpan].responses[data[defaultSpan].responses.length - 1].timestamp - data[defaultSpan].responses[data[defaultSpan].responses.length - 2].timestamp;
rpsStat.textContent = (data[defaultSpan].responses[data[defaultSpan].responses.length - 1].count / deltaTime * 1000).toFixed(2);
rpsChart.data.datasets[0].data = data[defaultSpan].responses.map(function (point) {
return point.count / deltaTime * 1000;
});
rpsChart.data.labels = data[defaultSpan].responses.map(addTimestamp);
}

charts.forEach(function(chart) {
chart.update();
});

var spanControls = document.getElementById('span-controls');
if (data.length !== spans.length) {
data.forEach(function (span, index) {
spans.push({
retention: span.retention,
interval: span.interval
});

var spanNode = document.createElement('span');
var textNode = document.createTextNode((span.retention * span.interval) / 60 + "M");
spanNode.appendChild(textNode);
spanNode.setAttribute('id', index);
spanNode.onclick = onSpanChange;
spanControls.appendChild(spanNode);
});
document.getElementsByTagName('span')[0].classList.add('active');
}
});

socket.on('stats', function (data) {
if (data.retention === spans[defaultSpan].retention && data.interval === spans[defaultSpan].interval) {
cpuStat.textContent = data.os.cpu.toFixed(1) + '%';
cpuChart.data.datasets[0].data.push(data.os.cpu);
cpuChart.data.labels.push(data.os.timestamp);

memStat.textContent = data.os.memory.toFixed(1) + 'MB';
memChart.data.datasets[0].data.push(data.os.memory);
memChart.data.labels.push(data.os.timestamp);

loadStat.textContent = data.os.load[0].toFixed(2);
loadChart.data.datasets[0].data.push(data.os.load[0]);
loadChart.data.labels.push(data.os.timestamp);

responseTimeStat.textContent = data.responses.mean.toFixed(2) + 'ms';
responseTimeChart.data.datasets[0].data.push(data.responses.mean);
responseTimeChart.data.labels.push(data.responses.timestamp);

var deltaTime = data.responses.timestamp - rpsChart.data.labels[rpsChart.data.labels.length - 1];
rpsStat.textContent = (data.responses.count / deltaTime * 1000).toFixed(2);
rpsChart.data.datasets[0].data.push(data.responses.count / deltaTime * 1000);
rpsChart.data.labels.push(data.responses.timestamp);

charts.forEach(function (chart) {
if (spans[defaultSpan].retention < chart.data.labels.length) {
chart.data.datasets[0].data.shift();
chart.data.labels.shift();
}

chart.update();
});
}
});
</script>
<script src="{{path}}/koa-monitor-frontend.js"></script>
</body>
</html>
</html>
Loading

0 comments on commit 07ccf48

Please sign in to comment.