spoonsix-dognotgod 0.1.2 → 0.1.3

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.
@@ -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