god 0.7.22 → 0.8.0
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 +20 -0
- data/VERSION.yml +3 -2
- data/god.gemspec +6 -5
- data/lib/god.rb +3 -3
- data/lib/god/cli/command.rb +1 -0
- data/lib/god/contacts/jabber.rb +0 -1
- data/lib/god/contacts/twitter.rb +0 -1
- data/lib/god/diagnostics.rb +12 -12
- data/lib/god/driver.rb +43 -49
- data/lib/god/event_handler.rb +6 -9
- data/lib/god/logger.rb +18 -12
- data/lib/god/task.rb +3 -3
- data/lib/god/watch.rb +2 -1
- data/test/helper.rb +1 -0
- data/test/test_task.rb +3 -3
- data/test/test_watch.rb +8 -8
- metadata +3 -2
data/History.txt
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
== 0.8.0 / 2009-11-30
|
2
|
+
* Minor Enhancements
|
3
|
+
* Rubygems decontamination
|
4
|
+
* Use Monitor instead of Mutex to provide ability to wait with a timeout
|
5
|
+
* Only generate log messages when they're being used
|
6
|
+
* Remove usage of Thread.critical in DriverEventQueue
|
7
|
+
* Update to work with latest bleak-house
|
8
|
+
* Cache some frequent lookups to reduce object creation
|
9
|
+
* Changing the @io.print call in SimpleLogger to not concatenate
|
10
|
+
the formatted results before printing
|
11
|
+
* Bug fixes
|
12
|
+
* Make sure we don't leak hash slots when processes die
|
13
|
+
* Make sure the driver is shutdown on Task#unregister!
|
14
|
+
* Fix memory leak when issuing "god load" successfully
|
15
|
+
* Fix defunct process
|
16
|
+
|
17
|
+
== NOTE
|
18
|
+
At this point I will stop giving credit in the history. Look at the author
|
19
|
+
and committer in the commit for that info.
|
20
|
+
|
1
21
|
== 0.7.22 / 2009-10-29
|
2
22
|
* Minor Enhancements
|
3
23
|
* Save ARGV so we can get access to it later if we want [github.com/eric]
|
data/VERSION.yml
CHANGED
data/god.gemspec
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{god}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tom Preston-Werner"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-11-30}
|
13
13
|
s.default_executable = %q{god}
|
14
14
|
s.description = %q{God is an easy to configure, easy to extend monitoring framework written in Ruby.}
|
15
15
|
s.email = %q{tom@mojombo.com}
|
16
16
|
s.executables = ["god"]
|
17
|
-
s.extensions = ["ext/god/extconf.rb"]
|
17
|
+
s.extensions = ["ext/god/extconf.rb", "ext/god/extconf.rb"]
|
18
18
|
s.extra_rdoc_files = [
|
19
19
|
"README.txt"
|
20
20
|
]
|
@@ -224,3 +224,4 @@ Gem::Specification.new do |s|
|
|
224
224
|
else
|
225
225
|
end
|
226
226
|
end
|
227
|
+
|
data/lib/god.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
2
2
|
|
3
|
-
# rubygems
|
4
|
-
require 'rubygems'
|
5
|
-
|
6
3
|
# core
|
7
4
|
require 'stringio'
|
8
5
|
require 'fileutils'
|
@@ -534,6 +531,9 @@ module God
|
|
534
531
|
watches = self.pending_watches.dup
|
535
532
|
self.pending_watches.clear
|
536
533
|
self.pending_watch_states.clear
|
534
|
+
|
535
|
+
# make sure we quit capturing when we're done
|
536
|
+
LOG.finish_capture
|
537
537
|
rescue Exception => e
|
538
538
|
# don't ever let running_load take down god
|
539
539
|
errors << LOG.finish_capture
|
data/lib/god/cli/command.rb
CHANGED
data/lib/god/contacts/jabber.rb
CHANGED
data/lib/god/contacts/twitter.rb
CHANGED
data/lib/god/diagnostics.rb
CHANGED
@@ -12,26 +12,26 @@ end
|
|
12
12
|
class BleakHouseDiagnostic
|
13
13
|
LOG_FILE = File.join(File.dirname(__FILE__), *%w[.. .. logs bleak.log])
|
14
14
|
|
15
|
-
class << self
|
16
|
-
attr_accessor :logger
|
17
|
-
end
|
18
|
-
|
19
15
|
def self.install
|
20
|
-
require '
|
21
|
-
self.
|
22
|
-
File.delete(LOG_FILE) rescue nil
|
16
|
+
require 'snapshot'
|
17
|
+
self.spin
|
23
18
|
end
|
24
19
|
|
25
|
-
def self.snapshot
|
26
|
-
|
20
|
+
def self.snapshot
|
21
|
+
@count ||= 0
|
22
|
+
filename = "/tmp/god-bleak-%s-%03i.dump" % [Process.pid,@count]
|
23
|
+
STDERR.puts "** BleakHouse: working..."
|
24
|
+
BleakHouse.ext_snapshot(filename, 3)
|
25
|
+
STDERR.puts "** BleakHouse: complete\n** Bleakhouse: Run 'bleak #{filename}' to analyze."
|
26
|
+
@count += 1
|
27
27
|
end
|
28
28
|
|
29
|
-
def self.spin(delay =
|
29
|
+
def self.spin(delay = 60)
|
30
30
|
Thread.new do
|
31
31
|
loop do
|
32
|
-
self.snapshot
|
33
32
|
sleep(delay)
|
33
|
+
self.snapshot
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
end
|
37
|
+
end
|
data/lib/god/driver.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
1
3
|
module God
|
2
4
|
class TimedEvent
|
3
5
|
include Comparable
|
@@ -52,29 +54,24 @@ module God
|
|
52
54
|
@task.send(@name, *@args)
|
53
55
|
end
|
54
56
|
end
|
55
|
-
|
56
|
-
class DriverEventQueue
|
57
|
+
|
58
|
+
class DriverEventQueue
|
57
59
|
def initialize
|
58
60
|
@shutdown = false
|
59
|
-
@waiting = []
|
60
61
|
@events = []
|
61
|
-
@
|
62
|
+
@monitor = Monitor.new
|
63
|
+
@resource = @monitor.new_cond
|
62
64
|
@events.taint
|
63
65
|
self.taint
|
64
66
|
end
|
65
67
|
|
66
|
-
#
|
68
|
+
#
|
67
69
|
# Wake any sleeping threads after setting the sentinel
|
68
|
-
#
|
70
|
+
#
|
69
71
|
def shutdown
|
70
72
|
@shutdown = true
|
71
|
-
|
72
|
-
|
73
|
-
@waiting.each do |t|
|
74
|
-
t.run
|
75
|
-
end
|
76
|
-
ensure
|
77
|
-
Thread.critical = false
|
73
|
+
@monitor.synchronize do
|
74
|
+
@resource.broadcast
|
78
75
|
end
|
79
76
|
end
|
80
77
|
|
@@ -82,47 +79,34 @@ module God
|
|
82
79
|
# Sleep until the queue has something due
|
83
80
|
#
|
84
81
|
def pop
|
85
|
-
|
86
|
-
|
87
|
-
@
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
Thread.critical = false
|
93
|
-
delay = @events.first.at - Time.now
|
94
|
-
sleep delay if delay > 0
|
95
|
-
Thread.critical = true
|
96
|
-
end
|
82
|
+
@monitor.synchronize do
|
83
|
+
if @events.empty?
|
84
|
+
raise ThreadError, "queue empty" if @shutdown
|
85
|
+
@resource.wait
|
86
|
+
else !@events.first.due?
|
87
|
+
delay = @events.first.at - Time.now
|
88
|
+
@resource.wait(delay) if delay > 0
|
97
89
|
end
|
90
|
+
|
98
91
|
@events.shift
|
99
|
-
ensure
|
100
|
-
Thread.critical = false
|
101
92
|
end
|
102
93
|
end
|
103
94
|
|
104
95
|
alias shift pop
|
105
96
|
alias deq pop
|
106
97
|
|
107
|
-
#
|
108
|
-
# Add an event to the queue, wake any waiters if what we added needs to
|
98
|
+
#
|
99
|
+
# Add an event to the queue, wake any waiters if what we added needs to
|
109
100
|
# happen sooner than the next pending event
|
110
101
|
#
|
111
102
|
def push(event)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
retry
|
120
|
-
ensure
|
121
|
-
Thread.critical = false
|
122
|
-
end
|
123
|
-
begin
|
124
|
-
t.run if t
|
125
|
-
rescue ThreadError
|
103
|
+
@monitor.synchronize do
|
104
|
+
@events << event
|
105
|
+
@events.sort!
|
106
|
+
|
107
|
+
# If we've sorted the events and found the one we're adding is at
|
108
|
+
# the front, it will likely need to run before the next due date
|
109
|
+
@resource.signal if @events.first == event
|
126
110
|
end
|
127
111
|
end
|
128
112
|
|
@@ -130,7 +114,7 @@ module God
|
|
130
114
|
alias enq push
|
131
115
|
|
132
116
|
def empty?
|
133
|
-
@
|
117
|
+
@events.empty?
|
134
118
|
end
|
135
119
|
|
136
120
|
def clear
|
@@ -142,16 +126,12 @@ module God
|
|
142
126
|
end
|
143
127
|
|
144
128
|
alias size length
|
145
|
-
|
146
|
-
def num_waiting
|
147
|
-
@waiting.size
|
148
|
-
end
|
149
129
|
end
|
150
130
|
|
151
131
|
|
152
132
|
class Driver
|
153
133
|
attr_reader :thread
|
154
|
-
|
134
|
+
|
155
135
|
# Instantiate a new Driver and start the scheduler loop to handle events
|
156
136
|
# +task+ is the Task this Driver belongs to
|
157
137
|
#
|
@@ -176,12 +156,26 @@ module God
|
|
176
156
|
end
|
177
157
|
end
|
178
158
|
|
159
|
+
# Check if we're in the driver context
|
160
|
+
#
|
161
|
+
# Returns true if in driver thread
|
162
|
+
def in_driver_context?
|
163
|
+
Thread.current == @thread
|
164
|
+
end
|
165
|
+
|
179
166
|
# Clear all events for this Driver
|
180
167
|
#
|
181
168
|
# Returns nothing
|
182
169
|
def clear_events
|
183
170
|
@events.clear
|
184
171
|
end
|
172
|
+
|
173
|
+
# Shutdown the DriverEventQueue threads
|
174
|
+
#
|
175
|
+
# Returns nothing
|
176
|
+
def shutdown
|
177
|
+
@events.shutdown
|
178
|
+
end
|
185
179
|
|
186
180
|
# Queue an asynchronous message
|
187
181
|
# +name+ is the Symbol name of the operation
|
data/lib/god/event_handler.rb
CHANGED
@@ -38,16 +38,12 @@ module God
|
|
38
38
|
@@handler.register_process(pid, @@actions[pid].keys)
|
39
39
|
end
|
40
40
|
|
41
|
-
def self.deregister(pid, event
|
41
|
+
def self.deregister(pid, event)
|
42
42
|
if watching_pid? pid
|
43
43
|
running = ::Process.kill(0, pid.to_i) rescue false
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
@@actions[pid].delete(event)
|
49
|
-
@@handler.register_process(pid, @@actions[pid].keys) if running
|
50
|
-
end
|
44
|
+
@@actions[pid].delete(event)
|
45
|
+
@@handler.register_process(pid, @@actions[pid].keys) if running
|
46
|
+
@@actions.delete(pid) if @@actions[pid].empty?
|
51
47
|
end
|
52
48
|
end
|
53
49
|
|
@@ -92,6 +88,7 @@ module God
|
|
92
88
|
end
|
93
89
|
|
94
90
|
::Process.kill('KILL', pid)
|
91
|
+
::Process.waitpid(pid)
|
95
92
|
|
96
93
|
sleep(0.1)
|
97
94
|
|
@@ -108,4 +105,4 @@ module God
|
|
108
105
|
end
|
109
106
|
|
110
107
|
end
|
111
|
-
end
|
108
|
+
end
|
data/lib/god/logger.rb
CHANGED
@@ -58,21 +58,27 @@ module God
|
|
58
58
|
def log(watch, level, text)
|
59
59
|
# initialize watch log if necessary
|
60
60
|
self.logs[watch.name] ||= Timeline.new(God::LOG_BUFFER_SIZE_DEFAULT) if watch
|
61
|
-
|
61
|
+
|
62
62
|
# push onto capture and timeline for the given watch
|
63
|
-
@
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
if @capture || (watch && (Time.now - @spool < 2))
|
64
|
+
@mutex.synchronize do
|
65
|
+
@templogio.truncate(0)
|
66
|
+
@templogio.rewind
|
67
|
+
@templog.send(level, text)
|
68
|
+
|
69
|
+
message = @templogio.string.dup
|
70
|
+
|
71
|
+
if @capture
|
72
|
+
@capture.puts(message)
|
73
|
+
else
|
74
|
+
self.logs[watch.name] << [Time.now, message]
|
75
|
+
end
|
70
76
|
end
|
71
77
|
end
|
72
|
-
|
78
|
+
|
73
79
|
# send to regular logger
|
74
|
-
self.send(level, text
|
75
|
-
|
80
|
+
self.send(level, text)
|
81
|
+
|
76
82
|
# send to syslog
|
77
83
|
Syslog.send(SYSLOG_EQUIVALENTS[level], text) if Logger.syslog
|
78
84
|
end
|
@@ -114,7 +120,7 @@ module God
|
|
114
120
|
# Returns String
|
115
121
|
def finish_capture
|
116
122
|
@mutex.synchronize do
|
117
|
-
cap = @capture.string
|
123
|
+
cap = @capture.string if @capture
|
118
124
|
@capture = nil
|
119
125
|
cap
|
120
126
|
end
|
data/lib/god/task.rb
CHANGED
@@ -144,7 +144,7 @@ module God
|
|
144
144
|
#
|
145
145
|
# Returns Task (self)
|
146
146
|
def move(to_state)
|
147
|
-
if
|
147
|
+
if !self.driver.in_driver_context?
|
148
148
|
# called from outside Driver
|
149
149
|
|
150
150
|
# send an async message to Driver
|
@@ -235,7 +235,7 @@ module God
|
|
235
235
|
#
|
236
236
|
# Returns Task (self)
|
237
237
|
def action(a, c = nil)
|
238
|
-
if
|
238
|
+
if !self.driver.in_driver_context?
|
239
239
|
# called from outside Driver
|
240
240
|
|
241
241
|
# send an async message to Driver
|
@@ -299,7 +299,7 @@ module God
|
|
299
299
|
end
|
300
300
|
|
301
301
|
def unregister!
|
302
|
-
|
302
|
+
driver.shutdown
|
303
303
|
end
|
304
304
|
|
305
305
|
###########################################################################
|
data/lib/god/watch.rb
CHANGED
@@ -104,7 +104,7 @@ module God
|
|
104
104
|
###########################################################################
|
105
105
|
|
106
106
|
def action(a, c = nil)
|
107
|
-
if
|
107
|
+
if !self.driver.in_driver_context?
|
108
108
|
# called from outside Driver
|
109
109
|
|
110
110
|
# send an async message to Driver
|
@@ -177,6 +177,7 @@ module God
|
|
177
177
|
|
178
178
|
def unregister!
|
179
179
|
God.registry.remove(@process)
|
180
|
+
super
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
data/test/helper.rb
CHANGED
data/test/test_task.rb
CHANGED
@@ -61,20 +61,20 @@ class TestTask < Test::Unit::TestCase
|
|
61
61
|
|
62
62
|
def test_action_should_send_string_commands_to_system
|
63
63
|
@task.foo = 'foo'
|
64
|
-
|
64
|
+
@task.driver.stubs(:in_driver_context?).returns(true)
|
65
65
|
@task.expects(:system).with('foo')
|
66
66
|
@task.action(:foo, nil)
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_action_should_call_lambda_commands
|
70
70
|
@task.foo = lambda { }
|
71
|
-
|
71
|
+
@task.driver.stubs(:in_driver_context?).returns(true)
|
72
72
|
@task.foo.expects(:call)
|
73
73
|
@task.action(:foo, nil)
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
|
77
|
-
|
77
|
+
@task.driver.stubs(:in_driver_context?).returns(true)
|
78
78
|
assert_raise NotImplementedError do
|
79
79
|
@task.foo = 7
|
80
80
|
@task.action(:foo, nil)
|
data/test/test_watch.rb
CHANGED
@@ -126,7 +126,7 @@ class TestWatch < Test::Unit::TestCase
|
|
126
126
|
# move
|
127
127
|
|
128
128
|
def test_move_should_not_clean_up_if_from_state_is_nil
|
129
|
-
|
129
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
130
130
|
@watch.driver.expects(:message).never
|
131
131
|
|
132
132
|
metric = nil
|
@@ -147,7 +147,7 @@ class TestWatch < Test::Unit::TestCase
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def test_move_should_clean_up_from_state_if_not_nil
|
150
|
-
|
150
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
151
151
|
@watch.driver.expects(:message).never
|
152
152
|
|
153
153
|
metric = nil
|
@@ -170,7 +170,7 @@ class TestWatch < Test::Unit::TestCase
|
|
170
170
|
end
|
171
171
|
|
172
172
|
def test_move_should_call_action
|
173
|
-
|
173
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
174
174
|
@watch.driver.expects(:message).never
|
175
175
|
|
176
176
|
@watch.expects(:action).with(:start)
|
@@ -179,7 +179,7 @@ class TestWatch < Test::Unit::TestCase
|
|
179
179
|
end
|
180
180
|
|
181
181
|
def test_move_should_move_to_up_state_if_no_start_or_restart_metric
|
182
|
-
|
182
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
183
183
|
@watch.driver.expects(:message).never
|
184
184
|
|
185
185
|
[:start, :restart].each do |state|
|
@@ -190,7 +190,7 @@ class TestWatch < Test::Unit::TestCase
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def test_move_should_enable_destination_metric
|
193
|
-
|
193
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
194
194
|
@watch.driver.expects(:message).never
|
195
195
|
|
196
196
|
metric = nil
|
@@ -213,7 +213,7 @@ class TestWatch < Test::Unit::TestCase
|
|
213
213
|
# action
|
214
214
|
|
215
215
|
def test_action_should_pass_start_and_stop_actions_to_call_action
|
216
|
-
|
216
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
217
217
|
@watch.driver.expects(:message).never
|
218
218
|
|
219
219
|
c = Conditions::FakePollCondition.new
|
@@ -224,7 +224,7 @@ class TestWatch < Test::Unit::TestCase
|
|
224
224
|
end
|
225
225
|
|
226
226
|
def test_action_should_do_stop_then_start_if_no_restart_command
|
227
|
-
|
227
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
228
228
|
@watch.driver.expects(:message).never
|
229
229
|
|
230
230
|
c = Conditions::FakePollCondition.new
|
@@ -234,7 +234,7 @@ class TestWatch < Test::Unit::TestCase
|
|
234
234
|
end
|
235
235
|
|
236
236
|
def test_action_should_restart_to_call_action_if_present
|
237
|
-
|
237
|
+
@watch.driver.stubs(:in_driver_context?).returns(true)
|
238
238
|
@watch.driver.expects(:message).never
|
239
239
|
|
240
240
|
@watch.restart = lambda { }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: god
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Preston-Werner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-30 00:00:00 -08:00
|
13
13
|
default_executable: god
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -19,6 +19,7 @@ executables:
|
|
19
19
|
- god
|
20
20
|
extensions:
|
21
21
|
- ext/god/extconf.rb
|
22
|
+
- ext/god/extconf.rb
|
22
23
|
extra_rdoc_files:
|
23
24
|
- README.txt
|
24
25
|
files:
|