spoonsix-dognotgod 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,41 +1,33 @@
1
1
  # dog not god: performance monitoring simplified
2
2
 
3
- dog not god is a performance monitoring tool for *nix based servers.
3
+ dog not god is a performance monitoring tool for *nix based servers. The focus is on simplicity and on a 100% ruby implementation.
4
4
 
5
- ## How does it work
5
+ ### Installation
6
6
 
7
- There are two components to dog not god.
7
+ gem sources -a http://gems.github.com
8
+ sudo gem install spoonsix-dognotgod
9
+ sudo gem install spoonsix-dognotgod-client
8
10
 
9
11
  ### Server
12
+ The server captures performance data, and presents it via a web based interface.
10
13
 
11
- The server plays two roles. First, it captures performance data, second, it presents it via a web based interface.
12
-
13
- ### Installation
14
-
15
- gem install dognotgod
16
- dognotgod start
14
+ dognotgod start
17
15
 
18
- This will kick off a thin server on port 4567. It will also create the folder ~/.dognotgod and store the sqlite database at this location.
16
+ This will kick off a thin server on port 4567. It will also create the folder ~/.dognotgod and store the SQLite database at this location.
19
17
 
20
18
  ### Client
21
19
 
22
20
  The client sits on the target machine - the machine to be monitored - captures performance data and sends it to the server. Note that this works on the machine acting as the server as well.
23
21
 
24
- ### Installation
25
-
26
- gem install dognotgod-client
27
-
28
- Add an entry to crontab
29
-
30
- crontab -e
31
- */1 * * * * ruby /path/to/gem/client.rb >> /dev/null 2>&1
22
+ crontab -e
23
+ */1 * * * * dognotgod-client -a server-address -p port >> /dev/null 2>&1
32
24
 
33
- This will run the client every minute.
25
+ This will run the client every minute. By default, the server-address is 127.0.0.1 and the port is 4567.
34
26
 
35
27
  ## License
36
28
 
37
29
  dog not god: performance monitoring simplified
38
- Copyright (C) 2009 Luis Correa d'Almeida
30
+ Copyright (C) 2009 spoonsix - Luis Correa d'Almeida
39
31
 
40
32
  This program is free software; you can redistribute it and/or
41
33
  modify it under the terms of the GNU General Public License
@@ -0,0 +1,28 @@
1
+ class Disk < Sequel::Model
2
+
3
+ many_to_one :filesystems
4
+
5
+ unless table_exists?
6
+ set_schema do
7
+ primary_key :id
8
+ integer :file_system_id
9
+ string :mounted_on
10
+ integer :used
11
+ integer :available
12
+ timestamp :created_at
13
+ timestamp :grain_5_min
14
+ timestamp :grain_15_min
15
+ timestamp :grain_30_min
16
+ timestamp :grain_60_min
17
+ end
18
+ create_table
19
+ end
20
+
21
+ before_create do
22
+ self.created_at = Time.now.utc unless self.created_at
23
+ self.grain_5_min = self.created_at.to_five_minute_grain_format
24
+ self.grain_15_min = self.created_at.to_fifteen_minute_grain_format
25
+ self.grain_30_min = self.created_at.to_thirty_minute_grain_format
26
+ self.grain_60_min = self.created_at.to_sixty_minute_grain_format
27
+ end
28
+ end
@@ -0,0 +1,98 @@
1
+ class FileSystem < Sequel::Model
2
+
3
+ many_to_one :hosts
4
+ one_to_many :disks
5
+
6
+ unless table_exists?
7
+ set_schema do
8
+ primary_key :id
9
+ integer :host_id
10
+ string :name
11
+ string :mounted_on
12
+ timestamp :created_at
13
+ end
14
+ create_table
15
+ end
16
+
17
+ def is_dev?
18
+ self.name.scan(/^\/dev/).size > 0
19
+ end
20
+
21
+ def size_in_Gb
22
+ last_entry = DB[:disks].filter(:file_system_id => self.id).reverse_order(:created_at).last
23
+ if last_entry
24
+ (last_entry[:available] + last_entry[:used]) / 1024 / 1024
25
+ else
26
+ 0
27
+ end
28
+ end
29
+
30
+ def used_in_Gb
31
+ last_entry = DB[:disks].filter(:file_system_id => self.id).reverse_order(:created_at).last
32
+ if last_entry
33
+ last_entry[:used] / 1024 / 1024
34
+ else
35
+ 0
36
+ end
37
+ end
38
+
39
+ def available_in_Gb
40
+ last_entry = DB[:disks].filter(:file_system_id => self.id).reverse_order(:created_at).last
41
+ if last_entry
42
+ last_entry[:available] / 1024 / 1024
43
+ else
44
+ 0
45
+ end
46
+ end
47
+
48
+ def disks_5_min_grain(start_time, end_time)
49
+ 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
50
+
51
+ time_range = (start_time..end_time)
52
+
53
+ series = []
54
+ series[0] = []
55
+ series[1] = []
56
+ series[2] = []
57
+ series[3] = []
58
+ time_range.step(300) do |five|
59
+ series[0] << five.to_minute_format
60
+ if disk.size > 0 and disk[0][:grain_5_min].to_minute_format == five.to_minute_format
61
+ disk_for_this_dim = disk.shift
62
+ series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used])
63
+ series[2] << disk_for_this_dim[:used]
64
+ else
65
+ series[1] << -1
66
+ series[2] << -1
67
+ end
68
+ end
69
+
70
+ series
71
+ end
72
+
73
+ def disks_15_min_grain(start_time, end_time)
74
+ disk = DB.fetch("SELECT ROUND(AVG(available)/1024/1024, 1) AS available, ROUND(AVG(used)/1024/1024, 1) AS used, grain_15_min FROM disks WHERE file_system_id = #{self.id} AND grain_15_min >= '#{start_time.to_fifteen_minute_grain_format.to_sql_format}' AND grain_15_min <= '#{end_time.to_fifteen_minute_grain_format.to_sql_format}' GROUP BY grain_15_min;").all
75
+
76
+ time_range = (start_time..end_time)
77
+
78
+ series = []
79
+ series[0] = []
80
+ series[1] = []
81
+ series[2] = []
82
+ series[3] = []
83
+ time_range.step(900) do |fifteen|
84
+ series[0] << fifteen.to_minute_format
85
+ if disk.size > 0 and disk[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
86
+ disk_for_this_dim = disk.shift
87
+ series[1] << (disk_for_this_dim[:available] + disk_for_this_dim[:used])
88
+ series[2] << disk_for_this_dim[:used]
89
+ else
90
+ series[1] << -1
91
+ series[2] << -1
92
+ end
93
+ end
94
+
95
+ series
96
+ end
97
+
98
+ end
data/app/models/host.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  class Host < Sequel::Model
2
2
 
3
3
  one_to_many :loads
4
+ one_to_many :file_systems
5
+ one_to_many :memories
4
6
 
5
7
  unless table_exists?
6
8
  set_schema do
@@ -11,18 +13,141 @@ class Host < Sequel::Model
11
13
  create_table
12
14
  end
13
15
 
16
+ ####################
17
+ # Heartbeat
18
+ ####################
19
+
20
+ # Timestamp of last entry in 'loads' table for this host
14
21
  def last_contacted_on
15
22
  self.loads.last.created_at if self.loads.last
16
23
  end
17
24
 
25
+ # Seconds to timestamp of last entry in 'loads' table for this host
18
26
  def distance_to_last_heartbeat_in_seconds
19
27
  (Time.now - self.loads.last.created_at) if self.loads.last
20
28
  end
21
29
 
22
- def loads2(start_time, end_time)
23
- load = DB.fetch("SELECT AVG(load_5_min) AS load_5_min, AVG(load_10_min) AS load_10_min, AVG(load_15_min) AS load_15_min, grain_5_min FROM loads WHERE host_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
24
- end
25
30
 
31
+ ####################
32
+ # Disk space
33
+ ####################
34
+ def total_disk_space_in_Gb
35
+ @total = 0
36
+ self.file_systems.each do |fs|
37
+ @total += fs.size_in_Gb
38
+ end
39
+
40
+ @total
41
+ end
42
+
43
+ def available_disk_space_in_Gb
44
+ @available = 0
45
+ self.file_systems.each do |fs|
46
+ @available += fs.available_in_Gb
47
+ end
48
+
49
+ @available
50
+ end
51
+
52
+
53
+ ####################
54
+ # Memory
55
+ ####################
56
+
57
+ def total_memory_in_Mb
58
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
59
+ if last_entry
60
+ (last_entry[:mem_available] + last_entry[:mem_used]) / 1024
61
+ else
62
+ 0
63
+ end
64
+ end
65
+
66
+ def available_memory_in_Mb
67
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
68
+ if last_entry
69
+ last_entry[:mem_available] / 1024
70
+ else
71
+ 0
72
+ end
73
+ end
74
+
75
+ def used_memory_in_Mb
76
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
77
+ if last_entry
78
+ last_entry[:mem_used] / 1024
79
+ else
80
+ 0
81
+ end
82
+ end
83
+
84
+ def memory_stats_15_min_grain(start_time, end_time)
85
+ data = DB.fetch("SELECT ROUND(AVG(mem_available)/1024,0) AS mem_available, ROUND(AVG(mem_used)/1024,0) AS mem_used, ROUND(AVG(swap_available)/1024,0) AS swap_available, ROUND(AVG(swap_used)/1024, 0) AS swap_used, grain_15_min FROM memories WHERE host_id = #{self.id} AND grain_15_min >= '#{start_time.to_fifteen_minute_grain_format.to_sql_format}' AND grain_15_min <= '#{end_time.to_fifteen_minute_grain_format.to_sql_format}' GROUP BY grain_15_min;").all
86
+
87
+ time_range = (start_time..end_time)
88
+
89
+ series = []
90
+ series[0] = []
91
+ series[1] = []
92
+ series[2] = []
93
+ series[3] = []
94
+ series[4] = []
95
+
96
+ time_range.step(900) do |fifteen|
97
+ series[0] << fifteen.to_minute_format
98
+ if data.size > 0 and data[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
99
+ fact_for_this_dim = data.shift
100
+ series[1] << fact_for_this_dim[:mem_available]
101
+ series[2] << fact_for_this_dim[:mem_used]
102
+ series[3] << fact_for_this_dim[:swap_available]
103
+ series[4] << fact_for_this_dim[:swap_used]
104
+ else
105
+ series[1] << -1
106
+ series[2] << -1
107
+ series[3] << -1
108
+ series[4] << -1
109
+ end
110
+ end
111
+
112
+ series
113
+ end
114
+
115
+
116
+ ####################
117
+ # Swap
118
+ ####################
119
+
120
+ def total_swap_in_Mb
121
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
122
+ if last_entry
123
+ (last_entry[:swap_available] + last_entry[:swap_used]) / 1024
124
+ else
125
+ 0
126
+ end
127
+ end
128
+
129
+ def available_swap_in_Mb
130
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
131
+ if last_entry
132
+ last_entry[:swap_available] / 1024
133
+ else
134
+ 0
135
+ end
136
+ end
137
+
138
+ def used_swap_in_Mb
139
+ last_entry = DB[:memories].filter(:host_id => self.id).reverse_order(:created_at).last
140
+ if last_entry
141
+ last_entry[:swap_used] / 1024
142
+ else
143
+ 0
144
+ end
145
+ end
146
+
147
+ ####################
148
+ # Load stats
149
+ ####################
150
+
26
151
  def loads_5_min_grain(start_time, end_time)
27
152
  load = DB.fetch("SELECT ROUND(AVG(load_5_min),1) AS load_5_min, ROUND(AVG(load_10_min),1) AS load_10_min, ROUND(AVG(load_15_min),1) AS load_15_min, grain_5_min FROM loads WHERE host_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
28
153
 
@@ -70,6 +195,7 @@ class Host < Sequel::Model
70
195
  series[1] = []
71
196
  series[2] = []
72
197
  series[3] = []
198
+ i = 0
73
199
  time_range.step(900) do |fifteen|
74
200
  series[0] << fifteen.to_minute_format
75
201
  if load.size > 0 and load[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
@@ -86,7 +212,7 @@ class Host < Sequel::Model
86
212
 
87
213
  series
88
214
  end
89
-
215
+
90
216
  def load_5_min
91
217
  self.loads.last.load_5_min if self.loads.last
92
218
  end
@@ -113,8 +239,4 @@ class Host < Sequel::Model
113
239
  end
114
240
  end
115
241
 
116
- def to_google_params
117
-
118
- end
119
-
120
242
  end
data/app/models/load.rb CHANGED
@@ -19,7 +19,7 @@ class Load < Sequel::Model
19
19
  end
20
20
 
21
21
  before_create do
22
- self.created_at = Time.now unless self.created_at
22
+ self.created_at = Time.now.utc unless self.created_at
23
23
  self.grain_5_min = self.created_at.to_five_minute_grain_format
24
24
  self.grain_15_min = self.created_at.to_fifteen_minute_grain_format
25
25
  self.grain_30_min = self.created_at.to_thirty_minute_grain_format
@@ -0,0 +1,29 @@
1
+ class Memory < Sequel::Model
2
+
3
+ many_to_one :hosts
4
+
5
+ unless table_exists?
6
+ set_schema do
7
+ primary_key :id
8
+ integer :host_id
9
+ integer :mem_available
10
+ integer :mem_used
11
+ integer :swap_available
12
+ integer :swap_used
13
+ timestamp :created_at
14
+ timestamp :grain_5_min
15
+ timestamp :grain_15_min
16
+ timestamp :grain_30_min
17
+ timestamp :grain_60_min
18
+ end
19
+ create_table
20
+ end
21
+
22
+ before_create do
23
+ self.created_at = Time.now.utc unless self.created_at
24
+ self.grain_5_min = self.created_at.to_five_minute_grain_format
25
+ self.grain_15_min = self.created_at.to_fifteen_minute_grain_format
26
+ self.grain_30_min = self.created_at.to_thirty_minute_grain_format
27
+ self.grain_60_min = self.created_at.to_sixty_minute_grain_format
28
+ end
29
+ end
data/server.rb CHANGED
@@ -14,7 +14,10 @@ configure do
14
14
 
15
15
  # require 'ostruct'
16
16
  require 'host'
17
+ require 'file_system'
17
18
  require 'load'
19
+ require 'disk'
20
+ require 'memory'
18
21
  end
19
22
 
20
23
  error do
@@ -27,64 +30,82 @@ error do
27
30
  end
28
31
 
29
32
  helpers do
30
- def admin?
31
- # request.cookies[Blog.admin_cookie_key] == Blog.admin_cookie_value
33
+
34
+ def get_host_or_create_if_not_exist(hostname)
35
+ host = DB[:hosts].filter(:hostname => hostname).first
36
+
37
+ unless host
38
+ DB[:hosts] << {:hostname => hostname}
39
+ host = DB[:hosts].filter(:hostname => hostname).first
40
+ end
41
+ host
32
42
  end
33
-
34
- def auth
35
- stop [ 401, 'Not authorized' ] unless admin?
43
+
44
+ def get_fs_or_create_if_not_exist(host_id, fs_name, mounted_on)
45
+ fs = DB[:file_systems].filter(:name => fs_name, :mounted_on => mounted_on).first
46
+
47
+ unless fs
48
+ DB[:file_systems] << {:name => fs_name, :mounted_on => mounted_on, :host_id => host_id}
49
+ fs = DB[:file_systems].filter(:name => fs_name, :mounted_on => mounted_on).first
50
+ end
51
+ fs
36
52
  end
53
+
37
54
  end
38
-
55
+
56
+ get '/stylesheets/style.css' do
57
+ header 'Content-Type' => 'text/css; charset=utf-8'
58
+ sass :style
59
+ end
60
+
39
61
  get "/" do
40
62
  @hosts = Host.order(:hostname).all
41
63
 
42
- @end_now = Time.now.to_fifteen_minute_grain_format
64
+ @end_now = Time.now.utc.to_fifteen_minute_grain_format
43
65
  @start_24h_ago = @end_now - (60*60*24)
44
66
  @start_6h_ago = @end_now - (60*60*6)
45
67
 
46
68
  haml :main
47
69
  end
48
70
 
49
- get "/hosts/:id/loads.xml" do
50
- @host = Host[params[:id]]
51
-
52
- @end_time = Time.now.to_five_minute_grain_format # Round to zero seconds on the minute
53
- @start_time = @end_time - (60*60*24)
54
- @time_range = (@start_time..@end_time)
55
-
56
- @loads = @host.loads2(@start_time, @end_time)
57
-
58
- content_type 'application/xml', :charset => 'utf-8'
59
- haml :loads_xml, :layout => false
60
- end
71
+ post "/load_stats" do
61
72
 
62
- post "/loads" do
63
- host = DB[:hosts].filter(:hostname => params[:hostname]).first
64
-
65
- # create an entry for a new host if it doesn't exist
66
- unless host
67
- DB[:hosts] << {:hostname => params[:hostname]}
68
- host = DB[:hosts].filter(:hostname => params[:hostname]).first
73
+ begin
74
+ host = get_host_or_create_if_not_exist(params[:hostname])
75
+ load_stats = Load.new({:load_5_min => params[:load_5_min], :load_10_min => params[:load_10_min], :load_15_min => params[:load_15_min], :host_id => host[:id]})
76
+ load_stats.save
77
+ status(201)
78
+ rescue
79
+ status(500)
69
80
  end
81
+ end
82
+
83
+ post "/mem_stats" do
70
84
 
71
- @now = Time.now
72
-
73
- load = Load.new({:load_5_min => params[:load_5_min], :load_10_min => params[:load_10_min], :load_15_min => params[:load_15_min], :host_id => host[:id], :created_at => @now})
74
- if load.save
85
+ begin
86
+ host = get_host_or_create_if_not_exist(params[:hostname])
87
+ mem_stats = Memory.new({:host_id => host[:id], :mem_available => params[:mem_available], :mem_used => params[:mem_used], :swap_available => params[:swap_available], :swap_used => params[:swap_used]})
88
+ mem_stats.save
75
89
  status(201)
76
- # response['Location'] = ""
77
- else
90
+ rescue
78
91
  status(500)
79
92
  end
80
93
  end
81
94
 
82
- get '/stylesheets/style.css' do
83
- header 'Content-Type' => 'text/css; charset=utf-8'
84
- sass :style
95
+ post "/file_system_stats" do
96
+
97
+ begin
98
+ host = get_host_or_create_if_not_exist(params[:hostname])
99
+ fs = get_fs_or_create_if_not_exist(host[:id], params[:file_system_name], params[:mounted_on])
100
+
101
+ disk_stats = Disk.new({:file_system_id => fs[:id], :mounted_on => params[:mounted_on], :used => params[:used], :available => params[:available]})
102
+ disk_stats.save
103
+ status(201)
104
+ rescue
105
+ status(500)
106
+ end
85
107
  end
86
108
 
87
-
88
109
  class Time
89
110
 
90
111
  # Rounds up to the 5 min intervals
data/views/layout.haml CHANGED
@@ -3,6 +3,10 @@
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/flot/jquery.flot.pack.js"}
9
+
6
10
 
7
11
  %body
8
12
  #header
data/views/main.haml CHANGED
@@ -3,17 +3,23 @@
3
3
  %table{:id => "summary-table", :cellspacing => 0, :cellpading => 0}
4
4
  %tr
5
5
  %th Host
6
+ %th Last heartbeat
6
7
  %th 5 min average
7
8
  %th 10 min average
8
9
  %th 15 min average
9
- %th Last heartbeat
10
+ %th Free disk space
11
+ %th Free memory
12
+ %th Free swap space
10
13
  -for host in @hosts
11
14
  %tr{:class => "level#{host.status}"}
12
15
  %td= host.hostname
16
+ %td= "#{host.distance_to_last_heartbeat_in_seconds.to_i} seconds ago" unless host.status == 0
13
17
  %td= host.load_5_min
14
18
  %td= host.load_10_min
15
19
  %td= host.load_15_min
16
- %td= "#{host.distance_to_last_heartbeat_in_seconds.to_i} seconds ago" unless host.status == 0
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
17
23
 
18
24
 
19
25
 
@@ -21,17 +27,40 @@
21
27
  %tr
22
28
  -for host in @hosts
23
29
  - series_6h = host.loads_5_min_grain(@start_6h_ago, @end_now)
24
- - params_for_6h = "cht=lc&chs=350x120&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.2,0.21&chxt=x,y&chxr=1,0,5,1&chds=0,5&chl=&chd=t:#{series_6h[1].join(",")}|#{series_6h[2].join(",")}|#{series_6h[3].join(",")}"
30
+ - params_for_6h = "cht=lc&chs=350x120&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.2,0.21&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(",")}"
25
31
  - series_24h = host.loads_15_min_grain(@start_24h_ago, @end_now)
26
- - params_for_24h = "cht=lc&chs=350x120&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.2,0.21&chxt=x,y&chxr=1,0,5,1&chds=0,5&chl=&chd=t:#{series_24h[1].join(",")}|#{series_24h[2].join(",")}|#{series_24h[3].join(",")}"
32
+ - params_for_24h = "cht=lc&chs=350x120&chco=FF0000,00FF00,0000FF&chm=r,DDDDDD,0,0.2,0.21&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(",")}"
33
+ - mem_series_24h = host.memory_stats_15_min_grain(@start_24h_ago, @end_now)
34
+ - mem_params_for_24h = "cht=lc&chs=350x120&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(",")}"
35
+ - swap_params_for_24h = "cht=lc&chs=350x120&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(",")}"
27
36
  %td
28
37
  .section
29
38
  %h2=host.hostname
30
39
  %p== Last heard from on #{host.last_contacted_on}
40
+
31
41
  %h4 Load averages for the last 24 hours
32
42
  %img{ :src => "http://chart.apis.google.com/chart?#{params_for_24h}"}
43
+
33
44
  %h4 Load averages for the last 6 hours
34
45
  %img{ :src => "http://chart.apis.google.com/chart?#{params_for_6h}"}
35
46
 
47
+ %h4 Memory
48
+ %p{:style => "float:right;"}== Total memory is #{host.total_memory_in_Mb}Mb
49
+ %br
50
+ %img{ :src => "http://chart.apis.google.com/chart?#{mem_params_for_24h}"}
51
+
52
+ %h4 Swap
53
+ %p{:style => "float:right;"}== Total memory is #{host.total_swap_in_Mb}Mb
54
+ %br
55
+ %img{ :src => "http://chart.apis.google.com/chart?#{swap_params_for_24h}"}
56
+
57
+ - host.file_systems.each do |fs|
58
+ - if fs.is_dev? and fs.size_in_Gb > 0
59
+ - series_24h = fs.disks_15_min_grain(@start_24h_ago, @end_now)
60
+ - 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(",")}"
61
+ %h4== #{fs.mounted_on} on #{fs.name}
62
+ %p{:style => "float:right;"}== Device size is #{fs.size_in_Gb}Gb
63
+ %br
64
+ %img{ :src => "http://chart.apis.google.com/chart?#{params_for_24h}"}
36
65
 
37
66
 
data/views/style.sass CHANGED
@@ -4,6 +4,9 @@ body
4
4
  :font-family Courier
5
5
  :font-size 1.0em
6
6
 
7
+ br
8
+ :clear both
9
+
7
10
  a, a:visited
8
11
  :color #AAA
9
12
 
@@ -22,7 +25,7 @@ h2
22
25
  :text-decoration underline
23
26
 
24
27
  h4
25
- :margin 20px 10px 20px 5px
28
+ :margin 20px 10px 10px 0px
26
29
  :padding 5px
27
30
  :background-color #EFEFEF
28
31
 
@@ -45,13 +48,13 @@ h4
45
48
  :border-left 1px solid #DDD
46
49
 
47
50
 
48
- #summary-table tr.level5
51
+ #summary-table tr.level4, #summary-table tr.level5
49
52
  :background-color #99FF99
50
53
 
51
54
  #summary-table tr.level3
52
55
  :background-color #999933
53
56
 
54
- #summary-table tr.level1
57
+ #summary-table tr.level1, #summary-table tr.level2
55
58
  :background-color #DD3333
56
59
 
57
60
  #summary-table tr.level0
@@ -71,9 +74,13 @@ h4
71
74
  :padding-left 5px
72
75
  :padding-right 5px
73
76
 
77
+
74
78
  #section-table
75
79
  :border 0px
76
80
 
81
+ #section-table td
82
+ :vertical-align top
83
+
77
84
  .section
78
85
  :margin-bottom 20px
79
86
  :margin-left 20px
@@ -83,6 +90,7 @@ p
83
90
  :font-size 0.7em
84
91
  :margin 0px
85
92
  :padding 0px
93
+ :margin-right 10px
86
94
 
87
95
  #footer
88
96
  :margin-top 20px
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.2
4
+ version: 0.1.3
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-02-28 00:00:00 -08:00
12
+ date: 2009-03-01 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -62,38 +62,28 @@ dependencies:
62
62
  - !ruby/object:Gem::Version
63
63
  version: 1.2.4
64
64
  version:
65
- - !ruby/object:Gem::Dependency
66
- name: rest-client
67
- type: :runtime
68
- version_requirement:
69
- version_requirements: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: "0.9"
74
- version:
75
65
  description: dog not god is a performance monitoring tool.
76
66
  email: luis.ca@gmail.com
77
67
  executables:
78
68
  - dognotgod
79
- - dognotgod-client
80
69
  extensions: []
81
70
 
82
71
  extra_rdoc_files: []
83
72
 
84
73
  files:
85
74
  - app/models
75
+ - app/models/disk.rb
76
+ - app/models/file_system.rb
86
77
  - app/models/host.rb
87
78
  - app/models/load.rb
79
+ - app/models/memory.rb
88
80
  - config.ru
89
- - README
81
+ - README.md
90
82
  - views/layout.haml
91
- - views/loads_xml.haml
92
83
  - views/main.haml
93
84
  - views/style.sass
94
85
  - config/thin.yml
95
86
  - server.rb
96
- - client.rb
97
87
  has_rdoc: false
98
88
  homepage: http://github.com/spoonsix/dognotgod
99
89
  post_install_message:
data/bin/dognotgod-client DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'rubygems'
3
-
4
- DOGNOTGOD_DIR = "#{File.dirname(__FILE__)}/.."
5
- Dir.chdir(DOGNOTGOD_DIR)
6
- load 'client.rb'
data/client.rb DELETED
@@ -1,64 +0,0 @@
1
- require 'rubygems'
2
- require 'optparse'
3
- require 'restclient'
4
-
5
- module DogNotGod
6
-
7
- class Client
8
-
9
- def initialize(argv)
10
- @argv = argv
11
-
12
- # Default options values
13
- @options = {
14
- :server_addr => "127.0.0.1",
15
- :server_port => "4567",
16
- :timeout => 5
17
- }
18
-
19
- parse!
20
-
21
- @endpoint = "http://#{@options[:server_addr]}:#{@options[:server_port]}"
22
- end
23
-
24
- def parser
25
- # NOTE: If you add an option here make sure the key in the +options+ hash is the
26
- # same as the name of the command line option.
27
- # +option+ keys are used to build the command line to launch other processes,
28
- # see <tt>lib/thin/command.rb</tt>.
29
- @parser ||= OptionParser.new do |opts|
30
- opts.banner = "Usage: dognotgod-client [options]"
31
- opts.separator ""
32
- opts.separator "Server options:"
33
-
34
- opts.on("-a", "--server-addr HOST", "HOST address to call (default: #{@options[:server_addr]})") { |host| @options[:server_addr] = host }
35
- opts.on("-p", "--server-port PORT", "use PORT (default: #{@options[:server_port]})") { |port| @options[:server_port] = port.to_i }
36
- #opts.on("-t", "--timeout SECONDS", "timeout after SECONDS (default: #{@options[:timeout]})") { |port| @options[:timeout] = port.to_i }
37
- opts.separator ""
38
- end
39
- end
40
-
41
- # Parse the options.
42
- def parse!
43
- parser.parse! @argv
44
- @arguments = @argv
45
- end
46
-
47
- def run!
48
- hostname = %x[hostname].split("\n")[0]
49
- uptime = %x[uptime]
50
- avgs = uptime.scan(/(\d+\.\d\d)/)
51
-
52
- begin
53
- RestClient.post("#{@endpoint}/loads", :load_5_min => avgs[0], :load_10_min => avgs[1], :load_15_min => avgs[2], :hostname => hostname)
54
- puts "OK"
55
- rescue
56
- puts "There was a problem connecting to the server on #{@endpoint}."
57
- end
58
- end
59
-
60
- end
61
-
62
- end
63
-
64
- DogNotGod::Client.new(ARGV).run!
data/views/loads_xml.haml DELETED
@@ -1,23 +0,0 @@
1
- !!! XML
2
- %chart
3
- %series
4
- -i=0
5
- -@time_range.step(300) do |five|
6
- %value{:xid => i+=1}
7
- =five.to_minute_format
8
- %graphs
9
- %graph{:gid => "1"}
10
- -i=0
11
- -load = Array.new(@loads)
12
- -@time_range.step(300) do |five|
13
- %value{:xid => i+=1}= load.shift[:load_5_min] if load.size > 0 and load[0][:grain_5_min].to_minute_format == five.to_minute_format
14
- %graph{:gid => "2"}
15
- -i=0
16
- -load = Array.new(@loads)
17
- -@time_range.step(300) do |five|
18
- %value{:xid => i+=1}= load.shift[:load_10_min] if load.size > 0 and load[0][:grain_5_min].to_minute_format == five.to_minute_format
19
- %graph{:gid => "3"}
20
- -i=0
21
- -load = Array.new(@loads)
22
- -@time_range.step(300) do |five|
23
- %value{:xid => i+=1}= load.shift[:load_15_min] if load.size > 0 and load[0][:grain_5_min].to_minute_format == five.to_minute_format