spoonsix-dognotgod 0.1.2
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 +52 -0
- data/app/models/host.rb +120 -0
- data/app/models/load.rb +28 -0
- data/bin/dognotgod +7 -0
- data/bin/dognotgod-client +6 -0
- data/client.rb +64 -0
- data/config.ru +4 -0
- data/config/thin.yml +11 -0
- data/server.rb +127 -0
- data/views/layout.haml +17 -0
- data/views/loads_xml.haml +23 -0
- data/views/main.haml +37 -0
- data/views/style.sass +96 -0
- metadata +124 -0
data/README
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# dog not god: performance monitoring simplified
|
2
|
+
|
3
|
+
dog not god is a performance monitoring tool for *nix based servers.
|
4
|
+
|
5
|
+
## How does it work
|
6
|
+
|
7
|
+
There are two components to dog not god.
|
8
|
+
|
9
|
+
### Server
|
10
|
+
|
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
|
17
|
+
|
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.
|
19
|
+
|
20
|
+
### Client
|
21
|
+
|
22
|
+
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
|
+
|
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
|
32
|
+
|
33
|
+
This will run the client every minute.
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
dog not god: performance monitoring simplified
|
38
|
+
Copyright (C) 2009 Luis Correa d'Almeida
|
39
|
+
|
40
|
+
This program is free software; you can redistribute it and/or
|
41
|
+
modify it under the terms of the GNU General Public License
|
42
|
+
as published by the Free Software Foundation; either version 2
|
43
|
+
of the License, or (at your option) any later version.
|
44
|
+
|
45
|
+
This program is distributed in the hope that it will be useful,
|
46
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
47
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
48
|
+
GNU General Public License for more details.
|
49
|
+
|
50
|
+
You should have received a copy of the GNU General Public License
|
51
|
+
along with this program; if not, write to the Free Software
|
52
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
data/app/models/host.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
class Host < Sequel::Model
|
2
|
+
|
3
|
+
one_to_many :loads
|
4
|
+
|
5
|
+
unless table_exists?
|
6
|
+
set_schema do
|
7
|
+
primary_key :id
|
8
|
+
text :hostname
|
9
|
+
timestamp :created_at
|
10
|
+
end
|
11
|
+
create_table
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_contacted_on
|
15
|
+
self.loads.last.created_at if self.loads.last
|
16
|
+
end
|
17
|
+
|
18
|
+
def distance_to_last_heartbeat_in_seconds
|
19
|
+
(Time.now - self.loads.last.created_at) if self.loads.last
|
20
|
+
end
|
21
|
+
|
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
|
+
|
26
|
+
def loads_5_min_grain(start_time, end_time)
|
27
|
+
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
|
+
|
29
|
+
time_range = (start_time..end_time)
|
30
|
+
|
31
|
+
series = []
|
32
|
+
series[0] = []
|
33
|
+
series[1] = []
|
34
|
+
series[2] = []
|
35
|
+
series[3] = []
|
36
|
+
time_range.step(300) do |five|
|
37
|
+
series[0] << five.to_minute_format
|
38
|
+
if load.size > 0 and load[0][:grain_5_min].to_minute_format == five.to_minute_format
|
39
|
+
load_for_this_dim = load.shift
|
40
|
+
series[1] << load_for_this_dim[:load_5_min]
|
41
|
+
series[2] << load_for_this_dim[:load_10_min]
|
42
|
+
series[3] << load_for_this_dim[:load_15_min]
|
43
|
+
else
|
44
|
+
series[1] << -1
|
45
|
+
series[2] << -1
|
46
|
+
series[3] << -1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
series
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Returns the load for this host in the following format
|
55
|
+
#
|
56
|
+
# series[0] will contain the time series data. This method will return the data in 15 min intervals.
|
57
|
+
# series[1] will contain the 5 min load averages
|
58
|
+
# series[2] will contain the 10 min load averages
|
59
|
+
# series[3] will contain the 15 min load averages
|
60
|
+
#
|
61
|
+
# If not data exists for a particular time period, then the value is -1
|
62
|
+
#
|
63
|
+
def loads_15_min_grain(start_time, end_time)
|
64
|
+
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_15_min FROM loads 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
|
65
|
+
|
66
|
+
time_range = (start_time..end_time)
|
67
|
+
|
68
|
+
series = []
|
69
|
+
series[0] = []
|
70
|
+
series[1] = []
|
71
|
+
series[2] = []
|
72
|
+
series[3] = []
|
73
|
+
time_range.step(900) do |fifteen|
|
74
|
+
series[0] << fifteen.to_minute_format
|
75
|
+
if load.size > 0 and load[0][:grain_15_min].to_minute_format == fifteen.to_minute_format
|
76
|
+
load_for_this_dim = load.shift
|
77
|
+
series[1] << load_for_this_dim[:load_5_min]
|
78
|
+
series[2] << load_for_this_dim[:load_10_min]
|
79
|
+
series[3] << load_for_this_dim[:load_15_min]
|
80
|
+
else
|
81
|
+
series[1] << -1
|
82
|
+
series[2] << -1
|
83
|
+
series[3] << -1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
series
|
88
|
+
end
|
89
|
+
|
90
|
+
def load_5_min
|
91
|
+
self.loads.last.load_5_min if self.loads.last
|
92
|
+
end
|
93
|
+
|
94
|
+
def load_10_min
|
95
|
+
self.loads.last.load_10_min if self.loads.last
|
96
|
+
end
|
97
|
+
|
98
|
+
def load_15_min
|
99
|
+
self.loads.last.load_15_min if self.loads.last
|
100
|
+
end
|
101
|
+
|
102
|
+
def status
|
103
|
+
if self.last_contacted_on == nil
|
104
|
+
0
|
105
|
+
elsif Time.now - self.last_contacted_on < 90
|
106
|
+
5
|
107
|
+
elsif Time.now - self.last_contacted_on < 180
|
108
|
+
3
|
109
|
+
elsif Time.now - self.last_contacted_on < 300
|
110
|
+
2
|
111
|
+
else
|
112
|
+
1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_google_params
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
data/app/models/load.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Load < 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
|
+
float :load_5_min
|
10
|
+
float :load_10_min
|
11
|
+
float :load_15_min
|
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 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
|
data/bin/dognotgod
ADDED
data/client.rb
ADDED
@@ -0,0 +1,64 @@
|
|
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/config.ru
ADDED
data/config/thin.yml
ADDED
data/server.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
configure do
|
5
|
+
DB_DIR = "#{ENV['HOME']}/.dognotgod"
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/app/models'
|
8
|
+
require 'sequel'
|
9
|
+
require 'logger'
|
10
|
+
|
11
|
+
Dir.mkdir(DB_DIR) unless File.exists?(DB_DIR)
|
12
|
+
DB = Sequel.connect("sqlite://#{DB_DIR}/dog.db")
|
13
|
+
DB.loggers << Logger.new($stdout)
|
14
|
+
|
15
|
+
# require 'ostruct'
|
16
|
+
require 'host'
|
17
|
+
require 'load'
|
18
|
+
end
|
19
|
+
|
20
|
+
error do
|
21
|
+
e = request.env['sinatra.error']
|
22
|
+
puts e.to_s
|
23
|
+
puts e.backtrace.join("\n")
|
24
|
+
"<pre>" + e + "<br /><br />" + e.backtrace.join("\n")
|
25
|
+
|
26
|
+
# "Application error"
|
27
|
+
end
|
28
|
+
|
29
|
+
helpers do
|
30
|
+
def admin?
|
31
|
+
# request.cookies[Blog.admin_cookie_key] == Blog.admin_cookie_value
|
32
|
+
end
|
33
|
+
|
34
|
+
def auth
|
35
|
+
stop [ 401, 'Not authorized' ] unless admin?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
get "/" do
|
40
|
+
@hosts = Host.order(:hostname).all
|
41
|
+
|
42
|
+
@end_now = Time.now.to_fifteen_minute_grain_format
|
43
|
+
@start_24h_ago = @end_now - (60*60*24)
|
44
|
+
@start_6h_ago = @end_now - (60*60*6)
|
45
|
+
|
46
|
+
haml :main
|
47
|
+
end
|
48
|
+
|
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
|
61
|
+
|
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
|
69
|
+
end
|
70
|
+
|
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
|
75
|
+
status(201)
|
76
|
+
# response['Location'] = ""
|
77
|
+
else
|
78
|
+
status(500)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
get '/stylesheets/style.css' do
|
83
|
+
header 'Content-Type' => 'text/css; charset=utf-8'
|
84
|
+
sass :style
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
class Time
|
89
|
+
|
90
|
+
# Rounds up to the 5 min intervals
|
91
|
+
def to_five_minute_grain_format
|
92
|
+
offset = (5-(self.min.to_i%5)) * 60
|
93
|
+
Time.parse((self + offset).strftime("%Y-%m-%d %H:%M"))
|
94
|
+
end
|
95
|
+
|
96
|
+
# Rounds up to the 10 min intervals
|
97
|
+
def to_ten_minute_grain_format
|
98
|
+
offset = (10-(self.min.to_i%10)) * 60
|
99
|
+
Time.parse((self + offset).strftime("%Y-%m-%d %H:%M"))
|
100
|
+
end
|
101
|
+
|
102
|
+
# Rounds up to the 15 min intervals
|
103
|
+
def to_fifteen_minute_grain_format
|
104
|
+
offset = (15-(self.min.to_i%15)) * 60
|
105
|
+
Time.parse((self + offset).strftime("%Y-%m-%d %H:%M"))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Rounds up to the 30 min intervals
|
109
|
+
def to_thirty_minute_grain_format
|
110
|
+
offset = (30-(self.min.to_i%30)) * 60
|
111
|
+
Time.parse((self + offset).strftime("%Y-%m-%d %H:%M"))
|
112
|
+
end
|
113
|
+
|
114
|
+
# Rounds up to the 60 min intervals
|
115
|
+
def to_sixty_minute_grain_format
|
116
|
+
offset = (60-(self.min.to_i%60)) * 60
|
117
|
+
Time.parse((self + offset).strftime("%Y-%m-%d %H:%M"))
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_minute_format
|
121
|
+
self.strftime("%Y-%m-%d %H:%M")
|
122
|
+
end
|
123
|
+
|
124
|
+
def to_sql_format
|
125
|
+
self.strftime("%Y-%m-%dT%H:%M")
|
126
|
+
end
|
127
|
+
end
|
data/views/layout.haml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title dog not god
|
5
|
+
%link{:rel=>'stylesheet', :href=>'/stylesheets/style.css', :type => "text/css"}
|
6
|
+
|
7
|
+
%body
|
8
|
+
#header
|
9
|
+
#content
|
10
|
+
%h1 dog not god
|
11
|
+
=yield
|
12
|
+
#footer
|
13
|
+
%p
|
14
|
+
%a{ :href => "http://github.com/luiscorreadalmeida/dog" } dog not god
|
15
|
+
is released under the
|
16
|
+
%a{ :href => "http://www.gnu.org/licenses/gpl.html" } GPL license
|
17
|
+
|
@@ -0,0 +1,23 @@
|
|
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
|
data/views/main.haml
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
%h2 Summary
|
2
|
+
#summary-section
|
3
|
+
%table{:id => "summary-table", :cellspacing => 0, :cellpading => 0}
|
4
|
+
%tr
|
5
|
+
%th Host
|
6
|
+
%th 5 min average
|
7
|
+
%th 10 min average
|
8
|
+
%th 15 min average
|
9
|
+
%th Last heartbeat
|
10
|
+
-for host in @hosts
|
11
|
+
%tr{:class => "level#{host.status}"}
|
12
|
+
%td= host.hostname
|
13
|
+
%td= host.load_5_min
|
14
|
+
%td= host.load_10_min
|
15
|
+
%td= host.load_15_min
|
16
|
+
%td= "#{host.distance_to_last_heartbeat_in_seconds.to_i} seconds ago" unless host.status == 0
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
%table{:id => "section-table"}
|
21
|
+
%tr
|
22
|
+
-for host in @hosts
|
23
|
+
- 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(",")}"
|
25
|
+
- 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(",")}"
|
27
|
+
%td
|
28
|
+
.section
|
29
|
+
%h2=host.hostname
|
30
|
+
%p== Last heard from on #{host.last_contacted_on}
|
31
|
+
%h4 Load averages for the last 24 hours
|
32
|
+
%img{ :src => "http://chart.apis.google.com/chart?#{params_for_24h}"}
|
33
|
+
%h4 Load averages for the last 6 hours
|
34
|
+
%img{ :src => "http://chart.apis.google.com/chart?#{params_for_6h}"}
|
35
|
+
|
36
|
+
|
37
|
+
|
data/views/style.sass
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
body
|
2
|
+
:margin 0
|
3
|
+
:padding 0
|
4
|
+
:font-family Courier
|
5
|
+
:font-size 1.0em
|
6
|
+
|
7
|
+
a, a:visited
|
8
|
+
:color #AAA
|
9
|
+
|
10
|
+
h1, h2, h3, h4, h5, h6
|
11
|
+
:font-family Georgia, serif
|
12
|
+
:font-weight normal
|
13
|
+
:margin 0px 10px 10px 0px
|
14
|
+
:white-space nowrap
|
15
|
+
|
16
|
+
h1
|
17
|
+
:padding-bottom 10px
|
18
|
+
:margin-bottom 30px
|
19
|
+
:border-bottom double #DDDDDD
|
20
|
+
|
21
|
+
h2
|
22
|
+
:text-decoration underline
|
23
|
+
|
24
|
+
h4
|
25
|
+
:margin 20px 10px 20px 5px
|
26
|
+
:padding 5px
|
27
|
+
:background-color #EFEFEF
|
28
|
+
|
29
|
+
#header
|
30
|
+
:height 10px
|
31
|
+
:background-color #EFEFEF
|
32
|
+
:margin-bottom 20px
|
33
|
+
|
34
|
+
#content
|
35
|
+
:margin 0px 30px 10px 20px
|
36
|
+
|
37
|
+
#summary-section
|
38
|
+
:font-size 0.7em
|
39
|
+
:margin-bottom 30px
|
40
|
+
:padding-bottom 20px
|
41
|
+
:border-bottom 1px solid #DDD
|
42
|
+
|
43
|
+
#summary-table
|
44
|
+
:border-top 1px solid #DDD
|
45
|
+
:border-left 1px solid #DDD
|
46
|
+
|
47
|
+
|
48
|
+
#summary-table tr.level5
|
49
|
+
:background-color #99FF99
|
50
|
+
|
51
|
+
#summary-table tr.level3
|
52
|
+
:background-color #999933
|
53
|
+
|
54
|
+
#summary-table tr.level1
|
55
|
+
:background-color #DD3333
|
56
|
+
|
57
|
+
#summary-table tr.level0
|
58
|
+
:background-color #EFEFEF
|
59
|
+
|
60
|
+
#summary-table th, #summary-table td
|
61
|
+
:border-bottom 1px solid #DDD
|
62
|
+
:border-right 1px solid #DDD
|
63
|
+
|
64
|
+
|
65
|
+
#summary-table th
|
66
|
+
:background-color #EFEFEF
|
67
|
+
:padding-left 15px
|
68
|
+
:padding-right 15px
|
69
|
+
|
70
|
+
#summary-table td
|
71
|
+
:padding-left 5px
|
72
|
+
:padding-right 5px
|
73
|
+
|
74
|
+
#section-table
|
75
|
+
:border 0px
|
76
|
+
|
77
|
+
.section
|
78
|
+
:margin-bottom 20px
|
79
|
+
:margin-left 20px
|
80
|
+
:border-right 1px solid #DDD
|
81
|
+
|
82
|
+
p
|
83
|
+
:font-size 0.7em
|
84
|
+
:margin 0px
|
85
|
+
:padding 0px
|
86
|
+
|
87
|
+
#footer
|
88
|
+
:margin-top 20px
|
89
|
+
:clear both
|
90
|
+
:padding 10px
|
91
|
+
:color #AAA
|
92
|
+
:text-align left
|
93
|
+
:font-family sans-serif
|
94
|
+
:text-align center
|
95
|
+
|
96
|
+
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spoonsix-dognotgod
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Luis Correa d'Almeida
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-28 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.0.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sequel
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.10.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: haml
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.0.7
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: thin
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.0.0
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3-ruby
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.2.4
|
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
|
+
description: dog not god is a performance monitoring tool.
|
76
|
+
email: luis.ca@gmail.com
|
77
|
+
executables:
|
78
|
+
- dognotgod
|
79
|
+
- dognotgod-client
|
80
|
+
extensions: []
|
81
|
+
|
82
|
+
extra_rdoc_files: []
|
83
|
+
|
84
|
+
files:
|
85
|
+
- app/models
|
86
|
+
- app/models/host.rb
|
87
|
+
- app/models/load.rb
|
88
|
+
- config.ru
|
89
|
+
- README
|
90
|
+
- views/layout.haml
|
91
|
+
- views/loads_xml.haml
|
92
|
+
- views/main.haml
|
93
|
+
- views/style.sass
|
94
|
+
- config/thin.yml
|
95
|
+
- server.rb
|
96
|
+
- client.rb
|
97
|
+
has_rdoc: false
|
98
|
+
homepage: http://github.com/spoonsix/dognotgod
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
version:
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
version:
|
116
|
+
requirements: []
|
117
|
+
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 1.2.0
|
120
|
+
signing_key:
|
121
|
+
specification_version: 2
|
122
|
+
summary: dog not god is a performance monitoring tool.
|
123
|
+
test_files: []
|
124
|
+
|