UNPKG

express-status-monitor

Version:

Realtime Monitoring for Express-based Node applications

336 lines (284 loc) 10.3 kB
/* eslint-disable no-plusplus, no-var, strict, vars-on-top, prefer-template, func-names, prefer-arrow-callback, no-loop-func */ /* global Chart, location, document, port, socketPath, parseInt, io */ 'use strict'; 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 + ':' + (port || location.port), { path: socketPath, }); var defaultSpan = 0; var spans = []; var statusCodesColors = ['#75D701', '#47b8e0', '#ffc952', '#E53A40']; 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 heapDataset = [Object.create(defaultDataset)]; var eventLoopDataset = [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 heapStat = document.getElementById('heapStat'); var eventLoopStat = document.getElementById('eventLoopStat'); 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 heapChartCtx = document.getElementById('heapChart'); var eventLoopChartCtx = document.getElementById('eventLoopChart'); var responseTimeChartCtx = document.getElementById('responseTimeChart'); var rpsChartCtx = document.getElementById('rpsChart'); var statusCodesChartCtx = document.getElementById('statusCodesChart'); var cpuChart = createChart(cpuChartCtx, cpuDataset); var memChart = createChart(memChartCtx, memDataset); var heapChart = createChart(heapChartCtx, heapDataset); var eventLoopChart = createChart(eventLoopChartCtx, eventLoopDataset); var loadChart = createChart(loadChartCtx, loadDataset); var responseTimeChart = createChart(responseTimeChartCtx, responseTimeDataset); var rpsChart = createChart(rpsChartCtx, rpsDataset); var statusCodesChart = new Chart(statusCodesChartCtx, { type: 'line', data: { labels: [], datasets: [ Object.create(defaultDataset), Object.create(defaultDataset), Object.create(defaultDataset), Object.create(defaultDataset), ], }, options: defaultOptions, }); statusCodesChart.data.datasets.forEach(function (dataset, index) { dataset.borderColor = statusCodesColors[index]; }); var charts = [ cpuChart, memChart, loadChart, responseTimeChart, rpsChart, statusCodesChart, heapChart, eventLoopChart, ]; var onSpanChange = function (e) { e.target.classList.add('active'); defaultSpan = parseInt(e.target.id, 10); 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('esm_change'); }; socket.on('esm_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(); var lastOsMetric = data[defaultSpan].os[data[defaultSpan].os.length - 1]; cpuStat.textContent = '0.0%'; if (lastOsMetric) { cpuStat.textContent = lastOsMetric.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 = '0.0MB'; if (lastOsMetric) { memStat.textContent = lastOsMetric.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 = '0.00'; if (lastOsMetric) { loadStat.textContent = lastOsMetric.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); heapChart.data.datasets[0].data = data[defaultSpan].os.map(function (point) { return point.heap.used_heap_size / 1024 / 1024; }); heapChart.data.labels = data[defaultSpan].os.map(addTimestamp); eventLoopChart.data.datasets[0].data = data[defaultSpan].os.map(function (point) { if (point.loop) { return point.loop.sum; } return 0; }); eventLoopChart.data.labels = data[defaultSpan].os.map(addTimestamp); var lastResponseMetric = data[defaultSpan].responses[data[defaultSpan].responses.length - 1]; responseTimeStat.textContent = '0.00ms'; if (lastResponseMetric) { responseTimeStat.textContent = lastResponseMetric.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); for (var i = 0; i < 4; i++) { statusCodesChart.data.datasets[i].data = data[defaultSpan].responses.map(function (point) { return point[i + 2]; }); } statusCodesChart.data.labels = data[defaultSpan].responses.map(addTimestamp); if (data[defaultSpan].responses.length >= 2) { var deltaTime = lastResponseMetric.timestamp - data[defaultSpan].responses[data[defaultSpan].responses.length - 2].timestamp; if (deltaTime < 1) deltaTime = 1000; rpsStat.textContent = ((lastResponseMetric.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'); // eslint-disable-line spanNode.appendChild(textNode); spanNode.setAttribute('id', index); spanNode.onclick = onSpanChange; spanControls.appendChild(spanNode); }); document.getElementsByTagName('span')[0].classList.add('active'); } }); socket.on('esm_stats', function (data) { console.log(data); if ( data.retention === spans[defaultSpan].retention && data.interval === spans[defaultSpan].interval ) { var os = data.os; var responses = data.responses; cpuStat.textContent = '0.0%'; if (os) { cpuStat.textContent = os.cpu.toFixed(1) + '%'; cpuChart.data.datasets[0].data.push(os.cpu); cpuChart.data.labels.push(os.timestamp); } memStat.textContent = '0.0MB'; if (os) { memStat.textContent = os.memory.toFixed(1) + 'MB'; memChart.data.datasets[0].data.push(os.memory); memChart.data.labels.push(os.timestamp); } loadStat.textContent = '0'; if (os) { loadStat.textContent = os.load[0].toFixed(2); loadChart.data.datasets[0].data.push(os.load[0]); loadChart.data.labels.push(os.timestamp); } heapStat.textContent = '0'; if (os) { heapStat.textContent = (os.heap.used_heap_size / 1024 / 1024).toFixed(1) + 'MB'; heapChart.data.datasets[0].data.push(os.heap.used_heap_size / 1024 / 1024); heapChart.data.labels.push(os.timestamp); } eventLoopStat.textContent = '0'; if (os && os.loop) { eventLoopStat.textContent = os.loop.sum.toFixed(2) + 'ms'; eventLoopChart.data.datasets[0].data.push(os.loop.sum); eventLoopChart.data.labels.push(os.timestamp); } responseTimeStat.textContent = '0.00ms'; if (responses) { responseTimeStat.textContent = responses.mean.toFixed(2) + 'ms'; responseTimeChart.data.datasets[0].data.push(responses.mean); responseTimeChart.data.labels.push(responses.timestamp); } if (responses) { var deltaTime = responses.timestamp - rpsChart.data.labels[rpsChart.data.labels.length - 1]; if (deltaTime < 1) deltaTime = 1000; rpsStat.textContent = ((responses.count / deltaTime) * 1000).toFixed(2); rpsChart.data.datasets[0].data.push((responses.count / deltaTime) * 1000); rpsChart.data.labels.push(responses.timestamp); } if (responses) { for (var i = 0; i < 4; i++) { statusCodesChart.data.datasets[i].data.push(data.responses[i + 2]); } statusCodesChart.data.labels.push(data.responses.timestamp); } charts.forEach(function (chart) { if (spans[defaultSpan].retention < chart.data.labels.length) { chart.data.datasets.forEach(function (dataset) { dataset.data.shift(); }); chart.data.labels.shift(); } chart.update(); }); } });