feat(webui): new Health screen
- add realtime chart - Total Status Code Count - Average response time - remove status code count - D3 & NVD3 & Angular NVD3
This commit is contained in:
parent
398dfbd8a5
commit
28458345b4
10 changed files with 252 additions and 51 deletions
|
@ -6,21 +6,199 @@
|
||||||
|
|
||||||
var vm = this;
|
var vm = this;
|
||||||
|
|
||||||
vm.health = Health.get();
|
vm.graph = {
|
||||||
|
averageResponseTime: {},
|
||||||
|
totalStatusCodeCount: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.graph.totalStatusCodeCount.options = {
|
||||||
|
"chart": {
|
||||||
|
type: 'discreteBarChart',
|
||||||
|
height: 200,
|
||||||
|
margin: {
|
||||||
|
top: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 40,
|
||||||
|
left: 55
|
||||||
|
},
|
||||||
|
x: function (d) {
|
||||||
|
return d.label;
|
||||||
|
},
|
||||||
|
y: function (d) {
|
||||||
|
return d.value;
|
||||||
|
},
|
||||||
|
showValues: true,
|
||||||
|
valueFormat: function (d) {
|
||||||
|
return d3.format('d')(d);
|
||||||
|
},
|
||||||
|
transitionDuration: 50,
|
||||||
|
yAxis: {
|
||||||
|
axisLabelDistance: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"enable": true,
|
||||||
|
"text": "Total Status Code Count",
|
||||||
|
"css": {
|
||||||
|
"textAlign": "center"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.graph.totalStatusCodeCount.data = [
|
||||||
|
{
|
||||||
|
key: "Total Status Code Count",
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
"label": "200",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Total Status Code Count graph
|
||||||
|
*
|
||||||
|
* @param {Object} totalStatusCodeCount Object from API
|
||||||
|
*/
|
||||||
|
function updateTotalStatusCodeCount(totalStatusCodeCount) {
|
||||||
|
|
||||||
|
// extract values
|
||||||
|
vm.graph.totalStatusCodeCount.data[0].values = [];
|
||||||
|
for (var code in totalStatusCodeCount) {
|
||||||
|
if (totalStatusCodeCount.hasOwnProperty(code)) {
|
||||||
|
vm.graph.totalStatusCodeCount.data[0].values.push({
|
||||||
|
label: code,
|
||||||
|
value: totalStatusCodeCount[code]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Total Status Code Count graph render
|
||||||
|
if (vm.graph.totalStatusCodeCount.api) {
|
||||||
|
vm.graph.totalStatusCodeCount.api.update();
|
||||||
|
} else {
|
||||||
|
console.error('fail');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.graph.averageResponseTime.options = {
|
||||||
|
chart: {
|
||||||
|
type: 'lineChart',
|
||||||
|
height: 200,
|
||||||
|
margin: {
|
||||||
|
top: 20,
|
||||||
|
right: 40,
|
||||||
|
bottom: 40,
|
||||||
|
left: 55
|
||||||
|
},
|
||||||
|
transitionDuration: 50,
|
||||||
|
x: function (d) {
|
||||||
|
return d.x;
|
||||||
|
},
|
||||||
|
y: function (d) {
|
||||||
|
return d.y;
|
||||||
|
},
|
||||||
|
useInteractiveGuideline: true,
|
||||||
|
xAxis: {
|
||||||
|
tickFormat: function (d) {
|
||||||
|
return d3.time.format('%X')(new Date(d));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
tickFormat: function (d) {
|
||||||
|
return d3.format(',.1f')(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"enable": true,
|
||||||
|
"text": "Average response time",
|
||||||
|
"css": {
|
||||||
|
"textAlign": "center"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var initialPoint = {
|
||||||
|
x: Date.now() - 3000,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
vm.graph.averageResponseTime.data = [
|
||||||
|
{
|
||||||
|
values: [initialPoint],
|
||||||
|
key: 'Average response time (ms)',
|
||||||
|
type: 'line',
|
||||||
|
color: '#2ca02c'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update average response time graph
|
||||||
|
*
|
||||||
|
* @param {Number} x Coordinate X
|
||||||
|
* @param {Number} y Coordinate Y
|
||||||
|
*/
|
||||||
|
function updateAverageResponseTimeGraph(x, y) {
|
||||||
|
|
||||||
|
// x multiply 1000 by because unix time is in seconds and JS Date are in milliseconds
|
||||||
|
var data = {
|
||||||
|
x: x * 1000,
|
||||||
|
y: y * 1000
|
||||||
|
};
|
||||||
|
vm.graph.averageResponseTime.data[0].values.push(data);
|
||||||
|
// limit graph entries
|
||||||
|
if (vm.graph.averageResponseTime.data[0].values.length > 100) {
|
||||||
|
vm.graph.averageResponseTime.data[0].values.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Average Response Time graph render
|
||||||
|
if (vm.graph.averageResponseTime.api) {
|
||||||
|
vm.graph.averageResponseTime.api.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all graph's datas
|
||||||
|
*
|
||||||
|
* @param {Object} health Health data from server
|
||||||
|
*/
|
||||||
|
function loadData(health) {
|
||||||
|
// Load datas and update Average Response Time graph render
|
||||||
|
updateAverageResponseTimeGraph(health.unixtime, health.average_response_time_sec);
|
||||||
|
|
||||||
|
// Load datas and update Total Status Code Count graph render
|
||||||
|
updateTotalStatusCodeCount(health.total_status_code_count);
|
||||||
|
|
||||||
|
// set data's view
|
||||||
|
vm.health = health;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action when load datas failed
|
||||||
|
*
|
||||||
|
* @param {Object} error Error state object
|
||||||
|
*/
|
||||||
|
function erroData(error) {
|
||||||
|
vm.health = {};
|
||||||
|
$log.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// first load
|
||||||
|
Health.get(loadData, erroData);
|
||||||
|
|
||||||
|
// Auto refresh data
|
||||||
var intervalId = $interval(function () {
|
var intervalId = $interval(function () {
|
||||||
Health.get(function (health) {
|
Health.get(loadData, erroData);
|
||||||
vm.health = health;
|
|
||||||
}, function (error) {
|
|
||||||
vm.health = {};
|
|
||||||
$log.error(error);
|
|
||||||
});
|
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
// Stop auto refresh when page change
|
||||||
$scope.$on('$destroy', function () {
|
$scope.$on('$destroy', function () {
|
||||||
$interval.cancel(intervalId);
|
$interval.cancel(intervalId);
|
||||||
});
|
});
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -2,45 +2,42 @@
|
||||||
<h1 class="text-danger">
|
<h1 class="text-danger">
|
||||||
<span class="glyphicon glyphicon-heart" aria-hidden="true"></span> Health
|
<span class="glyphicon glyphicon-heart" aria-hidden="true"></span> Health
|
||||||
</h1>
|
</h1>
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item">
|
<div class="row">
|
||||||
<span>Average response time sec :</span><span class="badge">{{healthCtrl.health.average_response_time_sec}}</span>
|
|
||||||
</li>
|
<div class="col-md-6">
|
||||||
<li class="list-group-item">
|
<div>
|
||||||
<span>Average response time :</span><span class="badge">{{healthCtrl.health.average_response_time}}</span>
|
<nvd3 options="healthCtrl.graph.averageResponseTime.options" data="healthCtrl.graph.averageResponseTime.data" api="healthCtrl.graph.averageResponseTime.api"></nvd3>
|
||||||
</li>
|
</div>
|
||||||
<li class="list-group-item">
|
<ul class="list-group">
|
||||||
<span>Total response time sec :</span><span class="badge">{{healthCtrl.health.total_response_time_sec}}</span>
|
<li class="list-group-item">
|
||||||
</li>
|
<span>Total response time :</span><span class="badge">{{healthCtrl.health.total_response_time}}</span>
|
||||||
<li class="list-group-item">
|
</li>
|
||||||
<span>Total response time :</span><span class="badge">{{healthCtrl.health.total_response_time}}</span>
|
</ul>
|
||||||
</li>
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Total count :</span><span class="badge">{{healthCtrl.health.total_count}}</span>
|
<span>PID :</span><span class="badge">{{healthCtrl.health.pid}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>PID :</span><span class="badge">{{healthCtrl.health.pid}}</span>
|
<span>Uptime :</span><span class="badge">{{healthCtrl.health.uptime}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
</ul>
|
||||||
<span>Uptime :</span><span class="badge">{{healthCtrl.health.uptime}}</span>
|
</div>
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
<div class="col-md-6">
|
||||||
<span>Uptime sec :</span><span class="badge">{{healthCtrl.health.uptime_sec}}</span>
|
<div>
|
||||||
</li>
|
<nvd3 options="healthCtrl.graph.totalStatusCodeCount.options" data="healthCtrl.graph.totalStatusCodeCount.data" api="healthCtrl.graph.totalStatusCodeCount.api"></nvd3>
|
||||||
<li class="list-group-item">
|
</div>
|
||||||
<span>Time :</span><span class="badge">{{healthCtrl.health.time}}</span>
|
<ul class="list-group">
|
||||||
</li>
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<span>Total count :</span><span class="badge">{{healthCtrl.health.total_count}}</span>
|
||||||
<span>Unixtime :</span><span class="badge">{{healthCtrl.health.unixtime}}</span>
|
</li>
|
||||||
</li>
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<span>Count :</span><span class="badge">{{healthCtrl.health.count}}</span>
|
||||||
<span>Status code count :</span><span class="badge">{{healthCtrl.health.status_code_count}}</span>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
<li class="list-group-item">
|
</div>
|
||||||
<span>Total status code count :</span><span class="badge">{{healthCtrl.health.total_status_code_count}}</span>
|
|
||||||
</li>
|
</div>
|
||||||
<li class="list-group-item">
|
|
||||||
<span>Count :</span><span class="badge">{{healthCtrl.health.count}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
.module('traefik.section', [
|
.module('traefik.section', [
|
||||||
'ui.router',
|
'ui.router',
|
||||||
'ui.bootstrap',
|
'ui.bootstrap',
|
||||||
|
'nvd3',
|
||||||
'traefik.section.providers',
|
'traefik.section.providers',
|
||||||
'traefik.section.health'
|
'traefik.section.health'
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
"bootstrap": "~3.3.5",
|
"bootstrap": "~3.3.5",
|
||||||
"angular-resource": "~1.4.7",
|
"angular-resource": "~1.4.7",
|
||||||
"angular-ui-router": "~0.2.15",
|
"angular-ui-router": "~0.2.15",
|
||||||
"angular-bootstrap": "~0.13.4"
|
"angular-bootstrap": "~0.13.4",
|
||||||
|
"angular-nvd3": "~1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
static/bower_components/angular-nvd3/dist/angular-nvd3.min.js
vendored
Normal file
1
static/bower_components/angular-nvd3/dist/angular-nvd3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
static/bower_components/d3/d3.min.js
vendored
Normal file
5
static/bower_components/d3/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bower_components/nvd3/build/nv.d3.min.css
vendored
Normal file
1
static/bower_components/nvd3/build/nv.d3.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
8
static/bower_components/nvd3/build/nv.d3.min.js
vendored
Normal file
8
static/bower_components/nvd3/build/nv.d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -13,6 +13,9 @@
|
||||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap-theme.min.css">
|
||||||
<link rel="stylesheet" href="bower_components/angular-bootstrap/ui-bootstrap-csp.css">
|
<link rel="stylesheet" href="bower_components/angular-bootstrap/ui-bootstrap-csp.css">
|
||||||
|
|
||||||
|
<!-- NVD3 -->
|
||||||
|
<link rel="stylesheet" href="bower_components/nvd3/build/nv.d3.min.css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -57,6 +60,9 @@
|
||||||
<script src="bower_components/angular-resource/angular-resource.min.js"></script>
|
<script src="bower_components/angular-resource/angular-resource.min.js"></script>
|
||||||
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
|
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
|
||||||
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
|
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
|
||||||
|
<script src="bower_components/d3/d3.min.js"></script>
|
||||||
|
<script src="bower_components/nvd3/build/nv.d3.min.js"></script>
|
||||||
|
<script src="bower_components/angular-nvd3/dist/angular-nvd3.min.js"></script>
|
||||||
<!-- end vendors -->
|
<!-- end vendors -->
|
||||||
|
|
||||||
<script src="app/traefik.js"></script>
|
<script src="app/traefik.js"></script>
|
||||||
|
|
|
@ -26,4 +26,7 @@ Do `npm install` and `bower install`
|
||||||
- [UI Router - Documentation](https://github.com/angular-ui/ui-router/wiki)
|
- [UI Router - Documentation](https://github.com/angular-ui/ui-router/wiki)
|
||||||
- [Bootstrap](http://getbootstrap.com)
|
- [Bootstrap](http://getbootstrap.com)
|
||||||
- [Angular Bootstrap](https://angular-ui.github.io/bootstrap)
|
- [Angular Bootstrap](https://angular-ui.github.io/bootstrap)
|
||||||
|
- [D3](http://d3js.org)
|
||||||
|
- [D3 - Documentation](https://github.com/mbostock/d3/wiki)
|
||||||
|
- [NVD3](http://nvd3.org)
|
||||||
|
- [Angular nvD3](http://krispo.github.io/angular-nvd3)
|
||||||
|
|
Loading…
Reference in a new issue