All stats working
rodzic
405c120bb1
commit
4bfeac7cc0
|
@ -14,6 +14,7 @@
|
||||||
.chart {
|
.chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container-stats {
|
#container-stats {
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header clearfix">
|
<div class="header clearfix">
|
||||||
|
<div class="btn-group pull-right" role="group" id="zoom-buttons">
|
||||||
|
<button type="button" class="btn btn-default btn-primary" id="zoom-hour">Hour</button>
|
||||||
|
<button type="button" class="btn btn-default" id="zoom-day">Day</button>
|
||||||
|
<button type="button" class="btn btn-default" id="zoom-week">Week</button>
|
||||||
|
<button type="button" class="btn btn-default" id="zoom-month">Month</button>
|
||||||
|
</div>
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
Docker Container Stats
|
Docker Container Stats
|
||||||
<span class="glyphicon glyphicon-stats"></span>
|
<span class="glyphicon glyphicon-stats"></span>
|
||||||
|
@ -60,21 +66,32 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<h4>Mem</h4>
|
|
||||||
<div id="mem-chart" class="chart"></div>
|
|
||||||
<div class="divider"></div>
|
|
||||||
<h4>Net In</h4>
|
|
||||||
<div id="net-in-chart" class="chart"></div>
|
|
||||||
<div class="divider"></div>
|
|
||||||
<h4>Net Out</h4>
|
|
||||||
<div id="net-out-chart" class="chart"></div>
|
|
||||||
<div class="divider"></div>
|
|
||||||
<h4>Block In</h4>
|
|
||||||
<div id="block-in-chart" class="chart"></div>
|
|
||||||
<div class="divider"></div>
|
|
||||||
<h4>Block Out</h4>
|
|
||||||
<div id="block-out-chart" class="chart"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h4>Mem</h4>
|
||||||
|
<div id="mem-chart" class="chart"></div>
|
||||||
|
<div class="alert alert-warning chart-warn" id="mem-chart-warn" role="alert">No data for specified zoom level.</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<h4>Net In</h4>
|
||||||
|
<div id="net-in-chart" class="chart"></div>
|
||||||
|
<div class="alert alert-warning chart-warn" id="net-in-chart-warn" role="alert">No data for specified zoom level.</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<h4>Net Out</h4>
|
||||||
|
<div id="net-out-chart" class="chart"></div>
|
||||||
|
<div class="alert alert-warning chart-warn" id="net-out-chart-warn" role="alert">No data for specified zoom level.</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<h4>Block In</h4>
|
||||||
|
<div id="block-in-chart" class="chart"></div>
|
||||||
|
<div class="alert alert-warning chart-warn" id="block-in-chart-warn" role="alert">No data for specified zoom level.</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<h4>Block Out</h4>
|
||||||
|
<div id="block-out-chart" class="chart"></div>
|
||||||
|
<div class="alert alert-warning chart-warn" id="block-out-chart-warn" role="alert">No data for specified zoom level.</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="js/jquery-2.2.1.min.js"></script>
|
<script src="js/jquery-2.2.1.min.js"></script>
|
||||||
<script src="js/bootstrap.min.js"></script>
|
<script src="js/bootstrap.min.js"></script>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var zoom = 'hour';
|
||||||
|
var selectedContainerId = null;
|
||||||
|
|
||||||
var unitRound = function(i) {
|
var unitRound = function(i) {
|
||||||
return parseFloat(Math.round(i * 100) / 100).toFixed(2);
|
return parseFloat(Math.round(i * 100) / 100).toFixed(2);
|
||||||
};
|
};
|
||||||
|
@ -47,26 +50,60 @@ var renderLatestStats = function(containerId) {
|
||||||
};
|
};
|
||||||
|
|
||||||
var renderChart = function(elementId, containerId, chart) {
|
var renderChart = function(elementId, containerId, chart) {
|
||||||
$.get('/rs/container/'+containerId+'/'+chart, function(stats) {
|
var url;
|
||||||
|
if (containerId) {
|
||||||
|
url = '/rs/container/'+containerId+'/'+chart+'/'+zoom;
|
||||||
|
} else {
|
||||||
|
url = '/rs/all/'+chart+'/'+zoom;
|
||||||
|
}
|
||||||
|
$.get(url, function(stats) {
|
||||||
|
$('#'+elementId).show();
|
||||||
|
$('#'+elementId+'-warn').hide();
|
||||||
|
if (stats.length <= 1) {
|
||||||
|
$('#'+elementId).hide();
|
||||||
|
$('#'+elementId+'-warn').show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
var data = google.visualization.arrayToDataTable(stats);
|
var data = google.visualization.arrayToDataTable(stats);
|
||||||
var options = {
|
var options = {
|
||||||
legend: { position: 'bottom' }
|
legend: { position: 'right' }
|
||||||
};
|
};
|
||||||
var chart = new google.visualization.LineChart(document.getElementById(elementId));
|
var chart = new google.visualization.LineChart(document.getElementById(elementId));
|
||||||
chart.draw(data, options);
|
chart.draw(data, options);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var selectContainer = function(id, name) {
|
var renderContainerStats = function(id) {
|
||||||
$('#selected-container').text('Selected container: ' + (name ? name : id) + ' (click to change)');
|
|
||||||
$('#container-list-collapse').collapse('hide');
|
|
||||||
$('#container-stats').show();
|
|
||||||
renderLatestStats(id);
|
renderLatestStats(id);
|
||||||
renderChart('mem-chart', id, 'mem');
|
renderChart('mem-chart', id, 'mem');
|
||||||
renderChart('net-in-chart', id, 'net_in');
|
renderChart('net-in-chart', id, 'net_in');
|
||||||
renderChart('net-out-chart', id, 'net_out');
|
renderChart('net-out-chart', id, 'net_out');
|
||||||
renderChart('block-in-chart', id, 'block_in');
|
renderChart('block-in-chart', id, 'block_in');
|
||||||
renderChart('block-out-chart', id, 'block_in');
|
renderChart('block-out-chart', id, 'block_out');
|
||||||
|
};
|
||||||
|
|
||||||
|
var selectContainer = function(id, name) {
|
||||||
|
$('#selected-container').text('Selected container: ' + (name ? name : id) + ' (click to change)');
|
||||||
|
$('#container-list-collapse').collapse('hide');
|
||||||
|
$('#container-stats').show();
|
||||||
|
renderContainerStats(id);
|
||||||
|
selectedContainerId = id;
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderAllContainerStats = function() {
|
||||||
|
renderChart('mem-chart', null, 'mem');
|
||||||
|
renderChart('net-in-chart', null, 'net_in');
|
||||||
|
renderChart('net-out-chart', null, 'net_out');
|
||||||
|
renderChart('block-in-chart', null, 'block_in');
|
||||||
|
renderChart('block-out-chart', null, 'block_out');
|
||||||
|
};
|
||||||
|
|
||||||
|
var reRenderCharts = function() {
|
||||||
|
if (selectedContainerId) {
|
||||||
|
renderContainerStats(selectedContainerId);
|
||||||
|
} else {
|
||||||
|
renderAllContainerStats();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var addItemToContainerList = function(list, container) {
|
var addItemToContainerList = function(list, container) {
|
||||||
|
@ -98,10 +135,25 @@ var loadContainerList = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var onZoomButtonClick = function(level) {
|
||||||
|
zoom = level;
|
||||||
|
$('#zoom-buttons > button').removeClass('btn-primary');
|
||||||
|
$('#zoom-'+level).addClass('btn-primary');
|
||||||
|
reRenderCharts();
|
||||||
|
};
|
||||||
|
|
||||||
|
var initZoomButton = function() {
|
||||||
|
$('#zoom-hour').click(function() { onZoomButtonClick('hour'); });
|
||||||
|
$('#zoom-day').click(function() { onZoomButtonClick('day'); });
|
||||||
|
$('#zoom-week').click(function() { onZoomButtonClick('week'); });
|
||||||
|
$('#zoom-month').click(function() { onZoomButtonClick('month'); });
|
||||||
|
};
|
||||||
|
|
||||||
var init = function() {
|
var init = function() {
|
||||||
google.charts.load('current', {packages: ['corechart']});
|
google.charts.load('current', {packages: ['corechart']});
|
||||||
|
initZoomButton();
|
||||||
loadContainerList();
|
loadContainerList();
|
||||||
//google.charts.setOnLoadCallback(drawChart
|
renderAllContainerStats();
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready(init);
|
$(document).ready(init);
|
||||||
|
|
77
httpd.js
77
httpd.js
|
@ -9,6 +9,57 @@ var express = require("express");
|
||||||
var app = express();
|
var app = express();
|
||||||
var db = new sqlite3.Database(DB_FILE);
|
var db = new sqlite3.Database(DB_FILE);
|
||||||
|
|
||||||
|
var isValidChart = function(s) {
|
||||||
|
return /^(net_in|net_out|block_in|block_out|mem)$/.test(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
var isValidZoom = function(s) {
|
||||||
|
return /^(hour|day|week|month)$/.test(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
var getMinDate = function(zoom) {
|
||||||
|
var now = moment();
|
||||||
|
now.subtract(1, zoom + 's');
|
||||||
|
return now.format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
};
|
||||||
|
|
||||||
|
var processPreResult = function(result, containers, preResult) {
|
||||||
|
var timestamps = [];
|
||||||
|
for (var ts in preResult) {
|
||||||
|
timestamps.push(ts);
|
||||||
|
}
|
||||||
|
timestamps.sort();
|
||||||
|
for (var k=0; k<timestamps.length; k++) {
|
||||||
|
var ts = timestamps[k];
|
||||||
|
result.push([ts]);
|
||||||
|
for (var i=0; i<containers.length; i++) {
|
||||||
|
result[k+1].push(preResult[ts][containers[i].id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var processNextContainer = function(result, preResult, containers, j, minDate, chart, res) {
|
||||||
|
var id = containers[j].id;
|
||||||
|
var name = containers[j].name;
|
||||||
|
result[0].push(name ? name : id);
|
||||||
|
db.all("SELECT ts, "+chart+" FROM stats WHERE id = ? AND ts >= ? ORDER BY ts ASC", id, minDate, function(err, rows) {
|
||||||
|
var prev = 0;
|
||||||
|
for (var i=0; i<rows.length; i++) {
|
||||||
|
if (!preResult.hasOwnProperty(rows[i].ts)) {
|
||||||
|
preResult[rows[i].ts] = {};
|
||||||
|
}
|
||||||
|
preResult[rows[i].ts][id] = (!rows[i][chart] ? prev : rows[i][chart]);
|
||||||
|
if (rows[i][chart]) prev = rows[i][chart];
|
||||||
|
}
|
||||||
|
if (j == containers.length-1) {
|
||||||
|
processPreResult(result, containers, preResult);
|
||||||
|
res.json(result);
|
||||||
|
} else {
|
||||||
|
processNextContainer(result, preResult, containers, j+1, minDate, chart, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
app.use(express.static("html"));
|
app.use(express.static("html"));
|
||||||
|
|
||||||
|
@ -24,12 +75,14 @@ app.get("/rs/container/:id/stats/latest", function(req, res) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/rs/container/:id/:chart", function(req, res) {
|
app.get("/rs/container/:id/:chart/:zoom", function(req, res) {
|
||||||
var chart = req.params.chart;
|
var chart = req.params.chart;
|
||||||
if (!/^(net_in|net_out|block_in|block_out|mem)$/.test(chart)) {
|
var zoom = req.params.zoom;
|
||||||
|
if (!isValidChart(chart) || !isValidZoom(zoom)) {
|
||||||
return res.json([]);
|
return res.json([]);
|
||||||
};
|
};
|
||||||
db.all("SELECT ts, "+chart+" FROM stats WHERE id = ? ORDER BY ts ASC", req.params.id, function(err, rows) {
|
var minDate = getMinDate(zoom);
|
||||||
|
db.all("SELECT ts, "+chart+" FROM stats WHERE id = ? AND ts >= ? ORDER BY ts ASC", req.params.id, minDate, function(err, rows) {
|
||||||
var json = [['Time', 'Bytes']];
|
var json = [['Time', 'Bytes']];
|
||||||
var prev = 0;
|
var prev = 0;
|
||||||
for (var i=0; i<rows.length; i++) {
|
for (var i=0; i<rows.length; i++) {
|
||||||
|
@ -40,6 +93,24 @@ app.get("/rs/container/:id/:chart", function(req, res) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get("/rs/all/:chart/:zoom", function(req, res) {
|
||||||
|
var chart = req.params.chart;
|
||||||
|
var zoom = req.params.zoom;
|
||||||
|
if (!isValidChart(chart) || !isValidZoom(zoom)) {
|
||||||
|
return res.json([]);
|
||||||
|
};
|
||||||
|
var minDate = getMinDate(zoom);
|
||||||
|
db.all("SELECT * FROM containers ORDER BY name, id ASC", function(err, containers) {
|
||||||
|
var result = [['Time']];
|
||||||
|
if (containers.length == 0) {
|
||||||
|
res.json(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var preResult = {};
|
||||||
|
processNextContainer(result, preResult, containers, 0, minDate, chart, res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(8080, function() {
|
app.listen(8080, function() {
|
||||||
|
|
||||||
});
|
});
|
Ładowanie…
Reference in New Issue