spoonsix-dognotgod 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -3
- data/app/models/file_system.rb +30 -4
- data/app/models/host.rb +56 -17
- data/public/javascripts/jquery.simplemodal-1.2.3.min.js +8 -0
- data/server.rb +18 -10
- data/views/host.haml +43 -0
- data/views/layout.haml +4 -1
- data/views/main.haml +17 -53
- data/views/style.sass +229 -27
- metadata +7 -4
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# dog not god:
|
1
|
+
# dog not god: server health monitoring simplified
|
2
2
|
|
3
|
-
dog not god is a
|
3
|
+
dog not god is a server health monitoring tool for *nix based servers. The focus is on simplicity and on a 100% ruby implementation.
|
4
4
|
|
5
5
|
### Installation
|
6
6
|
|
@@ -26,7 +26,7 @@ This will run the client every minute. By default, the server-address is 127.0.0
|
|
26
26
|
|
27
27
|
## License
|
28
28
|
|
29
|
-
dog not god:
|
29
|
+
dog not god: server health monitoring simplified
|
30
30
|
Copyright (C) 2009 spoonsix - Luis Correa d'Almeida
|
31
31
|
|
32
32
|
This program is free software; you can redistribute it and/or
|
data/app/models/file_system.rb
CHANGED
@@ -26,6 +26,10 @@ class FileSystem < Sequel::Model
|
|
26
26
|
available_in_Gb + used_in_Gb
|
27
27
|
end
|
28
28
|
|
29
|
+
def total_space_in_Gb
|
30
|
+
size_in_Gb
|
31
|
+
end
|
32
|
+
|
29
33
|
def used_in_Gb
|
30
34
|
if latest_disk_entry
|
31
35
|
latest_disk_entry.used / 1024 / 1024
|
@@ -34,6 +38,10 @@ class FileSystem < Sequel::Model
|
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
41
|
+
def used_space_in_Gb
|
42
|
+
used_in_Gb
|
43
|
+
end
|
44
|
+
|
37
45
|
def available_in_Gb
|
38
46
|
if latest_disk_entry
|
39
47
|
latest_disk_entry.available / 1024 / 1024
|
@@ -41,6 +49,24 @@ class FileSystem < Sequel::Model
|
|
41
49
|
0
|
42
50
|
end
|
43
51
|
end
|
52
|
+
|
53
|
+
def available_space_in_Gb
|
54
|
+
available_in_Gb
|
55
|
+
end
|
56
|
+
|
57
|
+
def available_space_in_percent
|
58
|
+
sprintf('%.2f', available_space_in_Gb.to_f / total_space_in_Gb * 100)
|
59
|
+
end
|
60
|
+
|
61
|
+
def status
|
62
|
+
if available_space_in_percent.to_i > 30
|
63
|
+
STATUS_GREEN
|
64
|
+
elsif available_space_in_percent.to_i > 10
|
65
|
+
STATUS_YELLOW
|
66
|
+
else
|
67
|
+
STATUS_RED
|
68
|
+
end
|
69
|
+
end
|
44
70
|
|
45
71
|
def disks_5_min_grain(start_time, end_time)
|
46
72
|
disk = DB.fetch("SELECT ROUND(AVG(available)/1024/1024, 1) AS available, ROUND(AVG(used)/1024/1024, 1) AS used, grain_5_min FROM disks WHERE file_system_id = #{self.id} AND grain_5_min >= '#{start_time.to_five_minute_grain_format.to_sql_format}' AND grain_5_min <= '#{end_time.to_five_minute_grain_format.to_sql_format}' GROUP BY grain_5_min;").all
|
@@ -56,8 +82,8 @@ class FileSystem < Sequel::Model
|
|
56
82
|
series[0] << five.to_minute_format
|
57
83
|
if disk.size > 0 and disk[0][:grain_5_min].to_minute_format == five.to_minute_format
|
58
84
|
disk_for_this_dim = disk.shift
|
59
|
-
series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used])
|
60
|
-
series[2] << disk_for_this_dim[:used]
|
85
|
+
series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used]).to_f
|
86
|
+
series[2] << disk_for_this_dim[:used].to_f
|
61
87
|
else
|
62
88
|
series[1] << -1
|
63
89
|
series[2] << -1
|
@@ -81,8 +107,8 @@ class FileSystem < Sequel::Model
|
|
81
107
|
series[0] << fifteen.to_minute_format
|
82
108
|
if disk.size > 0 and disk[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
|
83
109
|
disk_for_this_dim = disk.shift
|
84
|
-
series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used])
|
85
|
-
series[2] << disk_for_this_dim[:used]
|
110
|
+
series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used]).to_f
|
111
|
+
series[2] << disk_for_this_dim[:used].to_f
|
86
112
|
else
|
87
113
|
series[1] << -1
|
88
114
|
series[2] << -1
|
data/app/models/host.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Host < Sequel::Model
|
2
|
-
|
2
|
+
|
3
3
|
one_to_many :loads
|
4
4
|
|
5
5
|
one_to_many :file_systems
|
@@ -51,7 +51,7 @@ class Host < Sequel::Model
|
|
51
51
|
@total += fs.size_in_Gb
|
52
52
|
end
|
53
53
|
|
54
|
-
@total
|
54
|
+
@total_disk_space_in_Gb ||= @total
|
55
55
|
end
|
56
56
|
|
57
57
|
def available_disk_space_in_Gb
|
@@ -60,7 +60,21 @@ class Host < Sequel::Model
|
|
60
60
|
@available += fs.available_in_Gb
|
61
61
|
end
|
62
62
|
|
63
|
-
@available
|
63
|
+
@available_disk_space_in_Gb ||= @available
|
64
|
+
end
|
65
|
+
|
66
|
+
def available_disk_space_in_percent
|
67
|
+
sprintf('%.2f', available_disk_space_in_Gb.to_f / total_disk_space_in_Gb * 100)
|
68
|
+
end
|
69
|
+
|
70
|
+
def disk_status
|
71
|
+
if available_disk_space_in_percent.to_i > 30
|
72
|
+
STATUS_GREEN
|
73
|
+
elsif available_disk_space_in_percent.to_i > 10
|
74
|
+
STATUS_YELLOW
|
75
|
+
else
|
76
|
+
STATUS_RED
|
77
|
+
end
|
64
78
|
end
|
65
79
|
|
66
80
|
|
@@ -119,6 +133,19 @@ class Host < Sequel::Model
|
|
119
133
|
series
|
120
134
|
end
|
121
135
|
|
136
|
+
def available_memory_in_percent
|
137
|
+
sprintf('%.2f', available_memory_in_Mb.to_f / total_memory_in_Mb * 100)
|
138
|
+
end
|
139
|
+
|
140
|
+
def memory_status
|
141
|
+
if available_memory_in_percent.to_i > 30
|
142
|
+
STATUS_GREEN
|
143
|
+
elsif available_memory_in_percent.to_i > 10
|
144
|
+
STATUS_YELLOW
|
145
|
+
else
|
146
|
+
STATUS_RED
|
147
|
+
end
|
148
|
+
end
|
122
149
|
|
123
150
|
####################
|
124
151
|
# Swap
|
@@ -144,6 +171,20 @@ class Host < Sequel::Model
|
|
144
171
|
end
|
145
172
|
end
|
146
173
|
|
174
|
+
def available_swap_in_percent
|
175
|
+
sprintf('%.2f', available_swap_in_Mb.to_f / total_swap_in_Mb * 100)
|
176
|
+
end
|
177
|
+
|
178
|
+
def swap_status
|
179
|
+
if available_swap_in_percent.to_i > 30
|
180
|
+
STATUS_GREEN
|
181
|
+
elsif available_swap_in_percent.to_i > 10
|
182
|
+
STATUS_YELLOW
|
183
|
+
else
|
184
|
+
STATUS_RED
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
147
188
|
####################
|
148
189
|
# Load stats
|
149
190
|
####################
|
@@ -162,9 +203,9 @@ class Host < Sequel::Model
|
|
162
203
|
series[0] << five.to_minute_format
|
163
204
|
if load.size > 0 and load[0][:grain_5_min].to_minute_format == five.to_minute_format
|
164
205
|
load_for_this_dim = load.shift
|
165
|
-
series[1] << load_for_this_dim[:load_5_min]
|
166
|
-
series[2] << load_for_this_dim[:load_10_min]
|
167
|
-
series[3] << load_for_this_dim[:load_15_min]
|
206
|
+
series[1] << load_for_this_dim[:load_5_min].to_f
|
207
|
+
series[2] << load_for_this_dim[:load_10_min].to_f
|
208
|
+
series[3] << load_for_this_dim[:load_15_min].to_f
|
168
209
|
else
|
169
210
|
series[1] << -1
|
170
211
|
series[2] << -1
|
@@ -200,9 +241,9 @@ class Host < Sequel::Model
|
|
200
241
|
series[0] << fifteen.to_minute_format
|
201
242
|
if load.size > 0 and load[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
|
202
243
|
load_for_this_dim = load.shift
|
203
|
-
series[1] << load_for_this_dim[:load_5_min]
|
204
|
-
series[2] << load_for_this_dim[:load_10_min]
|
205
|
-
series[3] << load_for_this_dim[:load_15_min]
|
244
|
+
series[1] << load_for_this_dim[:load_5_min].to_f
|
245
|
+
series[2] << load_for_this_dim[:load_10_min].to_f
|
246
|
+
series[3] << load_for_this_dim[:load_15_min].to_f
|
206
247
|
else
|
207
248
|
series[1] << -1
|
208
249
|
series[2] << -1
|
@@ -227,15 +268,13 @@ class Host < Sequel::Model
|
|
227
268
|
|
228
269
|
def status
|
229
270
|
if self.last_contacted_on == nil
|
230
|
-
|
231
|
-
elsif Time.now - self.last_contacted_on <
|
232
|
-
|
233
|
-
elsif Time.now - self.last_contacted_on <
|
234
|
-
|
235
|
-
elsif Time.now - self.last_contacted_on < 300
|
236
|
-
2
|
271
|
+
STATUS_RED
|
272
|
+
elsif Time.now - self.last_contacted_on < 75
|
273
|
+
STATUS_GREEN
|
274
|
+
elsif Time.now - self.last_contacted_on < 120
|
275
|
+
STATUS_YELLOW
|
237
276
|
else
|
238
|
-
|
277
|
+
STATUS_RED
|
239
278
|
end
|
240
279
|
end
|
241
280
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/*
|
2
|
+
* SimpleModal 1.2.3 - jQuery Plugin
|
3
|
+
* http://www.ericmmartin.com/projects/simplemodal/
|
4
|
+
* Copyright (c) 2009 Eric Martin
|
5
|
+
* Dual licensed under the MIT and GPL licenses
|
6
|
+
* Revision: $Id: jquery.simplemodal.js 185 2009-02-09 21:51:12Z emartin24 $
|
7
|
+
*/
|
8
|
+
(function($){var ie6=$.browser.msie&&parseInt($.browser.version)==6&&typeof window['XMLHttpRequest']!="object",ieQuirks=null,w=[];$.modal=function(data,options){return $.modal.impl.init(data,options);};$.modal.close=function(){$.modal.impl.close();};$.fn.modal=function(options){return $.modal.impl.init(this,options);};$.modal.defaults={opacity:50,overlayId:'simplemodal-overlay',overlayCss:{},containerId:'simplemodal-container',containerCss:{},dataCss:{},zIndex:1000,close:true,closeHTML:'<a class="modalCloseImg" title="Close"></a>',closeClass:'simplemodal-close',position:null,persist:false,onOpen:null,onShow:null,onClose:null};$.modal.impl={opts:null,dialog:{},init:function(data,options){if(this.dialog.data){return false;}ieQuirks=$.browser.msie&&!$.boxModel;this.opts=$.extend({},$.modal.defaults,options);this.zIndex=this.opts.zIndex;this.occb=false;if(typeof data=='object'){data=data instanceof jQuery?data:$(data);if(data.parent().parent().size()>0){this.dialog.parentNode=data.parent();if(!this.opts.persist){this.dialog.orig=data.clone(true);}}}else if(typeof data=='string'||typeof data=='number'){data=$('<div/>').html(data);}else{alert('SimpleModal Error: Unsupported data type: '+typeof data);return false;}this.dialog.data=data.addClass('simplemodal-data').css(this.opts.dataCss);data=null;this.create();this.open();if($.isFunction(this.opts.onShow)){this.opts.onShow.apply(this,[this.dialog]);}return this;},create:function(){w=this.getDimensions();if(ie6){this.dialog.iframe=$('<iframe src="javascript:false;"/>').css($.extend(this.opts.iframeCss,{display:'none',opacity:0,position:'fixed',height:w[0],width:w[1],zIndex:this.opts.zIndex,top:0,left:0})).appendTo('body');}this.dialog.overlay=$('<div/>').attr('id',this.opts.overlayId).addClass('simplemodal-overlay').css($.extend(this.opts.overlayCss,{display:'none',opacity:this.opts.opacity/100,height:w[0],width:w[1],position:'fixed',left:0,top:0,zIndex:this.opts.zIndex+1})).appendTo('body');this.dialog.container=$('<div/>').attr('id',this.opts.containerId).addClass('simplemodal-container').css($.extend(this.opts.containerCss,{display:'none',position:'fixed',zIndex:this.opts.zIndex+2})).append(this.opts.close?$(this.opts.closeHTML).addClass(this.opts.closeClass):'').appendTo('body');this.setPosition();if(ie6||ieQuirks){this.fixIE();}this.dialog.container.append(this.dialog.data.hide());},bindEvents:function(){var self=this;$('.'+this.opts.closeClass).bind('click.simplemodal',function(e){e.preventDefault();self.close();});$(window).bind('resize.simplemodal',function(){w=self.getDimensions();self.setPosition();if(ie6||ieQuirks){self.fixIE();}else{self.dialog.iframe&&self.dialog.iframe.css({height:w[0],width:w[1]});self.dialog.overlay.css({height:w[0],width:w[1]});}});},unbindEvents:function(){$('.'+this.opts.closeClass).unbind('click.simplemodal');$(window).unbind('resize.simplemodal');},fixIE:function(){var p=this.opts.position;$.each([this.dialog.iframe||null,this.dialog.overlay,this.dialog.container],function(i,el){if(el){var bch='document.body.clientHeight',bcw='document.body.clientWidth',bsh='document.body.scrollHeight',bsl='document.body.scrollLeft',bst='document.body.scrollTop',bsw='document.body.scrollWidth',ch='document.documentElement.clientHeight',cw='document.documentElement.clientWidth',sl='document.documentElement.scrollLeft',st='document.documentElement.scrollTop',s=el[0].style;s.position='absolute';if(i<2){s.removeExpression('height');s.removeExpression('width');s.setExpression('height',''+bsh+' > '+bch+' ? '+bsh+' : '+bch+' + "px"');s.setExpression('width',''+bsw+' > '+bcw+' ? '+bsw+' : '+bcw+' + "px"');}else{var te,le;if(p&&p.constructor==Array){var top=p[0]?typeof p[0]=='number'?p[0].toString():p[0].replace(/px/,''):el.css('top').replace(/px/,'');te=top.indexOf('%')==-1?top+' + (t = '+st+' ? '+st+' : '+bst+') + "px"':parseInt(top.replace(/%/,''))+' * (('+ch+' || '+bch+') / 100) + (t = '+st+' ? '+st+' : '+bst+') + "px"';if(p[1]){var left=typeof p[1]=='number'?p[1].toString():p[1].replace(/px/,'');le=left.indexOf('%')==-1?left+' + (t = '+sl+' ? '+sl+' : '+bsl+') + "px"':parseInt(left.replace(/%/,''))+' * (('+cw+' || '+bcw+') / 100) + (t = '+sl+' ? '+sl+' : '+bsl+') + "px"';}}else{te='('+ch+' || '+bch+') / 2 - (this.offsetHeight / 2) + (t = '+st+' ? '+st+' : '+bst+') + "px"';le='('+cw+' || '+bcw+') / 2 - (this.offsetWidth / 2) + (t = '+sl+' ? '+sl+' : '+bsl+') + "px"';}s.removeExpression('top');s.removeExpression('left');s.setExpression('top',te);s.setExpression('left',le);}}});},getDimensions:function(){var el=$(window);var h=$.browser.opera&&$.browser.version>'9.5'&&$.fn.jquery<='1.2.6'?document.documentElement['clientHeight']:el.height();return[h,el.width()];},setPosition:function(){var top,left,hCenter=(w[0]/2)-((this.dialog.container.height()||this.dialog.data.height())/2),vCenter=(w[1]/2)-((this.dialog.container.width()||this.dialog.data.width())/2);if(this.opts.position&&this.opts.position.constructor==Array){top=this.opts.position[0]||hCenter;left=this.opts.position[1]||vCenter;}else{top=hCenter;left=vCenter;}this.dialog.container.css({left:left,top:top});},open:function(){this.dialog.iframe&&this.dialog.iframe.show();if($.isFunction(this.opts.onOpen)){this.opts.onOpen.apply(this,[this.dialog]);}else{this.dialog.overlay.show();this.dialog.container.show();this.dialog.data.show();}this.bindEvents();},close:function(){if(!this.dialog.data){return false;}if($.isFunction(this.opts.onClose)&&!this.occb){this.occb=true;this.opts.onClose.apply(this,[this.dialog]);}else{if(this.dialog.parentNode){if(this.opts.persist){this.dialog.data.hide().appendTo(this.dialog.parentNode);}else{this.dialog.data.remove();this.dialog.orig.appendTo(this.dialog.parentNode);}}else{this.dialog.data.remove();}this.dialog.container.remove();this.dialog.overlay.remove();this.dialog.iframe&&this.dialog.iframe.remove();this.dialog={};}this.unbindEvents();}};})(jQuery);
|
data/server.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'sinatra'
|
3
|
-
# require 'ruby-prof'
|
4
3
|
|
5
4
|
configure do
|
6
5
|
DB_DIR = "#{ENV['HOME']}/.dognotgod"
|
@@ -19,6 +18,11 @@ configure do
|
|
19
18
|
require 'load'
|
20
19
|
require 'disk'
|
21
20
|
require 'memory'
|
21
|
+
|
22
|
+
STATUS_GREEN = 1
|
23
|
+
STATUS_YELLOW = 2
|
24
|
+
STATUS_RED = 3
|
25
|
+
|
22
26
|
end
|
23
27
|
|
24
28
|
error do
|
@@ -43,11 +47,11 @@ helpers do
|
|
43
47
|
end
|
44
48
|
|
45
49
|
def get_fs_or_create_if_not_exist(host_id, fs_name, mounted_on)
|
46
|
-
fs = DB[:file_systems].filter(:name => fs_name, :mounted_on => mounted_on).first
|
50
|
+
fs = DB[:file_systems].filter(:name => fs_name, :host_id => host_id, :mounted_on => mounted_on).first
|
47
51
|
|
48
52
|
unless fs
|
49
53
|
DB[:file_systems] << {:name => fs_name, :mounted_on => mounted_on, :host_id => host_id}
|
50
|
-
fs = DB[:file_systems].filter(:name => fs_name, :mounted_on => mounted_on).first
|
54
|
+
fs = DB[:file_systems].filter(:name => fs_name, :host_id => host_id, :mounted_on => mounted_on).first
|
51
55
|
end
|
52
56
|
fs
|
53
57
|
end
|
@@ -60,21 +64,25 @@ get '/stylesheets/style.css' do
|
|
60
64
|
end
|
61
65
|
|
62
66
|
get "/" do
|
63
|
-
# result = RubyProf.profile do
|
64
|
-
|
65
67
|
@hosts = Host.order(:hostname).all
|
66
|
-
|
68
|
+
|
67
69
|
@end_now = Time.now.utc.to_fifteen_minute_grain_format
|
68
70
|
@start_24h_ago = @end_now - (60*60*24)
|
69
71
|
@start_6h_ago = @end_now - (60*60*6)
|
70
72
|
|
71
73
|
haml :main
|
72
|
-
# end
|
73
|
-
# Print a graph profile to text
|
74
|
-
# printer = RubyProf::GraphPrinter.new(result)
|
75
|
-
# printer.print(File.new("tmp/profile.log", "w"), 0)
|
76
74
|
end
|
77
75
|
|
76
|
+
get "/hosts/:id" do
|
77
|
+
@host = Host.find(:id => params[:id])
|
78
|
+
|
79
|
+
@end_now = Time.now.utc.to_fifteen_minute_grain_format
|
80
|
+
@start_24h_ago = @end_now - (60*60*24)
|
81
|
+
@start_6h_ago = @end_now - (60*60*6)
|
82
|
+
|
83
|
+
haml :host, :layout => false
|
84
|
+
end
|
85
|
+
|
78
86
|
post "/load_stats" do
|
79
87
|
|
80
88
|
begin
|
data/views/host.haml
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
- series_6h = @host.loads_15_min_grain(@start_6h_ago, @end_now)
|
2
|
+
- params_for_6h = "cht=ls&chs=300x100&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.25,0.26&chxt=x,y&chxr=1,0,4,1&chds=0,4&chl=&chd=t:#{series_6h[1].join(",")}|#{series_6h[2].join(",")}|#{series_6h[3].join(",")}"
|
3
|
+
- series_24h = @host.loads_15_min_grain(@start_24h_ago, @end_now)
|
4
|
+
- params_for_24h = "cht=lc&chs=300x100&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.25,0.26&chxt=x,y&chxr=1,0,4,1&chds=0,4&chl=&chd=t:#{series_24h[1].join(",")}|#{series_24h[2].join(",")}|#{series_24h[3].join(",")}"
|
5
|
+
- mem_series_24h = @host.memory_stats_15_min_grain(@start_24h_ago, @end_now)
|
6
|
+
- mem_params_for_24h = "cht=lc&chs=300x100&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.95,0.96&chxr=1,0,#{@host.total_memory_in_Mb * 1.05}&chxt=x,y&chl=&chds=0,#{@host.total_memory_in_Mb * 1.05}&chd=t:#{mem_series_24h[2].join(",")}|#{mem_series_24h[4].join(",")}"
|
7
|
+
- swap_params_for_24h = "cht=lc&chs=300x100&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.95,0.96&chxr=1,0,#{@host.total_swap_in_Mb * 1.05}&chxt=x,y&chl=&chds=0,#{@host.total_swap_in_Mb * 1.05}&chd=t:#{mem_series_24h[4].join(",")}"
|
8
|
+
.section
|
9
|
+
%h3=@host.hostname
|
10
|
+
%p== Last heard from on #{@host.last_contacted_on}
|
11
|
+
|
12
|
+
%table
|
13
|
+
%tr
|
14
|
+
%td{:style=> "vertical-align: top"}
|
15
|
+
%h4.load Load averages for the last 24 hours
|
16
|
+
%p{:style => "float:right;"}== 5, 10 and 15 min averages
|
17
|
+
%br
|
18
|
+
%img{ :src => "http://chart.apis.google.com/chart?#{params_for_24h}"}
|
19
|
+
%td
|
20
|
+
%h4.memory Memory & Swap
|
21
|
+
%p{:style => "float:right;"}== Total memory is #{@host.total_memory_in_Mb}Mb
|
22
|
+
%br
|
23
|
+
%img{ :src => "http://chart.apis.google.com/chart?#{mem_params_for_24h}"}
|
24
|
+
%tr
|
25
|
+
%td{:colspan => 2}
|
26
|
+
%h4.disk Disk space & File system info
|
27
|
+
%table.detail-table{:cellspacing => 0, :cellpading => 0}
|
28
|
+
%tr
|
29
|
+
%th
|
30
|
+
%th File system
|
31
|
+
%th Disk space
|
32
|
+
%th Percentage free disk space
|
33
|
+
- @host.file_systems.each do |fs|
|
34
|
+
%tr
|
35
|
+
%td=fs.mounted_on
|
36
|
+
%td=fs.name
|
37
|
+
- if fs.is_dev? and fs.size_in_Gb > 0
|
38
|
+
- series_24h = fs.disks_15_min_grain(@start_24h_ago, @end_now)
|
39
|
+
- params_for_24h = "cht=ls&chs=75x20&chco=999999&chds=0,#{series_24h[2].max.ceil}&chd=t:#{series_24h[2].join(",")}"
|
40
|
+
%td.space{:style => "padding-left: 100px; background: url(http://chart.apis.google.com/chart?#{params_for_24h}) no-repeat 5px 12px"}="#{fs.available_space_in_Gb} Gb free / #{fs.total_space_in_Gb} Gb total"
|
41
|
+
%td
|
42
|
+
%span.bar{:class => "status#{fs.status}", :style => "width: #{fs.available_space_in_percent.to_i}%"}="#{fs.available_space_in_percent}%" if fs.total_space_in_Gb > 0
|
43
|
+
|
data/views/layout.haml
CHANGED
@@ -3,12 +3,15 @@
|
|
3
3
|
%head
|
4
4
|
%title dog not god
|
5
5
|
%link{:rel=>'stylesheet', :href=>'/stylesheets/style.css', :type => "text/css"}
|
6
|
+
%script{:src => "http://www.google.com/jsapi"}
|
7
|
+
%script google.load("jquery", "1");
|
8
|
+
%script{:src => "/javascripts/jquery.simplemodal-1.2.3.min.js"}
|
6
9
|
|
7
10
|
|
8
11
|
%body
|
9
12
|
#header
|
10
13
|
#content
|
11
|
-
%h1
|
14
|
+
%h1="dog not god <br/><span style='font-size: 0.4em'>server health monitoring simplified</span>"
|
12
15
|
=yield
|
13
16
|
#footer
|
14
17
|
%p
|
data/views/main.haml
CHANGED
@@ -1,64 +1,28 @@
|
|
1
1
|
%h2 Summary
|
2
|
+
|
2
3
|
#summary-section
|
3
|
-
%table
|
4
|
+
%table.summary-table{:cellspacing => 0, :cellpading => 0}
|
4
5
|
%tr
|
5
6
|
%th Host
|
6
7
|
%th Last heartbeat
|
7
8
|
%th 5 min average
|
8
|
-
%th 10 min
|
9
|
-
%th 15 min
|
9
|
+
%th 10 min
|
10
|
+
%th 15 min
|
10
11
|
%th Free disk space
|
11
12
|
%th Free memory
|
12
13
|
%th Free swap space
|
13
|
-
-for host in @hosts
|
14
|
-
%tr{:class => "level#{host.status}"}
|
15
|
-
%td= host.hostname
|
16
|
-
%td= "#{host.distance_to_last_heartbeat_in_seconds.to_i} seconds ago" unless host.status == 0
|
17
|
-
%td= host.load_5_min
|
18
|
-
%td= host.load_10_min
|
19
|
-
%td= host.load_15_min
|
20
|
-
%td= "#{host.available_disk_space_in_Gb}Gb out of #{host.total_disk_space_in_Gb}Gb (#{sprintf('%.2f', (host.available_disk_space_in_Gb.to_f / host.total_disk_space_in_Gb) * 100)}%)" if host.total_disk_space_in_Gb > 0
|
21
|
-
%td= "#{host.available_memory_in_Mb}Mb out of #{host.total_memory_in_Mb}Mb (#{sprintf('%.2f', (host.available_memory_in_Mb.to_f / host.total_memory_in_Mb) * 100)}%)" if host.total_memory_in_Mb > 0
|
22
|
-
%td= "#{host.available_swap_in_Mb}Mb out of #{host.total_swap_in_Mb}Mb (#{sprintf('%.2f', (host.available_swap_in_Mb.to_f / host.total_swap_in_Mb) * 100)}%)" if host.total_swap_in_Mb > 0
|
23
|
-
|
24
|
-
%table{:id => "section-table"}
|
25
|
-
%tr
|
26
14
|
-for host in @hosts
|
27
15
|
- series_6h = host.loads_5_min_grain(@start_6h_ago, @end_now)
|
28
|
-
- params_for_6h = "cht=
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
%
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
%
|
41
|
-
|
42
|
-
%h4 Load averages for the last 6 hours
|
43
|
-
%img{ :src => "http://chart.apis.google.com/chart?#{params_for_6h}"}
|
44
|
-
|
45
|
-
%h4 Memory
|
46
|
-
%p{:style => "float:right;"}== Total memory is #{host.total_memory_in_Mb}Mb
|
47
|
-
%br
|
48
|
-
%img{ :src => "http://chart.apis.google.com/chart?#{mem_params_for_24h}"}
|
49
|
-
|
50
|
-
%h4 Swap
|
51
|
-
%p{:style => "float:right;"}== Total memory is #{host.total_swap_in_Mb}Mb
|
52
|
-
%br
|
53
|
-
%img{ :src => "http://chart.apis.google.com/chart?#{swap_params_for_24h}"}
|
54
|
-
|
55
|
-
- host.file_systems.each do |fs|
|
56
|
-
- if fs.is_dev? and fs.size_in_Gb > 0
|
57
|
-
- series_24h = fs.disks_15_min_grain(@start_24h_ago, @end_now)
|
58
|
-
- params_for_24h = "cht=lc&chs=350x120&chco=FF0000,00FF00,0000FF&chxr=1,0,#{fs.size_in_Gb * 1.05}&chxt=x,y&chds=0,#{fs.size_in_Gb * 1.05}&chl=&chd=t:#{series_24h[2].join(",")}"
|
59
|
-
%h4== #{fs.mounted_on} on #{fs.name}
|
60
|
-
%p{:style => "float:right;"}== Device size is #{fs.size_in_Gb}Gb
|
61
|
-
%br
|
62
|
-
%img{ :src => "http://chart.apis.google.com/chart?#{params_for_24h}"}
|
63
|
-
|
64
|
-
|
16
|
+
- params_for_6h = "cht=ls&chs=75x20&chco=999999&chds=0,#{series_6h[1].max}&chd=t:#{series_6h[1].join(",")}"
|
17
|
+
%tr.link{:onclick => "jQuery.get('/hosts/#{host.id}', {}, function(data) {jQuery.modal(data, {})})"}
|
18
|
+
%td{:class => "status#{host.status}"}= host.hostname
|
19
|
+
%td.distance-in-secs{:class => "status#{host.status}"}= "#{host.distance_to_last_heartbeat_in_seconds.to_i} seconds ago" unless host.status == 0
|
20
|
+
%td.load{:style => "background: url(http://chart.apis.google.com/chart?#{params_for_6h}) no-repeat 5px 12px"}=host.load_5_min
|
21
|
+
%td.load= host.load_10_min
|
22
|
+
%td.load= host.load_15_min
|
23
|
+
%td
|
24
|
+
%span.bar{:class => "status#{host.disk_status}", :style => "width: #{host.available_disk_space_in_percent.to_i}%"}="#{host.available_disk_space_in_percent}%" if host.total_disk_space_in_Gb > 0
|
25
|
+
%td
|
26
|
+
%span.bar{:class => "status#{host.memory_status}", :style => "width: #{host.available_memory_in_percent.to_i}%"}="#{host.available_memory_in_percent}%" if host.total_memory_in_Mb > 0
|
27
|
+
%td
|
28
|
+
%span.bar{:class => "status#{host.swap_status}", :style => "width: #{host.available_swap_in_percent.to_i}"}= "#{host.available_swap_in_percent}%" if host.total_swap_in_Mb > 0
|
data/views/style.sass
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
body
|
2
2
|
:margin 0
|
3
3
|
:padding 0
|
4
|
-
:font-family
|
4
|
+
:font-family Georgia, serif
|
5
5
|
:font-size 1.0em
|
6
6
|
|
7
7
|
br
|
@@ -10,56 +10,94 @@ br
|
|
10
10
|
a, a:visited
|
11
11
|
:color #AAA
|
12
12
|
|
13
|
+
//************************************************************
|
14
|
+
// headers
|
15
|
+
|
13
16
|
h1, h2, h3, h4, h5, h6
|
14
|
-
:font-family Georgia, serif
|
15
17
|
:font-weight normal
|
16
18
|
:margin 0px 10px 10px 0px
|
17
19
|
:white-space nowrap
|
20
|
+
:clear both
|
18
21
|
|
19
22
|
h1
|
20
23
|
:padding-bottom 10px
|
21
|
-
:margin
|
24
|
+
:margin 0px 0px 30px 0px
|
22
25
|
:border-bottom double #DDDDDD
|
23
26
|
|
24
27
|
h2
|
25
|
-
:
|
28
|
+
:background url(/images/blossom/48x48/world_globe.png) no-repeat 5px 10px
|
29
|
+
:padding 20px 10px 18px 60px
|
30
|
+
:margin 3px 0px 30px 0px
|
31
|
+
:border 1px solid #DDD
|
32
|
+
:border-bottom 1px solid #555
|
33
|
+
:background-color #EFEFEF
|
34
|
+
|
35
|
+
|
36
|
+
h3
|
37
|
+
:background url(/images/blossom/48x48/user.png) no-repeat 5px 7px
|
38
|
+
:padding 20px 10px 18px 60px
|
39
|
+
:margin 3px 0px 3px 0px
|
40
|
+
:border-top 1px solid #DDD
|
41
|
+
:border-bottom 1px solid #555
|
42
|
+
:background-color #EFEFEF
|
26
43
|
|
27
44
|
h4
|
28
|
-
:
|
29
|
-
:
|
45
|
+
:padding 10px 0px 10px 40px
|
46
|
+
:margin 2px 10px 3px 20px
|
47
|
+
:border-top 1px solid #DDD
|
48
|
+
:border-left 1px solid #DDD
|
49
|
+
:border-right 1px solid #DDD
|
50
|
+
:border-bottom 1px solid #555
|
51
|
+
|
52
|
+
h4.load
|
53
|
+
:background url(/images/blossom/32x32/process.png) no-repeat 5px 3px
|
54
|
+
:background-color #EFEFEF
|
55
|
+
|
56
|
+
h4.memory, h4.swap
|
57
|
+
:background url(/images/blossom/32x32/chart.png) no-repeat
|
30
58
|
:background-color #EFEFEF
|
59
|
+
|
60
|
+
h4.disk
|
61
|
+
:background url(/images/blossom/32x32/hard_disk.png) no-repeat
|
62
|
+
:background-color #EFEFEF
|
63
|
+
|
31
64
|
|
32
65
|
#header
|
33
66
|
:height 10px
|
34
67
|
:background-color #EFEFEF
|
68
|
+
:border-bottom 1px solid #DDD
|
35
69
|
:margin-bottom 20px
|
36
70
|
|
37
71
|
#content
|
38
72
|
:margin 0px 30px 10px 20px
|
73
|
+
|
74
|
+
#content-lightbox
|
75
|
+
:padding 10px 50px
|
76
|
+
:margin 10px auto
|
39
77
|
|
40
78
|
#summary-section
|
41
|
-
:font-size 0.
|
79
|
+
:font-size 0.8em
|
42
80
|
:margin-bottom 30px
|
43
81
|
:padding-bottom 20px
|
44
82
|
:border-bottom 1px solid #DDD
|
45
83
|
|
84
|
+
|
85
|
+
//************************************************************
|
46
86
|
// summary-table
|
47
87
|
|
48
88
|
.summary-table
|
49
89
|
:border-top 1px solid #DDD
|
50
90
|
:border-left 1px solid #DDD
|
51
|
-
|
52
|
-
.summary-table tr.level4, .summary-table tr.level5
|
53
|
-
:background-color #99FF99
|
91
|
+
:width 100%
|
54
92
|
|
55
|
-
.summary-table tr
|
56
|
-
:
|
93
|
+
.summary-table tr
|
94
|
+
:height 35px
|
57
95
|
|
58
|
-
.summary-table tr.
|
59
|
-
:
|
96
|
+
.summary-table tr.link
|
97
|
+
:cursor pointer
|
60
98
|
|
61
|
-
.summary-table tr.
|
62
|
-
:background-color #
|
99
|
+
.summary-table tr.link:hover
|
100
|
+
:background-color #FFFFEF
|
63
101
|
|
64
102
|
.summary-table th, #summary-table td
|
65
103
|
:border-bottom 1px solid #DDD
|
@@ -73,32 +111,196 @@ h4
|
|
73
111
|
.summary-table td
|
74
112
|
:padding-left 5px
|
75
113
|
:padding-right 5px
|
114
|
+
:border-bottom 1px solid #DDD
|
115
|
+
:border-right 1px solid #DDD
|
116
|
+
|
117
|
+
.summary-table td.status3
|
118
|
+
:background url(/images/coquette/24x24/red_button.png) no-repeat 8px 5px
|
119
|
+
:padding 0px 0px 0px 40px
|
120
|
+
:margin 0px 0px 0px 5px
|
121
|
+
|
122
|
+
.summary-table td.status2
|
123
|
+
:background url(/images/coquette/24x24/yellow_button.png) no-repeat 8px 5px
|
124
|
+
:padding 0px 0px 0px 40px
|
125
|
+
:margin 0px 0px 0px 5px
|
126
|
+
|
127
|
+
.summary-table td.status1
|
128
|
+
:background url(/images/coquette/24x24/green_button.png) no-repeat 8px 5px
|
129
|
+
:padding 0px 0px 0px 40px
|
130
|
+
:margin 0px 0px 0px 5px
|
131
|
+
|
132
|
+
.summary-table td.distance-in-secs, .summary-table td.load, .summary-table td.free-disk-space, .summary-table td.free-memory, .summary-table td.swap-space
|
133
|
+
:text-align right
|
134
|
+
:padding-right 5px
|
135
|
+
|
136
|
+
.summary-table td.distance-in-secs.status1
|
137
|
+
:background url(/images/coquette/16x16/green_button.png) no-repeat 10px 11px
|
138
|
+
|
139
|
+
.summary-table td.distance-in-secs.status2
|
140
|
+
:background url(/images/coquette/16x16/yellow_button.png) no-repeat 10px 11px
|
141
|
+
|
142
|
+
.summary-table td.distance-in-secs.status3
|
143
|
+
:background url(/images/coquette/16x16/red_button.png) no-repeat 10px 11px
|
144
|
+
|
145
|
+
|
146
|
+
.summary-table span.bar
|
147
|
+
:display block
|
148
|
+
:position relative
|
149
|
+
:text-align center
|
150
|
+
:color #000
|
151
|
+
:height 1.7em
|
152
|
+
:line-height 1.5em
|
153
|
+
:font-size 0.9em
|
154
|
+
|
155
|
+
.summary-table span.status1
|
156
|
+
:background-color #99DD00
|
157
|
+
|
158
|
+
.summary-table span.status2
|
159
|
+
:background-color #FFAA00
|
160
|
+
|
161
|
+
.summary-table span.status3
|
162
|
+
:background-color #CC0000
|
163
|
+
|
164
|
+
|
165
|
+
.summary-table img.sparkline
|
166
|
+
:padding-top 5px
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
//************************************************************
|
171
|
+
// detail-table
|
172
|
+
|
173
|
+
.detail-table
|
174
|
+
:border-top 1px solid #DDD
|
175
|
+
:border-left 1px solid #DDD
|
176
|
+
:font-size 0.7em
|
177
|
+
:margin 20px 20px 0px 20px
|
178
|
+
:width 100%
|
179
|
+
|
180
|
+
.detail-table tr
|
181
|
+
:height 25px
|
182
|
+
|
183
|
+
.detail-table th, #summary-table td
|
184
|
+
:border-bottom 1px solid #DDD
|
185
|
+
:border-right 1px solid #DDD
|
186
|
+
|
187
|
+
.detail-table th
|
188
|
+
:background-color #EFEFEF
|
189
|
+
:padding-left 15px
|
190
|
+
:padding-right 15px
|
191
|
+
|
192
|
+
.detail-table td
|
193
|
+
:padding-left 5px
|
194
|
+
:padding-right 5px
|
195
|
+
:border-bottom 1px solid #DDD
|
196
|
+
:border-right 1px solid #DDD
|
197
|
+
|
198
|
+
.detail-table td.status3
|
199
|
+
:background url(/images/coquette/24x24/red_button.png) no-repeat 8px 5px
|
200
|
+
:padding 0px 0px 0px 40px
|
201
|
+
:margin 0px 0px 0px 5px
|
202
|
+
|
203
|
+
.detail-table td.status2
|
204
|
+
:background url(/images/coquette/24x24/yellow_button.png) no-repeat 8px 5px
|
205
|
+
:padding 0px 0px 0px 40px
|
206
|
+
:margin 0px 0px 0px 5px
|
207
|
+
|
208
|
+
.detail-table td.status1
|
209
|
+
:background url(/images/coquette/24x24/green_button.png) no-repeat 8px 5px
|
210
|
+
:padding 0px 0px 0px 40px
|
211
|
+
:margin 0px 0px 0px 5px
|
212
|
+
|
213
|
+
.detail-table td.space
|
214
|
+
:text-align right
|
215
|
+
:padding-right 5px
|
216
|
+
|
217
|
+
.detail-table span.bar
|
218
|
+
:display block
|
219
|
+
:position relative
|
220
|
+
:text-align center
|
221
|
+
:color #000
|
222
|
+
:height 1.7em
|
223
|
+
:line-height 1.5em
|
224
|
+
:font-size 0.9em
|
225
|
+
|
226
|
+
.detail-table span.status1
|
227
|
+
:background-color #99DD00
|
228
|
+
|
229
|
+
.detail-table span.status2
|
230
|
+
:background-color #FFAA00
|
231
|
+
|
232
|
+
.detail-table span.status3
|
233
|
+
:background-color #CC0000
|
234
|
+
|
76
235
|
|
236
|
+
.detail-table img.sparkline
|
237
|
+
:padding-top 5px
|
238
|
+
|
239
|
+
|
240
|
+
//************************************************************
|
241
|
+
// section-table
|
77
242
|
|
78
243
|
#section-table
|
79
244
|
:border 0px
|
80
245
|
|
81
246
|
#section-table td
|
82
247
|
:vertical-align top
|
83
|
-
|
248
|
+
:padding-right 20px
|
249
|
+
|
84
250
|
.section
|
251
|
+
:padding 0px
|
252
|
+
:margin 0px
|
85
253
|
:margin-bottom 20px
|
86
|
-
:
|
87
|
-
:border-right 1px solid #DDD
|
254
|
+
:width 100%
|
88
255
|
|
89
|
-
p
|
90
|
-
:
|
91
|
-
:margin 0px
|
92
|
-
:
|
93
|
-
:
|
256
|
+
.section p
|
257
|
+
:padding 0px 15px 10px 0px
|
258
|
+
:margin 0px 0px 20px 0px
|
259
|
+
:color #333
|
260
|
+
:font-size 0.6em
|
261
|
+
:float right
|
262
|
+
|
263
|
+
.section img
|
264
|
+
:margin 10px 40px 0px 30px
|
265
|
+
|
266
|
+
|
267
|
+
//************************************************************
|
268
|
+
// footer
|
94
269
|
|
95
270
|
#footer
|
96
271
|
:margin-top 20px
|
97
272
|
:clear both
|
98
273
|
:padding 10px
|
99
|
-
:color #
|
100
|
-
:text-align left
|
101
|
-
:font-family sans-serif
|
274
|
+
:color #666
|
102
275
|
:text-align center
|
276
|
+
:background-color #EFEFEF
|
277
|
+
:border-top 1px solid #DDD
|
278
|
+
:font-size 0.8em
|
279
|
+
|
280
|
+
#footer a
|
281
|
+
:color #666
|
282
|
+
|
283
|
+
|
284
|
+
//************************************************************
|
285
|
+
// lightbox
|
286
|
+
|
287
|
+
#simplemodal-overlay
|
288
|
+
:background-color #000
|
289
|
+
:cursor wait
|
103
290
|
|
291
|
+
#simplemodal-container
|
292
|
+
:height 550px
|
293
|
+
:width 800px
|
294
|
+
:background-color #FFF
|
295
|
+
:border 5px solid #666
|
104
296
|
|
297
|
+
#simplemodal-container a.modalCloseImg
|
298
|
+
:background url(/images/blossom/32x32/delete_item.png) no-repeat
|
299
|
+
:width 32px
|
300
|
+
:height 32px
|
301
|
+
:display inline
|
302
|
+
:z-index 3200
|
303
|
+
:position absolute
|
304
|
+
:top -14px
|
305
|
+
:right -18px
|
306
|
+
:cursor pointer
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spoonsix-dognotgod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis Correa d'Almeida
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-07 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -72,7 +72,7 @@ dependencies:
|
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: "0.9"
|
74
74
|
version:
|
75
|
-
description: dog not god is a
|
75
|
+
description: dog not god is a server health monitoring tool.
|
76
76
|
email: luis.ca@gmail.com
|
77
77
|
executables:
|
78
78
|
- dognotgod
|
@@ -82,6 +82,7 @@ extensions: []
|
|
82
82
|
extra_rdoc_files: []
|
83
83
|
|
84
84
|
files:
|
85
|
+
- app/models
|
85
86
|
- app/models/disk.rb
|
86
87
|
- app/models/file_system.rb
|
87
88
|
- app/models/host.rb
|
@@ -91,6 +92,7 @@ files:
|
|
91
92
|
- lib/client_commands.rb
|
92
93
|
- config.ru
|
93
94
|
- README.md
|
95
|
+
- views/host.haml
|
94
96
|
- views/layout.haml
|
95
97
|
- views/main.haml
|
96
98
|
- views/style.sass
|
@@ -99,6 +101,7 @@ files:
|
|
99
101
|
- client.rb
|
100
102
|
- bin/dognotgod
|
101
103
|
- bin/dognotgod-client
|
104
|
+
- public/javascripts/jquery.simplemodal-1.2.3.min.js
|
102
105
|
has_rdoc: false
|
103
106
|
homepage: http://github.com/spoonsix/dognotgod
|
104
107
|
post_install_message:
|
@@ -124,6 +127,6 @@ rubyforge_project:
|
|
124
127
|
rubygems_version: 1.2.0
|
125
128
|
signing_key:
|
126
129
|
specification_version: 2
|
127
|
-
summary: dog not god is a
|
130
|
+
summary: dog not god is a server health monitoring tool.
|
128
131
|
test_files: []
|
129
132
|
|