Start on adding usage charts
This commit is contained in:
parent
a7ab14479e
commit
63cd6ffcc3
9 changed files with 192 additions and 0 deletions
|
@ -4,13 +4,46 @@ import json
|
||||||
from flask import request, Blueprint, abort, Response
|
from flask import request, Blueprint, abort, Response
|
||||||
from flask.ext.login import current_user
|
from flask.ext.login import current_user
|
||||||
from auth.auth import require_session_login
|
from auth.auth import require_session_login
|
||||||
|
from endpoints.common import route_show_if
|
||||||
from app import userevents
|
from app import userevents
|
||||||
|
from auth.permissions import SuperUserPermission
|
||||||
|
|
||||||
|
import features
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
realtime = Blueprint('realtime', __name__)
|
realtime = Blueprint('realtime', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@realtime.route("/ps")
|
||||||
|
@route_show_if(features.SUPER_USERS)
|
||||||
|
@require_session_login
|
||||||
|
def ps():
|
||||||
|
if not SuperUserPermission().can():
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
def generator():
|
||||||
|
while True:
|
||||||
|
data = {
|
||||||
|
'count': {
|
||||||
|
'cpu': psutil.cpu_percent(interval=1, percpu=True),
|
||||||
|
'virtual_mem': psutil.virtual_memory(),
|
||||||
|
'swap_mem': psutil.swap_memory(),
|
||||||
|
'connections': len(psutil.net_connections()),
|
||||||
|
'processes': len(psutil.pids()),
|
||||||
|
'network': psutil.net_io_counters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json_string = json.dumps(data)
|
||||||
|
yield 'data: %s\n\n' % json_string
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
return Response(generator(), mimetype="text/event-stream")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@realtime.route("/user/")
|
@realtime.route("/user/")
|
||||||
@require_session_login
|
@require_session_login
|
||||||
def index():
|
def index():
|
||||||
|
|
|
@ -41,3 +41,4 @@ git+https://github.com/DevTable/anunidecode.git
|
||||||
git+https://github.com/DevTable/avatar-generator.git
|
git+https://github.com/DevTable/avatar-generator.git
|
||||||
git+https://github.com/DevTable/pygithub.git
|
git+https://github.com/DevTable/pygithub.git
|
||||||
gipc
|
gipc
|
||||||
|
psutil
|
||||||
|
|
|
@ -37,6 +37,7 @@ marisa-trie==0.7
|
||||||
mixpanel-py==3.2.1
|
mixpanel-py==3.2.1
|
||||||
paramiko==1.15.2
|
paramiko==1.15.2
|
||||||
peewee==2.4.5
|
peewee==2.4.5
|
||||||
|
psutil==2.2.0
|
||||||
psycopg2==2.5.4
|
psycopg2==2.5.4
|
||||||
py-bcrypt==0.4
|
py-bcrypt==0.4
|
||||||
pycrypto==2.6.1
|
pycrypto==2.6.1
|
||||||
|
|
24
static/directives/ps-usage-graph.html
Normal file
24
static/directives/ps-usage-graph.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<div class="ps-usage-graph-element">
|
||||||
|
CPU:
|
||||||
|
<div class="realtime-line-chart" data="data.count.cpu" counter="counter"
|
||||||
|
label-template="CPU #{x} %"></div>
|
||||||
|
|
||||||
|
Process Count:
|
||||||
|
<div class="realtime-line-chart" data="data.count.processes" counter="counter"
|
||||||
|
label-template="Process Count"></div>
|
||||||
|
|
||||||
|
Virtual Memory:
|
||||||
|
<div class="realtime-line-chart" data="data.count.virtual_mem[2]" counter="counter"
|
||||||
|
label-template="Virtual Memory %"></div>
|
||||||
|
|
||||||
|
Swap Memory:
|
||||||
|
<div class="realtime-line-chart" data="data.count.swap_mem[3]" counter="counter"
|
||||||
|
label-template="Swap Memory %"></div>
|
||||||
|
|
||||||
|
Network Connections:
|
||||||
|
<div class="realtime-line-chart" data="data.count.connections" counter="counter"
|
||||||
|
label-template="Network Connection Count"></div>
|
||||||
|
|
||||||
|
Network Usage:
|
||||||
|
<div class="realtime-line-chart" data="data.count.network" labels="['Bytes In', 'Bytes Out']" counter="counter"></div>
|
||||||
|
</div>
|
3
static/directives/realtime-line-chart.html
Normal file
3
static/directives/realtime-line-chart.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="realtime-line-chart-element">
|
||||||
|
<div class="chart" style="width: 450px; height: 250px;"></div>
|
||||||
|
</div>
|
123
static/js/app.js
123
static/js/app.js
|
@ -6522,6 +6522,129 @@ quayApp.directive('locationView', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
quayApp.directive('realtimeLineChart', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/realtime-line-chart.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'data': '=data',
|
||||||
|
'labels': '=labels',
|
||||||
|
'counter': '=counter',
|
||||||
|
'labelTemplate': '@labelTemplate'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element) {
|
||||||
|
var graph = null;
|
||||||
|
var hoverDetail = null;
|
||||||
|
var series = [];
|
||||||
|
var counter = 0;
|
||||||
|
var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } );
|
||||||
|
|
||||||
|
var setupGraph = function() {
|
||||||
|
graph = new Rickshaw.Graph({
|
||||||
|
element: $element.find('.chart')[0],
|
||||||
|
renderer: 'line',
|
||||||
|
series: series,
|
||||||
|
min: 'auto',
|
||||||
|
padding: {
|
||||||
|
'top': 0.1,
|
||||||
|
'left': 0.01,
|
||||||
|
'right': 0.01,
|
||||||
|
'bottom': 0.1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hoverDetail = new Rickshaw.Graph.HoverDetail({
|
||||||
|
graph: graph,
|
||||||
|
xFormatter: function(x) {
|
||||||
|
return x.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var refresh = function(data) {
|
||||||
|
if (!data) { return; }
|
||||||
|
if (!graph) {
|
||||||
|
setupGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data == 'number') {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope.labels) {
|
||||||
|
data = data.slice(0, $scope.labels.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (series.length == 0){
|
||||||
|
for (var i = 0; i < data.length; ++i) {
|
||||||
|
var title = $scope.labels ? $scope.labels[i] : $scope.labelTemplate.replace('{x}', i + 1);
|
||||||
|
series.push({
|
||||||
|
'color': palette.color(),
|
||||||
|
'data': [],
|
||||||
|
'name': title
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
for (var i = 0; i < data.length; ++i) {
|
||||||
|
var arr = series[i].data;
|
||||||
|
arr.push({
|
||||||
|
'x': counter,
|
||||||
|
'y': data[i]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (arr.length > 10) {
|
||||||
|
series[i].data = arr.slice(arr.length - 10, arr.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch('counter', function(counter) {
|
||||||
|
refresh($scope.data_raw);
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$watch('data', function(data) {
|
||||||
|
$scope.data_raw = data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
quayApp.directive('psUsageGraph', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/ps-usage-graph.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
},
|
||||||
|
controller: function($scope, $element) {
|
||||||
|
$scope.counter = -1;
|
||||||
|
$scope.data = null;
|
||||||
|
|
||||||
|
var source = new EventSource('/realtime/ps');
|
||||||
|
source.onmessage = function(e) {
|
||||||
|
$scope.$apply(function() {
|
||||||
|
$scope.counter++;
|
||||||
|
$scope.data = JSON.parse(e.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
quayApp.directive('avatar', function () {
|
quayApp.directive('avatar', function () {
|
||||||
var directiveDefinitionObject = {
|
var directiveDefinitionObject = {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
|
|
1
static/lib/rickshaw.min.css
vendored
Normal file
1
static/lib/rickshaw.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
3
static/lib/rickshaw.min.js
vendored
Normal file
3
static/lib/rickshaw.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,7 @@
|
||||||
<div class="container" quay-show="Features.SUPER_USERS && showInterface">
|
<div class="container" quay-show="Features.SUPER_USERS && showInterface">
|
||||||
|
|
||||||
|
<div class="ps-usage-graph"></div>
|
||||||
|
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
This panel provides administrator access to <strong>super users of this installation of the registry</strong>. Super users can be managed in the configuration for this installation.
|
This panel provides administrator access to <strong>super users of this installation of the registry</strong>. Super users can be managed in the configuration for this installation.
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue