god 0.7.5 → 0.7.6
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/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
|