Bug fix, layout and charting improvements

community
Steve L. Nyemba 6 years ago
parent 407eb6f8ca
commit 117cd3840f

@ -270,6 +270,9 @@ def get_clients():
return ('',403)
@app.route('/1/clients',methods=['POST'])
def set_clients() :
"""
adding a client to the
"""
if 'key' in session :
clients = request.get_json(silent=True)
#
@ -284,6 +287,9 @@ def set_clients() :
# writer.set({"clients":clients})
writer.set(clients=clients)
return ('',200)
else:
ERROR_CODE = 403 if 'key' not in session else 400
return ('',ERROR_CODE)
@app.route("/1/emails",methods=['GET'])
def get_emails():
@ -379,7 +385,7 @@ def client_log():
logs = [body]
LIMIT = 40
if len(logs) > LIMIT :
log = logs[LIMIT:]
log = logs[:LIMIT]
document[context][node] = {"date":date,"logs":logs}
writer.set(**document)
# writer.write (label=context,data=row)
@ -519,49 +525,56 @@ def folder_logs(id):
except Exception,e:
print e;
return r,status
@app.route("/1/set/logs",methods=["POST"])
def set_logs() :
if 'key' not in session :
return ('',403)
else :
key = session['key']
@app.route('/1/get/logs')
def get_logs() :
"""
@deprecate
"""
r = {}
#session['key'] = 'c259e8b1-e2fb-40df-bf03-f521f8ee352d'
key = session['key'] if 'key' in session else None
if key is None and 'key' in request.headers:
key = request.headers['key']
if key is None :
return json.dumps(r)
else:
try:
#gReader = factory.instance(type=class_read,args=p)
#plan = gReader.view('plans/active',key=key)
plan = session['plan']
if plan :
dbname = plan['name']
args = str(json.dumps(p))
args = json.loads(args)
args['dbname'] = dbname
args['uid'] = key
#
# Let us persis this information (as well as the key)
#session['plan'] = plan['name']
session['store']= args
session['key'] = key
scope = ['app_resources','folder_info','app_status_details','app_resource_usage_details'] #,'emails','log_size']
gReader = factory.instance(type=class_read,args=args)
for id in scope :
view = ('summary/'+id).strip()
r[id] = gReader.view(view,key=key)
if 'logs' in session :
for id in session['logs'] :
r[id] = session['logs'][id]
# r[id] = r[node_id]
except Exception,e:
print (e)
return json.dumps(r)
pass
# @app.route('/1/get/logs')
# def get_logs() :
# """
# @deprecate
# """
# r = {}
# #session['key'] = 'c259e8b1-e2fb-40df-bf03-f521f8ee352d'
# key = session['key'] if 'key' in session else None
# if key is None and 'key' in request.headers:
# key = request.headers['key']
# if key is None :
# return json.dumps(r)
# else:
# try:
# #gReader = factory.instance(type=class_read,args=p)
# #plan = gReader.view('plans/active',key=key)
# plan = session['plan']
# if plan :
# dbname = plan['name']
# args = str(json.dumps(p))
# args = json.loads(args)
# args['dbname'] = dbname
# args['uid'] = key
# #
# # Let us persis this information (as well as the key)
# #session['plan'] = plan['name']
# session['store']= args
# session['key'] = key
# scope = ['app_resources','folder_info','app_status_details','app_resource_usage_details'] #,'emails','log_size']
# gReader = factory.instance(type=class_read,args=args)
# for id in scope :
# view = ('summary/'+id).strip()
# r[id] = gReader.view(view,key=key)
# if 'logs' in session :
# for id in session['logs'] :
# r[id] = session['logs'][id]
# # r[id] = r[node_id]
# except Exception,e:
# print (e)
# return json.dumps(r)
@app.route("/1/set/logs",methods=['PUT'])
def update_profile():
try:
@ -616,71 +629,71 @@ def get_usage_trend():
return json.dumps(r)
@app.route("/1/app/usage/trend")
def get_usage_detail():
"""
@deprecate
This function returns detailed information about usage per application monitored. It will return the 24 most recent observations in the logs
@param node node identifier e.g: apps@zulu.io
@return {node_x:{app_1:{memory_usage:[],cpu_usage:[]}},...}
"""
r = {}
try:
if 'id' not in request.args and 'node' not in request.args :
id = session['default.node']
else:
id = request.args['id'] if 'id' in request.args else request.args.get('node')
if 'app' not in request.args :
if 'default.app' in session :
app_id = session['default.app']
else:
app_id = None
else:
app_id = request.args.get('app')
#
# removing trailing white spaces
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/app_resource_usage_details',key=p['uid'])
id = id.strip()
if app_id is not None :
app_id = app_id.strip()
r = r[id][app_id]
else :
r = r[id]
except Exception,e:
print ' *** ',(e)
return json.dumps(r)
@app.route('/1/app/status')
def app_status() :
"""
@deprecate
This function aggregates the number of crashes/running/idle instances found in the past 24 log entries
for a particular application
@param nid node identifier e.g: app@zulu.io
@param app application identifier e.g: kate, firefox, chrome ... specified in the configuraiton
"""
r = []
try:
nid = request.args.get('node') # Node identifier
aid = request.args.get('app') # application identifier
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/app_status_details',key=p['uid'])
#
#@TODO: Once the back-end enables the nodes in which the application is running, uncomment the line below
#
print[nid,aid]
r = r[nid][aid]
except Exception,e:
print e
return json.dumps(r)
# @app.route("/1/app/usage/trend")
# def get_usage_detail():
# """
# @deprecate
# This function returns detailed information about usage per application monitored. It will return the 24 most recent observations in the logs
# @param node node identifier e.g: apps@zulu.io
# @return {node_x:{app_1:{memory_usage:[],cpu_usage:[]}},...}
# """
# r = {}
# try:
# if 'id' not in request.args and 'node' not in request.args :
# id = session['default.node']
# else:
# id = request.args['id'] if 'id' in request.args else request.args.get('node')
# if 'app' not in request.args :
# if 'default.app' in session :
# app_id = session['default.app']
# else:
# app_id = None
# else:
# app_id = request.args.get('app')
# #
# # removing trailing white spaces
# gReader = factory.instance(type=class_read,args=p)
# r = gReader.view('summary/app_resource_usage_details',key=p['uid'])
# id = id.strip()
# if app_id is not None :
# app_id = app_id.strip()
# r = r[id][app_id]
# else :
# r = r[id]
# except Exception,e:
# print ' *** ',(e)
# return json.dumps(r)
# @app.route('/1/app/status')
# def app_status() :
# """
# @deprecate
# This function aggregates the number of crashes/running/idle instances found in the past 24 log entries
# for a particular application
# @param nid node identifier e.g: app@zulu.io
# @param app application identifier e.g: kate, firefox, chrome ... specified in the configuraiton
# """
# r = []
# try:
# nid = request.args.get('node') # Node identifier
# aid = request.args.get('app') # application identifier
# gReader = factory.instance(type=class_read,args=p)
# r = gReader.view('summary/app_status_details',key=p['uid'])
# #
# #@TODO: Once the back-end enables the nodes in which the application is running, uncomment the line below
# #
# print[nid,aid]
# r = r[nid][aid]
# except Exception,e:
# print e
# return json.dumps(r)
#@app.route('/get/<id>')
@ -831,30 +844,30 @@ def InitCollector():
This function/endpoint will assess n-virtual environments and return the results
@TODO: Should this be stored for future mining (I don't think so but could be wrong)
"""
@app.route('/sandbox')
def sandbox():
global CONFIG
if 'sandbox' in CONFIG: #CONFIG['monitor']:
#handler = HANDLERS['sandbox']['class']
#conf = HANDLERS['sandbox']['config']
r = []
# p = Factory.instance('sandbox',CONFIG)
handler = monitor.Sandbox()
conf = CONFIG['sandbox']
for id in conf:
try:
handler.init(conf[id])
r.append (dict(handler.composite(),**{"label":id}))
except Exception as e:
pass
else:
r = []
return json.dumps(r)
# @app.route('/sandbox')
# def sandbox():
# global CONFIG
# if 'sandbox' in CONFIG: #CONFIG['monitor']:
# #handler = HANDLERS['sandbox']['class']
# #conf = HANDLERS['sandbox']['config']
# r = []
# # p = Factory.instance('sandbox',CONFIG)
# handler = monitor.Sandbox()
# conf = CONFIG['sandbox']
# for id in conf:
# try:
# handler.init(conf[id])
# r.append (dict(handler.composite(),**{"label":id}))
# except Exception as e:
# pass
# else:
# r = []
# return json.dumps(r)
#@app.route('/trends')
#def trends ():
#id = request.args.get('id')
@ -1046,43 +1059,86 @@ def user():
#d = []
#return json.dumps(d)
@app.route("/1/plot/<id>",methods=['POST'])
def prepare_plot(id):
if 'key' in session :
body = request.get_json(silent=True)
REF = {"apps":['mem','cpu'],"folders":['files','size_in_kb']}
try:
node = body['node']
names = body['names']
params = REF[id]
args = {"type":SYS_STORE['class']['read'],"args":SYS_STORE['args']}
args['args']['uid'] = session['key']
args['context'] = SYS_ARGS.PARAMS['context']
dhandler = didact(config=args,key=session['key'])
logs = dhandler.m[id].filter_logs(node=node,names=names,params=params)
#
#
df = pd.DataFrame(logs)
q = []
XRAM = []
XCPU = []
xn = 0
xn_=0
html = """
The following are the last :count entries of
The analysis an average of :mean % usage, with recorded variatons of :sqrt
<br>Drops or spikes that are +/- :n would classify
"""
for name in names :
xram_ = df[df.name == name]['mem'].values.tolist()[-12:]
xcpu_ = df[df.name == name]['cpu'].values.tolist()[-12:]
xn = len(xram_) if len(xram_) > xn else xn
xn_ = len(xcpu_) if len(xcpu_) > xn_ else xn_
XRAM.append(xram_)
XCPU.append(xcpu_)
mean = np.mean(xram_)
max_ = np.max(xram_)
# X.append(np.random.choice(100,4).tolist())
q = [{"info":"Monitoring RAM consumption trends","ylabel":"% used","node":node,"x":XRAM,"labels":np.arange(1,xn).tolist(),"series":names,"title":"RAM Usage"}]
q.append({"info":"Monitoring CPU consumption trends","ylabel":"% used","node":node,"x":XCPU,"labels":np.arange(1,xn_).tolist(),"series":names,"title":"CPU Usage"})
key = 'app.trend.'+node
session[key] = q
return (key,200)
except Exception,e:
print (e)
return ('',400)
# return render_template("dashboard/apps/data-grid.html",body)
else:
return ('',403)
@app.route("/1/plot/<format>/<id>/<key>",methods=['GET'])
def get_charts(format,id,key):
remove = request.args['no'].split(',') if 'no' in request.args else []
series = ['series_1']
# args = dict(session[key],**{"remove":remove})
# print session['cloud-info']
# if id == 'pie' :
# X = list(np.arange(3) * np.random.randn() + 10)
# X[2] = 23.5
# else :
# X = []
# series = []
# for i in range(0,3):
# X.append([ np.random.randn()+10 for i in range(0,3)])
# series.append('series '+str(i))
# labels = session['cloud-info']['labels'] #['Foo','Boo','Joo']
# title = 'Do More'
# series = [ 'Series '+str(i+1) for i in range(len(labels))]
# args = {"x":X,"labels":labels,"title":title,"series":series,"remove":remove}
args = session[key]
if isinstance(args,list) :
if isinstance(args,list) and 'index' in request.args:
index = int(request.args['index'])
args = args[index]
args['remove'] = remove
info = [Graph.instance(format,id,**args)]
else:
# print args
info = [ Graph.instance(format,id, **dict(item,**{'remove':remove})) for item in args]
# if remove is not None :
args['remove'] = remove
# args['remove'] = remove
info = Graph.instance(format,id,**args)
# info = Graph.instance(format,id,**args)
if format in ['image','png','jpeg','jpg'] :
# g = ImageGraphs()
# stream = g.pie(X,labels,title)
return Response(info,mimetype='image/png')
else:
args = {'chart_id': ('g_'+id)}
args['config'] = info
args['info'] = info
args['context'] = SYS_ARGS.PARAMS['context'] if 'context' in SYS_ARGS.PARAMS else ''
return render_template('dashboard/graphs/chart.html',**args)
if __name__== '__main__':

@ -16,7 +16,7 @@ body {
.left {float:left}
.right{float:right}
.no-float{float:none}
.maroon {color:maroon}
.title-bar {padding:4px; margin:4px}
.title-bar .title {font-size:18px;}
.jsgrid-edit-row > .jsgrid-cell {

@ -1,44 +1,24 @@
<meta class="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">
<link href="{{context}}static/css/fa/css/font-awesome.css" type="text/css" rel="stylesheet">
<link href="{{context}}static/css/fa/animation.css" rel="stylesheet" type="text/css">
<link href="{{context}}/static/css/default.css" type="text/css" rel="stylesheet">
<link href="{{context}}/static/css/fa/css/font-awesome.css" type="text/css" rel="stylesheet">
<link href="{{context}}/static/css/fa/animation.css" rel="stylesheet" type="text/css">
<script src="{{context}}/static/js/jquery/jquery.min.js"></script>
<script src="{{context}}/static/js/jx/dom.js"></script>
<link href="{{context}}/static/js/jsgrid/jsgrid.css" rel="stylesheet" type="text/css">
<link href="{{context}}/static/js/jsgrid/jsgrid-theme.css" rel="stylesheet" type="text/css">
<script src="{{context}}/static/js/jsgrid/jsgrid.js"></script>
<script src="{{context}}/static/js/jx/dom.js"></script>
<script src="{{context}}/static/js/jx/rpc.js"></script>
<link href="{{context}}/static/css/default.css" rel="stylesheet" type="text/css">
<script>
var DATA_GRID={{grid|tojson}}
var STATUS_ICONS = {
"S":"fa ellipsis-h",
"T":"fa fa-times",
"Z":"fa fa-exclamation-triangle",
"R":"fa fa-check"
}
DATA_GRID.width = '100%'
DATA_GRID.rowClass = function(item,index){
return "small"
}
$(document).ready(function(){
$("#grid").jsGrid(DATA_GRID)
})
</script>
<body>
<div class="title-bar">
<span class="title">Application/Processes</span>
<div>
<div>
<div class="bold">RAM</div>
</div>
<div class="search-box border" style="padding:2px; margin-bottom:4px; display:grid; grid-template-columns: auto 64px">
<input type="text" id="search" placeholder="[Enter Application Name]" onkeyup="on_keyup(event)"/>
<div class="default" style="display:grid; grid-template-columns: 50% 50%; grid-gap:2px">
<div class="active" align="center" onclick="save_emails()"><i class="fa fa-check"></i></div>
<div class="active" align="center" onclick="clear_emails()"><i class="fa fa-times"></i></div>
</div>
<div>
<div class="bold">CPU</div>
</div>
<div id="grid"></div>
</div>
</body>

@ -1,3 +1,4 @@
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">
<!--
This file is designed to provide a summary view of a given node
@ -6,6 +7,7 @@
<link href="{{context}}/static/css/fa/css/font-awesome.css" type="text/css" rel="stylesheet">
<link href="{{context}}/static/css/fa/font-awesome-animation.css" rel="stylesheet" type="text/css">
<script src="{{context}}/static/js/jquery/jquery.min.js"></script>
<script src="{{context}}/static/js/jx/ext/modal.js"></script>
<script src="{{context}}/static/js/jx/dom.js"></script>
<link href="{{context}}/static/js/jsgrid/jsgrid.css" rel="stylesheet" type="text/css">
<link href="{{context}}/static/js/jsgrid/jsgrid-theme.css" rel="stylesheet" type="text/css">
@ -42,8 +44,8 @@
font-size:18px;
align-items: center;
display:grid;
grid-template-columns: auto 95px;
grid-gap:2px;
grid-template-columns: 70% auto;
grid-gap:1px;
min-height:24px;
}
.widget .chart {
@ -104,6 +106,7 @@
.fa-times {color:maroon}
.fa-folder-open {color:#FF7F24;}
.fa-cog {color:gray}
.fa-dashboard {color:#4682b4}
.busy {
display:flex ;
align-items: center;
@ -111,6 +114,17 @@
height:100%;
}
.action-group {display:grid; grid-gap:1px; grid-template-columns:repeat(3,64px); justify-content: end}
.hidden {display:none}
.dialog-frame {
padding:4px;
width:50%;
}
.dialog {padding:4px; font-size:12px; min-height:10%}
.dialog .title { font-weight: bold; padding:4px; margin-bottom:4px; background:#f3f3f3; }
.dialog .title i {color:ff5733}
.dialog .message {padding:8px; font-family:verdana; min-height:10%}
</style>
<script>
@ -126,19 +140,129 @@
// config.data = apps
// $('#grid').jsGrid(config)
// })
var grid = {}
grid.format = {}
grid.format.apps = function(){
var m = {}
jx.utils.patterns.visitor(logs,function(row){
var id = row.name
if (m[id] == null){
m[id] = {"name":id,"users":1,"proc_count":1,"mem":row.mem,"cpu":row.cpu}
}else{
m[id].users += 1
m[id].proc_count += 1
m[id].mem += row.mem
m[id].cpu += row.cpu
}
})
}
{{app_summary|tojson}}
var render_grid = function(name){
var logs = {{app_logs|tojson}}[name]['logs']
var id = '#app_grid_'+name
var config = {{ app_grid|tojson}}
config.data = logs
var _id = id.replace('#','')
jx.dom.set.attribute(_id,'selected',{})
config.fields[0].itemTemplate = function(value,item){
var i = jx.dom.get.instance('I')
var selected = jx.dom.get.attribute(_id,'selected')
var key = item.name+'@'+item.user
if(selected[key] == null){
i.className = 'fa fa-square-o'
}else{
i.className = 'fa fa-check'
}
i.data = item
i.onclick = function(){
var selected = jx.dom.get.attribute(_id,'selected')
var key = this.data.name+'@'+this.data.user
if(this.className == 'fa fa-square-o') {
this.className = 'fa fa-check'
selected[key] = this.data
}else{
this.className = 'fa fa-square-o'
delete selected[key]
}
jx.dom.set.attribute(_id,'selected',selected)
$(id).jsGrid("option","fields")[0].headerTemplate() //.headerTemplate()
// $(id).jsGrid("refresh")
// console.log(p)
}
return i
}
config.fields[0].headerTemplate = function(){
// if(_id == null){
// this.title = null
// }else{
// console.log(keys.length == 0)
// if (keys.length > 0){
var i = jx.dom.get.instance('I')
i.className = 'active fa fa-line-chart'
i.onclick = function(){
var selected = jx.dom.get.attribute(_id,'selected')
var keys = Object.keys(selected)
if(keys.length == 0){
jx.dom.set.value('dialog_title','<i class="fa fa-warning"></i> Trends')
jx.dom.set.value('dialog_msg','Select a row to visualize trends')
var html = jx.dom.get.value('dialog').replace(/hidden/,'')
jx.modal.show(html)
}else{
var uri = '/monitor/1/plot/apps'
var body = {node:_id.replace(/app_grid_/,'')}
body.names = jx.utils.patterns.visitor(keys,function(id){
return selected[id].name
})
var httpclient = HttpClient.instance()
httpclient.setData(JSON.stringify(body))
httpclient.setHeader("Content-Type","application/json")
httpclient.post(uri,function(x){
if(x.status == 200){
var key = x.responseText.trim()
jx.modal.show({url:'/monitor/1/plot/html/line/'+key+'?draw-all' })
}else{
console.log(x.status)
}
})
}
}
this.title = i
// }
return (this.title === undefined || this.title === null) ? this.name : this.title;
// }else{
}
config.fields[config.fields.length-1].itemTemplate = function(value,item){
var p = {"X":"fa fa-times","S":"fa fa-ellipsis-h","S+":"fa fa-ellipsis-h","R":"fa fa-check"}
var i = jx.dom.get.instance('I')
i.className = p[value] != null? p[value]: 'fa fa-cog fa-spin'
return i
}
var id = '#app_grid_'+name
$(id).jsGrid(config)
}
/**
@ -161,23 +285,42 @@
<div class="small bold" style="margin-top:10px; color:#4682B4">Loading dashboard ...</div>
</div>
</div>
<div id="dialog" class="dialog-frame hidden">
<div class="dialog">
<div id="dialog_title" class="title">
</div>
<div id="dialog_msg" class="message">
</div>
<div>
<div class="button border-round border" align="center">
Ok
</div>
</div>
</div>
</div>
<div class="board">
<div class="search">
<!-- <div class="search">
<input type="text" placeholder="[Node/Data Collector]">
<div align="left" style="align-items: center">
<span class="active"><i class="fa fa-trash"></i></span>
</div>
</div>
</div> -->
<div class=" border-round">
{% for name in nodes %}
<div class="widget">
<div class="title border-bottom" align='center'>
<h3>{{name}}</h3>
<div>
<div align="center">
<h3>{{name}}</h3>
</div>
<div class="action-group" align="right">
<span class="active"><i class="fa fa-file-pdf-o"></i></span>
<span id="{{name}}_o" class="active" onclick="show_hide(['{{name}}_data','{{name}}_i'],['{{name}}','{{name}}_o'])" ><i class="fa fa-th" style="color:darkgray"></i></span>
<span id="{{name}}_i" class="active" onclick="show_hide(['{{name}}','{{name}}_o'],['{{name}}_i','{{name}}_data'])" style="display:none"><i class="fa fa-pie-chart" style=" color:orangered"></i></span>
<div id="{{name}}_i" title="Dashboard" class="active" onclick="show_hide(['{{name}}'],['{{name}}_data'])" style="margin:1px; padding-left:20px; padding-right:20px; background-color:#f3f3f3"><i class="fa fa-dashboard" style=""></i></div>
<div id="{{name}}_o" title="Data Trends" class="active" onclick="show_hide(['{{name}}_data'],['{{name}}'])" style="margin:1px; padding-left:20px; padding-right:20px; background-color:#f3f3f3"><i class="fa fa-th" style=""></i></div>
<div class="active" title="Download Data" style="margin:1px; padding-left:20px; padding-right:20px; background-color:#f3f3f3"><i class="fa fa-download"></i></div>
</div>
@ -328,6 +471,12 @@
</div>
<div id="{{name}}_data"class="grid no-border" style="display:none;">
<p>
Apps On <b>{{name}}</b>
<div class="small">
click select names and visualize trends
</div>
</p>
<div id="app_grid_{{name}}" style="margin-top:10px;"></div>
<script>

@ -1,3 +1,4 @@
<meta charset="utf-8"/>
<!--
generating client keys
-->

@ -1,9 +1,13 @@
<meta charset="utf-8"/>
<!-- <link rel="shortcut icon" href="{{context}}/static/img/logo-small.png" type="image/x-icon"> -->
<link rel="icon" href="{{context}}/static/img/logo-small.png" type="image/x-icon">
<link href="{{context}}/static/css/default.css" type="text/css" rel="stylesheet">
<link href="{{context}}/static/chartist/chartist.css" type="text/css" rel="stylesheet">
<script src="{{context}}/static/js/chart.js/chart.bundle.js"></script>
<script src="{{context}}/static/js/jquery/jquery.min.js"></script>
<script src="{{context}}/static/js/jx/dom.js"></script>
<script src="{{context}}/static/js/jx/utils.js"></script>
<script src="{{context}}/static/js/jx/ext/math.js"></script>
{% block content %} {% endblock%}

@ -1,53 +1,53 @@
{% extends 'dashboard/graphs/base.html' %}
{% block content %}
<style>
.board {
display:grid;
grid-template-columns: repeat(auto-fit,49%);
grid-gap:0px;
}
.border-round {padding:8px; margin:8px; border-radius:8px;}
.title {margin:4px; font-size:18px; font-family:verdana}
</style>
<script>
$(document).ready(function(){
// Chart.plugins.register({
// afterDatasetsDraw: function(chart) {
// var ctx = chart.chart.ctx;
// chart.data.datasets.forEach(function(dataset, i) {
// var meta = chart.getDatasetMeta(i);
// if (!meta.hidden) {
// meta.data.forEach(function(element, index) {
// // Draw the text in black, with the specified font
// ctx.fillStyle = 'rgb(0, 0, 0)';
// var fontSize = 16;
// var fontStyle = 'normal';
// var fontFamily = 'Helvetica Neue';
// ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
// // Just naively convert to string for now
// var dataString = dataset.datalabels[index].toString();
// // Make sure alignment settings are correct
// ctx.textAlign = 'center';
// ctx.textBaseline = 'middle';
// ctx.fillStyle = 'white'
// var padding = 5;
// var position = element.tooltipPosition();
var render_chart =function(index,config){
var id = 'chart_'+index
var canvas = jx.dom.get.instance('CANVAS')
var context = canvas.getContext('2d')
jx.dom.append(id,canvas)
new Chart(context, config)
// ctx.fillText(dataString, position.x -40 , position.y - (fontSize / 2) - padding);
// });
// }
// });
// }
// });
var context = document.getElementById('{{chart_id|safe}}').getContext('2d')
var args = {{config|tojson}}
// args.options.plugins.datalabels = {backgroundColor:'rgba(242,242,242,0.7)',
// display:function(context){
// var labels = context.dataset.datalabels
// var index = context.dataIndex
// return labels[index]
// }
// }
new Chart(context, args)
})
}
// $(document).ready(function(){
// })
</script>
<div>
<canvas id="{{chart_id|safe}}"></canvas>
</div>
<body>
{% if info|length == 1 %}
<div>
{% else %}
<div class="board">
{% endif %}
{% for config in info %}
{% if info|length > 1%}
<div class="border border-round">
{% else %}
<div>
{% endif %}
<div class="title bold" align="center">{{config.title}}</div>
<!-- <canvas id="{{chart_id_|safe}}"></canvas> -->
<div id="chart_{{loop.index|int}}"></div>
<div id="descr_{{loop.index|int}}" class="border-top" align="center">
<br>{{config.info}}
</div>
<script>
render_chart({{loop.index|int}},{{config|tojson}})
</script>
</div>
{% endfor %}
</div>
</body>
{% endblock %}

@ -1,6 +1,7 @@
<!--
Managing user emails that will be notified or receive emails from the user
-->
<meta charset="utf-8"/>
<script src="{{context}}/static/js/jquery/jquery.min.js"></script>
<script src="{{context}}/static/js/jx/dom.js"></script>

@ -19,6 +19,7 @@ class Graph :
@param format format of the chart to be rendered <{image,png,jpeg}| html>
@param name name of the chart (pie|scatter|line|bar)
"""
_objects = []
if format.lower() in ['jpeg','svg','image','png','jpg','bmp','tiff'] :
_object = ImageGraphs(format,**args)
else:
@ -115,6 +116,7 @@ class HTMLGraph(Graph):
if len(X) == 2 :
config['options']['cutoutPercentage']= 70
config['info'] = self.args['info'] if 'info' in self.args else ''
return config
def bar(self):
config = self.line()
@ -127,7 +129,7 @@ class HTMLGraph(Graph):
labels = self.args['labels']
title = self.args['title']
series = self.args['series']
config = {"type":"line","responsive":True,"data":{"datasets":[],"labels":labels}}
config = {"title":title,"type":"line","responsive":True,"data":{"datasets":[],"labels":labels}}
config["options"] = {"responsive":True,"legend":{"position":"right","display":False},"title":{"display":True,"text":title},"animation":{"animateScale":True,"animateRotate":True}}
if 'legend' not in self.args['remove'] :
config['options']['legend']["display"] = True
@ -137,6 +139,7 @@ class HTMLGraph(Graph):
if "xlabel" in self.args :
config['options']['scales']['xAxes'] = [{"scaleLabel":{"display":True,"labelString":self.args['xlabel']}}]
config["data"]["labels"] = labels
config['info'] = self.args['info'] if 'info' in self.args else ''
if isinstance(X[0],list) == False :
X = [X[0]]

@ -19,7 +19,37 @@ class analytics :
self.cache = {}
self.cache['key'] = args['key']
self.cache['name'] = self.__class__.__name__
self.init()
#
# Let's extract the logs for processing later on
#
id = self.get('name')
self.raw_logs = self.handler.read()[id]
def filter_logs(self,**args):
"""
This function will filter logs given node, names and parameters
@param node identifier of the node
@param names items to be extracted (folernames, app names)
@param params variables of interest
"""
id = args['node']
names = args['names']
params = args['params']
if id in self.raw_logs :
matrix = self.raw_logs[id]['logs']
r = []
LIMIT = 24
for row in matrix :
r += row
r= pd.DataFrame(r)[['name']+params]
return r[r.name.isin( names)].to_dict(orient='records')
# .to_dict(orient='records')
else:
return None
def get_formatted_date(self,row):
m = {1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"}
return "-".join([m[row['month']],str(row['day']),str(row['year'])]) +" "+ " ".join([str(row['hour']),'h :',str(row['minute']),'min' ])
@ -38,17 +68,6 @@ class analytics :
self.set('summary',self.summary(logs))
self.format(logs)
# if id in r :
# nodes = r[id].keys()
# print nodes
# self.set('nodes',nodes)
# logs = {}
# for name in nodes :
# logs[name] = r[id][name]['log']
# self.set('logs',logs)
# self.set('summary',self.summary(r[id]))
# self.format(self.summary(r[id]))
def summary(self,logs) :
raise Exception("needs to be implemented")
@ -78,11 +97,7 @@ class apps(analytics) :
"""
def __init__(self,**args):
analytics.__init__(self,**args)
logs = self.get('logs')
# for node in logs :
# data = logs[node]
# df = pd.DataFrame(data)
# df.groupby(['name'],as_index=False).count()
def init(self):
"""
This function will handle initialization of critical variables
@ -90,7 +105,7 @@ class apps(analytics) :
"""
analytics.init(self)
grid = {"width":"100%","editing":False,"rowClass":"small"}
grid['fields'] = [{"name":"name","title":"Process","headercss":"small"},{"name":"cpu","title":"CPU Usage","headercss":"small","type":"number"},{"name":"mem","title":"RAM Usage","headercss":"small","type":"number"},{"name":"status","title":"Status","headercss":"small","align":"center","width":"32px"}]
grid['fields'] = [{"name":"","width":32,"align":"center"},{"name":"name","title":"Name","headercss":"small"},{"name":"user","title":"User","headercss":"small"},{"name":"cpu","title":"CPU","headercss":"small","type":"number"},{"name":"mem","title":"RAM","headercss":"small","type":"number"},{"name":"status","title":"Status","headercss":"small","align":"center","width":"32px"}]
self.set('grid',grid)
def summary(self,data):
@ -112,24 +127,11 @@ class apps(analytics) :
r.append({"date":date,"node":node,"running":running,"idle":idle,"crash":crash,"formatted_date":formatted_date})
return r
# logs = pd.DataFrame(self.get('logs'))
# r = []
# for id in logs :
# row = pd.DataFrame(logs[id]['log'])
# crash = np.sum(row.status == 'X')
# idle = np.sum(row.status == 'S') + np.sum(row.status == 'S+')
# cpu = row.cpu.sum()
# mem = row.mem.sum() #{"sum":row.mem.sum(),"mean":row.mem.mean(),"sd":np.sqrt(row.mem.var())}
# running = row.shape[0] - crash - idle
# r.append({"node":id,"date":logs[id]['date']['long'],"running":running,"idle":idle,"crash":crash,"mem":mem,"cpu":cpu})
# return r
# self.set("summary",)
def format(self,data) :
"""
This function adds other somewhat important statistics :
- resources used for the node
- the data is limited to the last pull
"""
r = []
@ -235,8 +237,10 @@ class didact():
key = args['key']
collection = [apps(config=config,key=key),folders(config=config,key=key)]
self.cache = {}
self.m = {}
for item in collection :
self.cache = dict(self.cache,**item.cache)
self.m[item.get('name')] = item
r = []
for item in collection:

Loading…
Cancel
Save