god 0.7.5 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +3 -0
- data/Rakefile +1 -1
- data/ext/god/kqueue_handler.c +1 -0
- data/lib/god.rb +5 -1
- data/lib/god/cli/run.rb +80 -94
- data/lib/god/system/portable_poller.rb +42 -0
- data/lib/god/system/process.rb +10 -23
- data/lib/god/system/slash_proc_poller.rb +62 -0
- data/test/test_system_portable_poller.rb +17 -0
- data/test/test_system_process.rb +0 -12
- metadata +6 -2
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.7.6 / 2008-05-13
|
2
|
+
* Major Enhancements
|
3
|
+
* Implement System::Process methods for Linux based on /proc [Kevin Clark]
|
4
|
+
* Minor Enhancements
|
5
|
+
* Allowing directories to be loaded at start [Bert Goethals]
|
6
|
+
* Bug Fixes
|
7
|
+
* Don't leak events on error in the kqueue handler [Kevin Clark]
|
8
|
+
|
1
9
|
== 0.7.5 / 2008-02-21
|
2
10
|
* Bug Fixes
|
3
11
|
* Remove Ruby's Logger and replace with custom SimpleLogger to stop threaded leak
|
data/Manifest.txt
CHANGED
@@ -48,7 +48,9 @@ lib/god/registry.rb
|
|
48
48
|
lib/god/simple_logger.rb
|
49
49
|
lib/god/socket.rb
|
50
50
|
lib/god/sugar.rb
|
51
|
+
lib/god/system/portable_poller.rb
|
51
52
|
lib/god/system/process.rb
|
53
|
+
lib/god/system/slash_proc_poller.rb
|
52
54
|
lib/god/task.rb
|
53
55
|
lib/god/timeline.rb
|
54
56
|
lib/god/trigger.rb
|
@@ -96,6 +98,7 @@ test/test_process.rb
|
|
96
98
|
test/test_registry.rb
|
97
99
|
test/test_socket.rb
|
98
100
|
test/test_sugar.rb
|
101
|
+
test/test_system_portable_poller.rb
|
99
102
|
test/test_system_process.rb
|
100
103
|
test/test_task.rb
|
101
104
|
test/test_timeline.rb
|
data/Rakefile
CHANGED
data/ext/god/kqueue_handler.c
CHANGED
data/lib/god.rb
CHANGED
@@ -20,7 +20,11 @@ end
|
|
20
20
|
require 'god/errors'
|
21
21
|
require 'god/simple_logger'
|
22
22
|
require 'god/logger'
|
23
|
+
|
23
24
|
require 'god/system/process'
|
25
|
+
require 'god/system/portable_poller'
|
26
|
+
require 'god/system/slash_proc_poller'
|
27
|
+
|
24
28
|
require 'god/dependency_graph'
|
25
29
|
require 'god/timeline'
|
26
30
|
require 'god/configurable'
|
@@ -129,7 +133,7 @@ class Module
|
|
129
133
|
end
|
130
134
|
|
131
135
|
module God
|
132
|
-
VERSION = '0.7.
|
136
|
+
VERSION = '0.7.6'
|
133
137
|
|
134
138
|
LOG_BUFFER_SIZE_DEFAULT = 100
|
135
139
|
PID_FILE_DIRECTORY_DEFAULTS = ['/var/run/god', '~/.god/pids']
|
data/lib/god/cli/run.rb
CHANGED
@@ -33,6 +33,60 @@ module God
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
def default_run
|
37
|
+
# start attached pid watcher if necessary
|
38
|
+
if @options[:attach]
|
39
|
+
self.attach
|
40
|
+
end
|
41
|
+
|
42
|
+
if @options[:port]
|
43
|
+
God.port = @options[:port]
|
44
|
+
end
|
45
|
+
|
46
|
+
if @options[:events]
|
47
|
+
God::EventHandler.load
|
48
|
+
end
|
49
|
+
|
50
|
+
# set log level, defaults to WARN
|
51
|
+
if @options[:log_level]
|
52
|
+
God.log_level = @options[:log_level]
|
53
|
+
else
|
54
|
+
God.log_level = @options[:daemonize] ? :warn : :info
|
55
|
+
end
|
56
|
+
|
57
|
+
if @options[:config]
|
58
|
+
unless File.exist?(@options[:config])
|
59
|
+
abort "File not found: #{@options[:config]}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# start the event handler
|
63
|
+
God::EventHandler.start if God::EventHandler.loaded?
|
64
|
+
|
65
|
+
load_config @options[:config]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_in_front
|
70
|
+
require 'god'
|
71
|
+
|
72
|
+
if @options[:bleakhouse]
|
73
|
+
BleakHouseDiagnostic.install
|
74
|
+
end
|
75
|
+
|
76
|
+
default_run
|
77
|
+
|
78
|
+
if @options[:log]
|
79
|
+
log_file = File.expand_path(@options[:log])
|
80
|
+
puts "Sending output to log file: #{log_file}"
|
81
|
+
|
82
|
+
# reset file descriptors
|
83
|
+
STDIN.reopen "/dev/null"
|
84
|
+
STDOUT.reopen(log_file, "a")
|
85
|
+
STDERR.reopen STDOUT
|
86
|
+
STDOUT.sync = true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
36
90
|
def run_daemonized
|
37
91
|
# trap and ignore SIGHUP
|
38
92
|
Signal.trap('HUP') {}
|
@@ -49,18 +103,8 @@ module God
|
|
49
103
|
STDERR.reopen STDOUT
|
50
104
|
STDOUT.sync = true
|
51
105
|
|
52
|
-
# start attached pid watcher if necessary
|
53
|
-
if @options[:attach]
|
54
|
-
self.attach
|
55
|
-
end
|
56
|
-
|
57
|
-
# set port if requested
|
58
|
-
if @options[:port]
|
59
|
-
God.port = @options[:port]
|
60
|
-
end
|
61
|
-
|
62
106
|
# set pid if requested
|
63
|
-
if @options[:pid]
|
107
|
+
if @options[:pid] # and as deamon
|
64
108
|
God.pid = @options[:pid]
|
65
109
|
end
|
66
110
|
|
@@ -68,9 +112,7 @@ module God
|
|
68
112
|
Logger.syslog = false
|
69
113
|
end
|
70
114
|
|
71
|
-
|
72
|
-
God::EventHandler.load
|
73
|
-
end
|
115
|
+
default_run
|
74
116
|
|
75
117
|
unless God::EventHandler.loaded?
|
76
118
|
puts
|
@@ -83,34 +125,6 @@ module God
|
|
83
125
|
puts
|
84
126
|
end
|
85
127
|
|
86
|
-
# load config
|
87
|
-
if @options[:config]
|
88
|
-
# set log level, defaults to WARN
|
89
|
-
if @options[:log_level]
|
90
|
-
God.log_level = @options[:log_level]
|
91
|
-
else
|
92
|
-
God.log_level = :warn
|
93
|
-
end
|
94
|
-
|
95
|
-
unless File.exist?(@options[:config])
|
96
|
-
abort "File not found: #{@options[:config]}"
|
97
|
-
end
|
98
|
-
|
99
|
-
# start the event handler
|
100
|
-
God::EventHandler.start if God::EventHandler.loaded?
|
101
|
-
|
102
|
-
begin
|
103
|
-
load File.expand_path(@options[:config])
|
104
|
-
rescue Exception => e
|
105
|
-
if e.instance_of?(SystemExit)
|
106
|
-
raise
|
107
|
-
else
|
108
|
-
puts e.message
|
109
|
-
puts e.backtrace.join("\n")
|
110
|
-
abort "There was an error in your configuration file (see above)"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
128
|
rescue => e
|
115
129
|
puts e.message
|
116
130
|
puts e.backtrace.join("\n")
|
@@ -127,63 +141,35 @@ module God
|
|
127
141
|
exit
|
128
142
|
end
|
129
143
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
# start attached pid watcher if necessary
|
138
|
-
if @options[:attach]
|
139
|
-
self.attach
|
140
|
-
end
|
141
|
-
|
142
|
-
if @options[:port]
|
143
|
-
God.port = @options[:port]
|
144
|
-
end
|
145
|
-
|
146
|
-
if @options[:events]
|
147
|
-
God::EventHandler.load
|
148
|
-
end
|
149
|
-
|
150
|
-
# set log level if requested
|
151
|
-
if @options[:log_level]
|
152
|
-
God.log_level = @options[:log_level]
|
153
|
-
end
|
154
|
-
|
155
|
-
if @options[:config]
|
156
|
-
unless File.exist?(@options[:config])
|
157
|
-
abort "File not found: #{@options[:config]}"
|
144
|
+
def load_config(config)
|
145
|
+
if File.directory? config
|
146
|
+
files_loaded = false
|
147
|
+
Dir[File.expand_path('**/*.god', config)].each do |god_file|
|
148
|
+
files_loaded ||= load_god_file(File.expand_path(god_file))
|
158
149
|
end
|
159
|
-
|
160
|
-
|
161
|
-
God::EventHandler.start if God::EventHandler.loaded?
|
162
|
-
|
163
|
-
begin
|
164
|
-
load File.expand_path(@options[:config])
|
165
|
-
rescue Exception => e
|
166
|
-
if e.instance_of?(SystemExit)
|
167
|
-
raise
|
168
|
-
else
|
169
|
-
puts e.message
|
170
|
-
puts e.backtrace.join("\n")
|
171
|
-
abort "There was an error in your configuration file (see above)"
|
172
|
-
end
|
150
|
+
unless files_loaded
|
151
|
+
abort "No files could be loaded"
|
173
152
|
end
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
puts "Sending output to log file: #{log_file}"
|
178
|
-
|
179
|
-
# reset file descriptors
|
180
|
-
STDIN.reopen "/dev/null"
|
181
|
-
STDOUT.reopen(log_file, "a")
|
182
|
-
STDERR.reopen STDOUT
|
183
|
-
STDOUT.sync = true
|
153
|
+
else
|
154
|
+
unless load_god_file(File.expand_path(config))
|
155
|
+
abort "File could not be loaded"
|
184
156
|
end
|
185
157
|
end
|
186
158
|
end
|
159
|
+
|
160
|
+
def load_god_file(god_file)
|
161
|
+
load File.expand_path(god_file)
|
162
|
+
rescue Exception => e
|
163
|
+
if e.instance_of?(SystemExit)
|
164
|
+
raise
|
165
|
+
else
|
166
|
+
puts "There was an error in #{god_file}"
|
167
|
+
puts "\t" + e.message
|
168
|
+
puts "\t" + e.backtrace.join("\n\t")
|
169
|
+
return false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
187
173
|
end # Run
|
188
174
|
|
189
175
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module God
|
2
|
+
module System
|
3
|
+
class PortablePoller
|
4
|
+
def initialize(pid)
|
5
|
+
@pid = pid
|
6
|
+
end
|
7
|
+
# Memory usage in kilobytes (resident set size)
|
8
|
+
def memory
|
9
|
+
ps_int('rss')
|
10
|
+
end
|
11
|
+
|
12
|
+
# Percentage memory usage
|
13
|
+
def percent_memory
|
14
|
+
ps_float('%mem')
|
15
|
+
end
|
16
|
+
|
17
|
+
# Percentage CPU usage
|
18
|
+
def percent_cpu
|
19
|
+
ps_float('%cpu')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def ps_int(keyword)
|
25
|
+
`ps -o #{keyword}= -p #{@pid}`.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def ps_float(keyword)
|
29
|
+
`ps -o #{keyword}= -p #{@pid}`.to_f
|
30
|
+
end
|
31
|
+
|
32
|
+
def ps_string(keyword)
|
33
|
+
`ps -o #{keyword}= -p #{@pid}`.strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def time_string_to_seconds(text)
|
37
|
+
_, minutes, seconds, useconds = *text.match(/(\d+):(\d{2}).(\d{2})/)
|
38
|
+
(minutes.to_i * 60) + seconds.to_i
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/god/system/process.rb
CHANGED
@@ -4,6 +4,7 @@ module God
|
|
4
4
|
class Process
|
5
5
|
def initialize(pid)
|
6
6
|
@pid = pid.to_i
|
7
|
+
@poller = fetch_system_poller.new(@pid)
|
7
8
|
end
|
8
9
|
|
9
10
|
# Return true if this process is running, false otherwise
|
@@ -13,41 +14,27 @@ module God
|
|
13
14
|
|
14
15
|
# Memory usage in kilobytes (resident set size)
|
15
16
|
def memory
|
16
|
-
|
17
|
+
@poller.memory
|
17
18
|
end
|
18
19
|
|
19
20
|
# Percentage memory usage
|
20
21
|
def percent_memory
|
21
|
-
|
22
|
+
@poller.percent_memory
|
22
23
|
end
|
23
24
|
|
24
25
|
# Percentage CPU usage
|
25
26
|
def percent_cpu
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
# Seconds of CPU time (accumulated cpu time, user + system)
|
30
|
-
def cpu_time
|
31
|
-
time_string_to_seconds(ps_string('time'))
|
27
|
+
@poller.percent_cpu
|
32
28
|
end
|
33
29
|
|
34
30
|
private
|
35
31
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
def ps_string(keyword)
|
45
|
-
`ps -o #{keyword}= -p #{@pid}`.strip
|
46
|
-
end
|
47
|
-
|
48
|
-
def time_string_to_seconds(text)
|
49
|
-
_, minutes, seconds, useconds = *text.match(/(\d+):(\d{2}).(\d{2})/)
|
50
|
-
(minutes.to_i * 60) + seconds.to_i
|
32
|
+
def fetch_system_poller
|
33
|
+
if test(?d, '/proc')
|
34
|
+
SlashProcPoller
|
35
|
+
else
|
36
|
+
PortablePoller
|
37
|
+
end
|
51
38
|
end
|
52
39
|
end
|
53
40
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module God
|
2
|
+
module System
|
3
|
+
class SlashProcPoller < PortablePoller
|
4
|
+
@@kb_per_page = 4 # TODO: Need to make this portable
|
5
|
+
@@hertz = 100
|
6
|
+
@@total_mem = nil
|
7
|
+
|
8
|
+
def initialize(pid)
|
9
|
+
super(pid)
|
10
|
+
|
11
|
+
unless @@total_mem # in K
|
12
|
+
File.open("/proc/meminfo") do |f|
|
13
|
+
@@total_mem = f.gets.split[1]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def memory
|
19
|
+
stat[:rss].to_i * @@kb_per_page
|
20
|
+
end
|
21
|
+
|
22
|
+
def percent_memory
|
23
|
+
(memory / @@total_mem.to_f) * 100
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: Change this to calculate the wma instead
|
27
|
+
def percent_cpu
|
28
|
+
stats = stat
|
29
|
+
total_time = stats[:utime].to_i + stats[:stime].to_i # in jiffies
|
30
|
+
seconds = uptime - stats[:starttime].to_i / @@hertz
|
31
|
+
if seconds == 0
|
32
|
+
0
|
33
|
+
else
|
34
|
+
((total_time * 1000 / @@hertz) / seconds) / 10
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# in seconds
|
41
|
+
def uptime
|
42
|
+
File.read('/proc/uptime').split[0].to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
def stat
|
46
|
+
stats = {}
|
47
|
+
stats[:pid], stats[:comm], stats[:state], stats[:ppid], stats[:pgrp],
|
48
|
+
stats[:session], stats[:tty_nr], stats[:tpgid], stats[:flags],
|
49
|
+
stats[:minflt], stats[:cminflt], stats[:majflt], stats[:cmajflt],
|
50
|
+
stats[:utime], stats[:stime], stats[:cutime], stats[:cstime],
|
51
|
+
stats[:priority], stats[:nice], _, stats[:itrealvalue],
|
52
|
+
stats[:starttime], stats[:vsize], stats[:rss], stats[:rlim],
|
53
|
+
stats[:startcode], stats[:endcode], stats[:startstack], stats[:kstkesp],
|
54
|
+
stats[:kstkeip], stats[:signal], stats[:blocked], stats[:sigignore],
|
55
|
+
stats[:sigcatch], stats[:wchan], stats[:nswap], stats[:cnswap],
|
56
|
+
stats[:exit_signal], stats[:processor], stats[:rt_priority],
|
57
|
+
stats[:policy] = File.read("/proc/#{@pid}/stat").split
|
58
|
+
stats
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestSystemPortablePoller < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
pid = Process.pid
|
6
|
+
@process = System::PortablePoller.new(pid)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_time_string_to_seconds
|
10
|
+
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:00')
|
11
|
+
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:55')
|
12
|
+
assert_equal 27, @process.bypass.time_string_to_seconds('0:27:32')
|
13
|
+
assert_equal 75, @process.bypass.time_string_to_seconds('1:15:13')
|
14
|
+
assert_equal 735, @process.bypass.time_string_to_seconds('12:15:13')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/test/test_system_process.rb
CHANGED
@@ -26,17 +26,5 @@ class TestSystemProcess < Test::Unit::TestCase
|
|
26
26
|
def test_percent_cpu
|
27
27
|
assert_kind_of Float, @process.percent_cpu
|
28
28
|
end
|
29
|
-
|
30
|
-
def test_cpu_time
|
31
|
-
assert_kind_of Integer, @process.cpu_time
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_time_string_to_seconds
|
35
|
-
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:00')
|
36
|
-
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:55')
|
37
|
-
assert_equal 27, @process.bypass.time_string_to_seconds('0:27:32')
|
38
|
-
assert_equal 75, @process.bypass.time_string_to_seconds('1:15:13')
|
39
|
-
assert_equal 735, @process.bypass.time_string_to_seconds('12:15:13')
|
40
|
-
end
|
41
29
|
end
|
42
30
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: god
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.7.
|
7
|
-
date: 2008-05-
|
6
|
+
version: 0.7.6
|
7
|
+
date: 2008-05-21 00:00:00 -07:00
|
8
8
|
summary: Like monit, only awesome
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -80,7 +80,9 @@ files:
|
|
80
80
|
- lib/god/simple_logger.rb
|
81
81
|
- lib/god/socket.rb
|
82
82
|
- lib/god/sugar.rb
|
83
|
+
- lib/god/system/portable_poller.rb
|
83
84
|
- lib/god/system/process.rb
|
85
|
+
- lib/god/system/slash_proc_poller.rb
|
84
86
|
- lib/god/task.rb
|
85
87
|
- lib/god/timeline.rb
|
86
88
|
- lib/god/trigger.rb
|
@@ -128,6 +130,7 @@ files:
|
|
128
130
|
- test/test_registry.rb
|
129
131
|
- test/test_socket.rb
|
130
132
|
- test/test_sugar.rb
|
133
|
+
- test/test_system_portable_poller.rb
|
131
134
|
- test/test_system_process.rb
|
132
135
|
- test/test_task.rb
|
133
136
|
- test/test_timeline.rb
|
@@ -152,6 +155,7 @@ test_files:
|
|
152
155
|
- test/test_registry.rb
|
153
156
|
- test/test_socket.rb
|
154
157
|
- test/test_sugar.rb
|
158
|
+
- test/test_system_portable_poller.rb
|
155
159
|
- test/test_system_process.rb
|
156
160
|
- test/test_task.rb
|
157
161
|
- test/test_timeline.rb
|