Browse Source

trends powered by chart.js

Steve L. Nyemba 8 years ago
parent
commit
eb8f6596e6

BIN
src/.DS_Store


BIN
src/api/.DS_Store


+ 4 - 3
src/api/index.py

@@ -65,7 +65,7 @@ mthread.start()
 @app.route('/get/<id>')
 @app.route('/get/<id>')
 def procs(id):	
 def procs(id):	
 	if id in HANDLERS and len(mthread.logs)>0:
 	if id in HANDLERS and len(mthread.logs)>0:
-		r = ProcessQueue.get(block=True,timeout=15)
+		# r = ProcessQueue.get(block=True,timeout=15)
 		index = len(mthread.logs) -1
 		index = len(mthread.logs) -1
 		r = mthread.logs[index]
 		r = mthread.logs[index]
 		return json.dumps(r)
 		return json.dumps(r)
@@ -75,10 +75,11 @@ def procs(id):
 @app.route('/trends') 
 @app.route('/trends') 
 def trends ():
 def trends ():
 	id = request.args.get('id')
 	id = request.args.get('id')
+	# key = request.args.get('key')
 	handler = monitor.mapreducer()
 	handler = monitor.mapreducer()
 	r = handler.filter(id,mthread.logs)
 	r = handler.filter(id,mthread.logs)
-	r = handler.run(r,handler.mapper,None)
-	print [" **** ",len(r)]
+	r = handler.run(r,handler.mapper,handler.reducer)
+	
 	return json.dumps(r)
 	return json.dumps(r)
 @app.route('/dashboard')
 @app.route('/dashboard')
 def dashboard():
 def dashboard():

BIN
src/api/static/.DS_Store


+ 11 - 0
src/api/static/css/default.css

@@ -58,3 +58,14 @@ input[type=text]{
 input[type=text]:focus{
 input[type=text]:focus{
 	border-left-color:#4682B4;
 	border-left-color:#4682B4;
 }
 }
+
+.padding-2x{padding:4px;}
+.margin-2x {margin:4px;}
+.info {
+	padding:4px;
+	margin:4px;
+	width:40%;
+	height:300px;
+}
+.height-quarter{height:25%;}
+.width-half {width:47%; }

BIN
src/api/static/js/.DS_Store


BIN
src/api/static/js/chart.js/.DS_Store


File diff suppressed because it is too large
+ 14868 - 0
src/api/static/js/chart.js/chart.bundle.js


File diff suppressed because it is too large
+ 2 - 0
src/api/static/js/colors.js


+ 74 - 5
src/api/static/js/dashboard.js

@@ -17,14 +17,16 @@ monitor.processes.init = function(x){
 		var i	= jx.dom.get.instance('I')
 		var i	= jx.dom.get.instance('I')
 		i.className = 'fa fa-chevron-right left'
 		i.className = 'fa fa-chevron-right left'
 		
 		
-		div.innerHTML = label
-		
-		frame.data = r[label]
-		frame.label= label
+		div.innerHTML	= label
+		frame.data	= r[label]
+		frame.label	= label
 		frame.appendChild(i)
 		frame.appendChild(i)
 		frame.appendChild(div)
 		frame.appendChild(div)
 		frame.className = 'menu-item'
 		frame.className = 'menu-item'
-		frame.onclick = function(){ monitor.processes.render(this.label,this.data)}
+		frame.onclick = function () {
+			monitor.processes.render(this.label, this.data);
+			monitor.processes.trend.init(this.label)
+		}
 		jx.dom.append('menu',frame)
 		jx.dom.append('menu',frame)
 	})
 	})
 }
 }
@@ -56,3 +58,70 @@ monitor.processes.render = function(label,data) {
 
 
 
 
 }
 }
+
+monitor.processes.trend = {}
+monitor.processes.trend.init = function (label) {
+	var httpclient = HttpClient.instance()
+	var uri = '/trends?id='+label
+	httpclient.get(uri, function (x) {
+		var logs = JSON.parse(x.responseText)
+		// jx.dom.set.attribute(label,'logs',logs)
+		monitor.processes.trend.render(logs)
+	})
+}
+monitor.processes.trend.render = function (logs, key) {
+	if (key == null) {
+		key = 'memory_usage'
+	}
+	var context = $('#trends_chart')
+	var conf = { type: 'line' }
+	conf.data = {}
+	conf.options = { legend: { position: 'bottom' } }
+	conf.options.scales = {}
+	conf.options.scales.yAxes = [{ title: {display:true,text:key},gridLines: {display:false}}]
+	conf.options.scales.xAxes = [
+		{
+			
+			type: 'time',
+			gridLines: {display:false},
+			time: {
+				format:'dd-MMM HH:mm'
+			}
+			
+		}
+		
+	]
+	// conf.data.labels = x_axis
+	var p = jx.utils.keys(logs)
+	conf.data.datasets = [	]
+	var labels = []
+	var i = 0;
+	
+	for (id in logs) {
+		var serie = {}
+		serie.label = id
+		serie.data = jx.utils.patterns.visitor(logs[id], function (item) {
+			// x = parseFloat(item['hour'] + '.' + item['minute']).toFixed(2)
+			x = new Date(item.year,item.month-1,item.day,item.hour,item.minute)
+			y = item[key]
+			labels.push(x)
+			console.log([item.day,item.hour,item.minute])
+			return {x:x,y:y}
+		})
+		
+		serie.backgroundColor = ['transparent']
+		serie.borderColor = COLORS[i]
+		serie.borderWidth = 1
+		++i
+		conf.data.datasets.push(serie)
+		
+
+	}
+	console.log(labels)
+	labels = jx.utils.unique(labels)
+	
+	conf.data.labels = labels
+	// console.log(conf)
+	var chart = new Chart(context,conf)
+
+}

+ 20 - 6
src/api/templates/dashboard.html

@@ -7,12 +7,13 @@
 <link href="{{context}}/static/css/fa/css/font-awesome.min.css" rel="stylesheet" type="text/css">
 <link href="{{context}}/static/css/fa/css/font-awesome.min.css" rel="stylesheet" type="text/css">
 
 
 <script src="{{ context }}/static/js/jquery/jquery.min.js"></script>
 <script src="{{ context }}/static/js/jquery/jquery.min.js"></script>
-
+<script src="{{context}}/static/js/chart.js/chart.bundle.js"></script>
 
 
 <script src="{{context}}/static/js/jx/rpc.js"></script>
 <script src="{{context}}/static/js/jx/rpc.js"></script>
 <script src="{{context}}/static/js/jx/dom.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/utils.js"></script>
 <script src="{{ context }}/static/js/jsgrid/jsgrid.js"></script>
 <script src="{{ context }}/static/js/jsgrid/jsgrid.js"></script>
+<script src="{{context}}/static/js/colors.js"></script>
 <script src="{{context}}/static/js/dashboard.js"></script>
 <script src="{{context}}/static/js/dashboard.js"></script>
 <title>iMonitor</title>
 <title>iMonitor</title>
 <script>
 <script>
@@ -25,16 +26,29 @@
 		<div class="left">Monitoring</div>
 		<div class="left">Monitoring</div>
 		<div class="right">Trends</div>
 		<div class="right">Trends</div>
 	</div>
 	</div>
-	<div class="left small border">
+	<div class="left small" style="width:15%">
 		<div><input id="find_scope" type="text" placeholder="Find Context"></div>
 		<div><input id="find_scope" type="text" placeholder="Find Context"></div>
 		<div id="menu" class="menu"></div>
 		<div id="menu" class="menu"></div>
 	</div>
 	</div>
 		
 		
-	<div class="left height-quarter">
-		<div class="grid">
+	<div class="left info border">
+		
 			<div class="small" style="text-transform:capitalize">Monitoring <span id="latest_processes_label"></span></div>
 			<div class="small" style="text-transform:capitalize">Monitoring <span id="latest_processes_label"></span></div>
-			<div id="latest_processes" class="small"></div>
-		</div>
+			<div id="latest_processes" class="grid small"></div>
+		
 	</div>	
 	</div>	
+	<div class="left info border">
+		
+		<div class="small">History of Processes <span id="trend_info"></span>
+		</div>
+		<div class="menu">
+			<div class="left menu-item small  padding-2x margin-2x"><i class="fa fa-chevron-right"></i> CPU used</div>
+			<div class="left menu-item small padding-2x margin-2x"><i class="fa fa-chevron-right"></i> Mem. Used</div>
+			<div class="left menu-item small padding-2x margin-2x"><i class="fa fa-chevron-right"></i> Mem. Avail</div>
+		</div>
+		<canvas id="trends_chart" class="small grid">
+
+		</canvas>
+	</div>
 	
 	
 </body>
 </body>

+ 18 - 6
src/monitor.py

@@ -22,7 +22,7 @@ class Analysis:
 		self.logs.append(object)
 		self.logs.append(object)
 	def init(self):
 	def init(self):
 		d = datetime.datetime.now()
 		d = datetime.datetime.now()
-		self.now = {"month":d.month,"year":d.year, "day":d.day,"hour":d.hour}
+		self.now = {"month":d.month,"year":d.year, "day":d.day,"hour":d.hour,"minute":d.minute}
 """
 """
 	This class is designed to analyze environment variables. Environment variables can either be folders, files or simple values
 	This class is designed to analyze environment variables. Environment variables can either be folders, files or simple values
 	The class returns a quantifiable assessment of the environment variables (expected 100%)
 	The class returns a quantifiable assessment of the environment variables (expected 100%)
@@ -57,6 +57,7 @@ class Env(Analysis):
 			return 0
 			return 0
 	
 	
 	def composite (self):
 	def composite (self):
+		Analysis.init(self)
 		r = [ self.evaluate(id) for id in self.values] ;		
 		r = [ self.evaluate(id) for id in self.values] ;		
 		N = len(r)
 		N = len(r)
 		n = sum(r)
 		n = sum(r)
@@ -90,6 +91,7 @@ class Sandbox(Analysis):
 		This function returns the ratio of existing modules relative to the ones expected
 		This function returns the ratio of existing modules relative to the ones expected
 	"""
 	"""
 	def composite(self):
 	def composite(self):
+		Analysis.init(self)
 		required_modules= self.get_requirements()
 		required_modules= self.get_requirements()
 		sandbox_modules	= self.get_sandbox_requirements()
 		sandbox_modules	= self.get_sandbox_requirements()
 		N = len(required_modules)
 		N = len(required_modules)
@@ -115,6 +117,7 @@ class ProcessCounter(Analysis):
 		
 		
 		return int(handler.communicate()[0].replace("\n","") )
 		return int(handler.communicate()[0].replace("\n","") )
 	def composite(self):
 	def composite(self):
+		Analysis.init(self)
 		r = {}
 		r = {}
 		for name in self.names :
 		for name in self.names :
 			r[name] = self.evaluate(name)
 			r[name] = self.evaluate(name)
@@ -168,11 +171,14 @@ class DetailProcess(Analysis):
 		else:
 		else:
 			return "crash"
 			return "crash"
 	def format(self,row):
 	def format(self,row):
+		
 		r= {"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"label":row[3]}
 		r= {"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"label":row[3]}
 		status = self.status(r)
 		status = self.status(r)
 		r['status'] = status
 		r['status'] = status
 		return dict(self.now,**r)
 		return dict(self.now,**r)
 	def composite(self):
 	def composite(self):
+		Analysis.init(self)
+		print ' **** ',self.now
 		#value = self.evaluate(self.name)
 		#value = self.evaluate(self.name)
 		#row= {"memory_usage":value[0],"cpu_usage":value[1]}
 		#row= {"memory_usage":value[0],"cpu_usage":value[1]}
 		#return row
 		#return row
@@ -209,8 +215,8 @@ class Monitor (Thread):
 			self.queue.put(r)
 			self.queue.put(r)
 			self.prune()
 			self.prune()
 			self.queue.task_done()
 			self.queue.task_done()
-			
-			time.sleep(10)
+			HALF_HOUR = 60*15
+			time.sleep(HALF_HOUR)
 	def prune(self) :
 	def prune(self) :
 		MAX_ENTRIES = 1000
 		MAX_ENTRIES = 1000
 		if len(self.logs) > MAX_ENTRIES :
 		if len(self.logs) > MAX_ENTRIES :
@@ -230,14 +236,20 @@ class mapreducer:
 			
 			
 			
 			
 		if reducer is not None:
 		if reducer is not None:
-			r = [reducer(self.store[key]) for key in self.store]
+			r = {}
+			for key in self.store:
+				beg = len(self.store[key]) - 101 if len(self.store[key]) > 100 else 0
+				end = beg + 100
+				r[key] = self.store[key][beg:end]
+			# r = [reducer(self.store[key]) for key in self.store]
 		else:
 		else:
 			r = self.store
 			r = self.store
 		return r
 		return r
 	def mapper(self,row,emit):
 	def mapper(self,row,emit):
-		[emit(item['label'],item) for item in row ]
+		[emit(_matrix['label'],_matrix) for _matrix in row ]
 	def reducer(self,values):
 	def reducer(self,values):
-		return value			
+		beg = len(values)-101 if len(values) > 100 else 0
+		return values[beg:]
 
 
 	def emit(self,key,content):
 	def emit(self,key,content):
 		if key not in self.store:
 		if key not in self.store: