Containers are identified by name now for handling container restarts
rodzic
0c4665295e
commit
791c51d5ed
|
@ -37,8 +37,7 @@
|
|||
<table class="table" id="container-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Name or ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -1,159 +1,159 @@
|
|||
'use strict';
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var zoom = 'hour';
|
||||
var selectedContainerId = null;
|
||||
var zoom = 'hour';
|
||||
var selectedContainerId = null;
|
||||
|
||||
var unitRound = function(i) {
|
||||
return parseFloat(Math.round(i * 100) / 100).toFixed(2);
|
||||
};
|
||||
var unitRound = function(i) {
|
||||
return parseFloat(Math.round(i * 100) / 100).toFixed(2);
|
||||
};
|
||||
|
||||
var getReadableUnit = function(i) {
|
||||
if (i < 1024) return unitRound(i) + ' B';
|
||||
if (i < 1024*1024) return unitRound(i/1024) + ' KB';
|
||||
if (i < 1024*1024*1024) return unitRound(i/1024/1024) + ' MB';
|
||||
if (i < 1024*1024*1024*1024) return unitRound(i/1024/1024/1024) + ' GB';
|
||||
if (i < 1024*1024*1024*1024*1024) return unitRound(i/1024/1024/1024/1024) + ' TB';
|
||||
if (i < 1024*1024*1024*1024*1024*1024) return unitRound(i/1024/1024/1024/1024/1024) + ' PB';
|
||||
};
|
||||
var getReadableUnit = function(i) {
|
||||
if (i < 1024) return unitRound(i) + ' B';
|
||||
if (i < 1024*1024) return unitRound(i/1024) + ' KB';
|
||||
if (i < 1024*1024*1024) return unitRound(i/1024/1024) + ' MB';
|
||||
if (i < 1024*1024*1024*1024) return unitRound(i/1024/1024/1024) + ' GB';
|
||||
if (i < 1024*1024*1024*1024*1024) return unitRound(i/1024/1024/1024/1024) + ' TB';
|
||||
if (i < 1024*1024*1024*1024*1024*1024) return unitRound(i/1024/1024/1024/1024/1024) + ' PB';
|
||||
};
|
||||
|
||||
var addStatRow = function(list, row) {
|
||||
var tr = $(document.createElement('tr'));
|
||||
var td0 = $(document.createElement('td'));
|
||||
var td1 = $(document.createElement('td'));
|
||||
var td2 = $(document.createElement('td'));
|
||||
var td3 = $(document.createElement('td'));
|
||||
var td4 = $(document.createElement('td'));
|
||||
var td5 = $(document.createElement('td'));
|
||||
var td6 = $(document.createElement('td'));
|
||||
|
||||
td0.text(row.ts);
|
||||
td1.text(row.cpu + '%');
|
||||
td2.text(getReadableUnit(row.mem));
|
||||
td3.text(getReadableUnit(row.net_in));
|
||||
td4.text(getReadableUnit(row.net_out));
|
||||
td5.text(getReadableUnit(row.block_in));
|
||||
td6.text(getReadableUnit(row.block_out));
|
||||
|
||||
tr.append(td0, td1, td2, td3, td4, td5, td6);
|
||||
list.append(tr);
|
||||
};
|
||||
var addStatRow = function(list, row) {
|
||||
var tr = $(document.createElement('tr'));
|
||||
var td0 = $(document.createElement('td'));
|
||||
var td1 = $(document.createElement('td'));
|
||||
var td2 = $(document.createElement('td'));
|
||||
var td3 = $(document.createElement('td'));
|
||||
var td4 = $(document.createElement('td'));
|
||||
var td5 = $(document.createElement('td'));
|
||||
var td6 = $(document.createElement('td'));
|
||||
|
||||
td0.text(row.ts);
|
||||
td1.text(row.cpu + '%');
|
||||
td2.text(getReadableUnit(row.mem));
|
||||
td3.text(getReadableUnit(row.net_in));
|
||||
td4.text(getReadableUnit(row.net_out));
|
||||
td5.text(getReadableUnit(row.block_in));
|
||||
td6.text(getReadableUnit(row.block_out));
|
||||
|
||||
tr.append(td0, td1, td2, td3, td4, td5, td6);
|
||||
list.append(tr);
|
||||
};
|
||||
|
||||
var renderLatestStats = function(containerId) {
|
||||
$.get('/rs/container/'+containerId+'/stats/latest', function(data) {
|
||||
var list = $('#container-stats-latest > tbody');
|
||||
list.empty();
|
||||
for (var i=0; i<data.length; i++) {
|
||||
var row = data[i];
|
||||
addStatRow(list, row);
|
||||
var renderLatestStats = function(containerId) {
|
||||
$.get('/rs/container/'+containerId+'/stats/latest', function(data) {
|
||||
var list = $('#container-stats-latest > tbody');
|
||||
list.empty();
|
||||
for (var i=0; i<data.length; i++) {
|
||||
var row = data[i];
|
||||
addStatRow(list, row);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var renderChart = function(elementId, containerId, chart) {
|
||||
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 options = {
|
||||
legend: { position: 'right' }
|
||||
};
|
||||
var chart = new google.visualization.LineChart(document.getElementById(elementId));
|
||||
chart.draw(data, options);
|
||||
});
|
||||
};
|
||||
|
||||
var renderChart = function(elementId, containerId, chart) {
|
||||
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 renderContainerStats = function(id) {
|
||||
renderLatestStats(id);
|
||||
renderChart('mem-chart', id, 'mem');
|
||||
renderChart('net-in-chart', id, 'net_in');
|
||||
renderChart('net-out-chart', id, 'net_out');
|
||||
renderChart('block-in-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 data = google.visualization.arrayToDataTable(stats);
|
||||
var options = {
|
||||
legend: { position: 'right' }
|
||||
};
|
||||
var chart = new google.visualization.LineChart(document.getElementById(elementId));
|
||||
chart.draw(data, options);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
var renderContainerStats = function(id) {
|
||||
renderLatestStats(id);
|
||||
renderChart('mem-chart', id, 'mem');
|
||||
renderChart('net-in-chart', id, 'net_in');
|
||||
renderChart('net-out-chart', id, 'net_out');
|
||||
renderChart('block-in-chart', id, 'block_in');
|
||||
renderChart('block-out-chart', id, 'block_out');
|
||||
};
|
||||
var addItemToContainerList = function(list, container) {
|
||||
var tr = $(document.createElement('tr'));
|
||||
var td1 = $(document.createElement('td'));
|
||||
var link = $(document.createElement('a'));
|
||||
|
||||
link.attr('href', '#');
|
||||
link.click(function() {
|
||||
selectContainer(container.id, container.name);
|
||||
return false;
|
||||
});
|
||||
link.text(container.name);
|
||||
td1.append(link);
|
||||
|
||||
tr.append(td1);
|
||||
list.append(tr);
|
||||
};
|
||||
|
||||
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 loadContainerList = function() {
|
||||
$.get('/rs/containers/get', function(data) {
|
||||
var list = $('#container-list > tbody');
|
||||
for (var i=0; i<data.length; i++) {
|
||||
var container = data[i];
|
||||
addItemToContainerList(list, container);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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 onZoomButtonClick = function(level) {
|
||||
zoom = level;
|
||||
$('#zoom-buttons > button').removeClass('btn-primary');
|
||||
$('#zoom-'+level).addClass('btn-primary');
|
||||
reRenderCharts();
|
||||
};
|
||||
|
||||
var reRenderCharts = function() {
|
||||
if (selectedContainerId) {
|
||||
renderContainerStats(selectedContainerId);
|
||||
} else {
|
||||
renderAllContainerStats();
|
||||
}
|
||||
};
|
||||
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 addItemToContainerList = function(list, container) {
|
||||
var tr = $(document.createElement('tr'));
|
||||
var td1 = $(document.createElement('td'));
|
||||
var td2 = $(document.createElement('td'));
|
||||
var link = $(document.createElement('a'));
|
||||
|
||||
link.attr('href', '#');
|
||||
link.click(function() {
|
||||
selectContainer(container.id, container.name);
|
||||
return false;
|
||||
});
|
||||
link.text(container.id);
|
||||
td1.append(link);
|
||||
td2.text(container.name);
|
||||
|
||||
tr.append(td1, td2);
|
||||
list.append(tr);
|
||||
};
|
||||
var init = function() {
|
||||
google.charts.load('current', {packages: ['corechart']});
|
||||
initZoomButton();
|
||||
loadContainerList();
|
||||
google.charts.setOnLoadCallback(renderAllContainerStats);
|
||||
};
|
||||
|
||||
var loadContainerList = function() {
|
||||
$.get('/rs/containers/get', function(data) {
|
||||
var list = $('#container-list > tbody');
|
||||
for (var i=0; i<data.length; i++) {
|
||||
var container = data[i];
|
||||
addItemToContainerList(list, container);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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() {
|
||||
google.charts.load('current', {packages: ['corechart']});
|
||||
initZoomButton();
|
||||
loadContainerList();
|
||||
renderAllContainerStats();
|
||||
};
|
||||
|
||||
$(document).ready(init);
|
||||
$(document).ready(init);
|
||||
}());
|
||||
|
|
19
httpd.js
19
httpd.js
|
@ -1,4 +1,4 @@
|
|||
var DB_FILE = 'db/netstats.db';
|
||||
var DB_FILE = 'db/stats.db';
|
||||
|
||||
var sqlite3 = require('sqlite3');
|
||||
var bodyParser = require('body-parser');
|
||||
|
@ -25,15 +25,16 @@ var getMinDate = function(zoom) {
|
|||
|
||||
var processPreResult = function(result, containers, preResult) {
|
||||
var timestamps = [];
|
||||
for (var ts in preResult) {
|
||||
var ts;
|
||||
for (ts in preResult) {
|
||||
timestamps.push(ts);
|
||||
}
|
||||
timestamps.sort();
|
||||
for (var k=0; k<timestamps.length; k++) {
|
||||
var ts = timestamps[k];
|
||||
ts = timestamps[k];
|
||||
result.push([ts]);
|
||||
for (var i=0; i<containers.length; i++) {
|
||||
result[k+1].push(preResult[ts][containers[i].id]);
|
||||
result[k+1].push(preResult[ts][containers[i].id] ? preResult[ts][containers[i].id] : 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -64,7 +65,7 @@ app.use(bodyParser.urlencoded({ extended: true }));
|
|||
app.use(express.static("html"));
|
||||
|
||||
app.get("/rs/containers/get", function(req, res) {
|
||||
db.all("SELECT * FROM containers ORDER BY name, id ASC", function(err, rows) {
|
||||
db.all("SELECT * FROM containers ORDER BY name ASC", function(err, rows) {
|
||||
res.json(rows);
|
||||
});
|
||||
});
|
||||
|
@ -80,7 +81,7 @@ app.get("/rs/container/:id/:chart/:zoom", function(req, res) {
|
|||
var zoom = req.params.zoom;
|
||||
if (!isValidChart(chart) || !isValidZoom(zoom)) {
|
||||
return res.json([]);
|
||||
};
|
||||
}
|
||||
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']];
|
||||
|
@ -98,11 +99,11 @@ app.get("/rs/all/:chart/:zoom", function(req, res) {
|
|||
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) {
|
||||
db.all("SELECT * FROM containers ORDER BY name ASC", function(err, containers) {
|
||||
var result = [['Time']];
|
||||
if (containers.length == 0) {
|
||||
if (containers.length === 0) {
|
||||
res.json(result);
|
||||
return;
|
||||
}
|
||||
|
|
38
stats.js
38
stats.js
|
@ -1,4 +1,4 @@
|
|||
var DB_FILE = 'db/netstats.db';
|
||||
var DB_FILE = 'db/stats.db';
|
||||
var DOCKER = '/usr/bin/docker';
|
||||
var INTERVAL = 60;
|
||||
var TEST = false;
|
||||
|
@ -48,7 +48,7 @@ var getBytes = function(s) {
|
|||
return bytes;
|
||||
};
|
||||
|
||||
var addNetworkStats = function(containers) {
|
||||
var addStatsToContainerList = function(containers) {
|
||||
var out;
|
||||
if (TEST) {
|
||||
out = fs.readFileSync('test/docker_stats.txt', {encoding: 'utf-8'});
|
||||
|
@ -84,14 +84,26 @@ var addNetworkStats = function(containers) {
|
|||
}
|
||||
};
|
||||
|
||||
var writeContainerStats = function(id, container, now) {
|
||||
var stm;
|
||||
stm = db.prepare("INSERT OR IGNORE INTO containers (id, name) VALUES (?, ?)");
|
||||
stm.run(id, container.name);
|
||||
stm = db.prepare("INSERT INTO stats (id, ts, cpu, mem, net_in, net_out, block_in, block_out) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
stm.run(id, now, container.cpu, container.mem, container.net.in, container.net.out, container.block.in, container.block.out);
|
||||
stm.finalize();
|
||||
var getCreateContainerId = function(name, cid, cb) {
|
||||
if (!name) name = cid;
|
||||
db.get("SELECT id FROM containers WHERE name = ? LIMIT 1", name, function(err, row) {
|
||||
if (row) {
|
||||
cb(row.id);
|
||||
} else {
|
||||
db.run("INSERT INTO containers (name) VALUES (?)", name, function() {
|
||||
cb(this.lastID);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var writeContainerStats = function(cid, container, now) {
|
||||
getCreateContainerId(container.name, cid, function(id) {
|
||||
var stm = db.prepare("INSERT INTO stats (id, ts, cpu, mem, net_in, net_out, block_in, block_out) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
stm.run(id, now, container.cpu, container.mem, container.net.in, container.net.out, container.block.in, container.block.out);
|
||||
stm.finalize();
|
||||
});
|
||||
};
|
||||
|
||||
var writeStats = function(containers) {
|
||||
|
@ -104,16 +116,16 @@ var writeStats = function(containers) {
|
|||
|
||||
var main = function() {
|
||||
var containers = getContainers();
|
||||
addNetworkStats(containers);
|
||||
addStatsToContainerList(containers);
|
||||
writeStats(containers);
|
||||
};
|
||||
|
||||
db.run("CREATE TABLE IF NOT EXISTS containers ( " +
|
||||
"id TEXT NOT NULL PRIMARY KEY, " +
|
||||
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
|
||||
"name TEXT NOT NULL)");
|
||||
|
||||
db.run("CREATE TABLE IF NOT EXISTS stats ( " +
|
||||
"id TEXT NOT NULL, " +
|
||||
"id INTEGER NOT NULL, " +
|
||||
"ts DATETIME NOT NULL, " +
|
||||
"cpu REAL NOT NULL, " +
|
||||
"mem REAL NOT NULL, " +
|
||||
|
|
Ładowanie…
Reference in New Issue