resurrected_god 0.14.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +559 -0
- data/README.md +9 -4
- data/bin/god +26 -28
- data/ext/god/extconf.rb +9 -9
- data/lib/god/behavior.rb +3 -5
- data/lib/god/behaviors/clean_pid_file.rb +4 -6
- data/lib/god/behaviors/clean_unix_socket.rb +4 -6
- data/lib/god/behaviors/notify_when_flapping.rb +13 -15
- data/lib/god/cli/command.rb +109 -89
- data/lib/god/cli/run.rb +51 -75
- data/lib/god/cli/version.rb +2 -4
- data/lib/god/condition.rb +12 -14
- data/lib/god/conditions/always.rb +3 -2
- data/lib/god/conditions/complex.rb +23 -24
- data/lib/god/conditions/cpu_usage.rb +12 -16
- data/lib/god/conditions/degrading_lambda.rb +15 -19
- data/lib/god/conditions/disk_usage.rb +7 -8
- data/lib/god/conditions/file_mtime.rb +3 -7
- data/lib/god/conditions/file_touched.rb +4 -5
- data/lib/god/conditions/flapping.rb +57 -62
- data/lib/god/conditions/http_response_code.rb +27 -32
- data/lib/god/conditions/lambda.rb +3 -5
- data/lib/god/conditions/memory_usage.rb +12 -16
- data/lib/god/conditions/process_exits.rb +12 -12
- data/lib/god/conditions/process_running.rb +8 -10
- data/lib/god/conditions/socket_responding.rb +23 -28
- data/lib/god/conditions/tries.rb +12 -14
- data/lib/god/configurable.rb +7 -10
- data/lib/god/contact.rb +41 -52
- data/lib/god/contacts/airbrake.rb +10 -12
- data/lib/god/contacts/campfire.rb +18 -20
- data/lib/god/contacts/email.rb +27 -28
- data/lib/god/contacts/prowl.rb +16 -17
- data/lib/god/contacts/scout.rb +2 -5
- data/lib/god/contacts/sensu.rb +15 -11
- data/lib/god/contacts/slack.rb +23 -33
- data/lib/god/contacts/statsd.rb +8 -8
- data/lib/god/contacts/twitter.rb +2 -2
- data/lib/god/contacts/webhook.rb +21 -24
- data/lib/god/driver.rb +12 -18
- data/lib/god/errors.rb +0 -2
- data/lib/god/event_handler.rb +40 -49
- data/lib/god/event_handlers/dummy_handler.rb +1 -1
- data/lib/god/event_handlers/kqueue_handler.rb +2 -2
- data/lib/god/event_handlers/netlink_handler.rb +1 -1
- data/lib/god/logger.rb +5 -13
- data/lib/god/metric.rb +13 -15
- data/lib/god/process.rb +93 -98
- data/lib/god/simple_logger.rb +13 -15
- data/lib/god/socket.rb +21 -23
- data/lib/god/sugar.rb +8 -8
- data/lib/god/sys_logger.rb +6 -8
- data/lib/god/system/portable_poller.rb +1 -9
- data/lib/god/system/process.rb +4 -6
- data/lib/god/system/slash_proc_poller.rb +17 -19
- data/lib/god/task.rb +110 -136
- data/lib/god/timeline.rb +2 -4
- data/lib/god/trigger.rb +7 -11
- data/lib/god/version.rb +1 -1
- data/lib/god/watch.rb +51 -57
- data/lib/god.rb +122 -148
- metadata +17 -370
- data/Announce.txt +0 -135
- data/Gemfile +0 -5
- data/Rakefile +0 -129
- data/doc/god.asciidoc +0 -1592
- data/doc/intro.asciidoc +0 -20
- data/ext/god/.gitignore +0 -5
- data/lib/god/compat19.rb +0 -33
- data/lib/god/contacts/hipchat.rb +0 -117
- data/lib/god/contacts/jabber.rb +0 -75
- data/test/configs/child_events/child_events.god +0 -44
- data/test/configs/child_events/simple_server.rb +0 -3
- data/test/configs/child_polls/child_polls.god +0 -37
- data/test/configs/child_polls/simple_server.rb +0 -12
- data/test/configs/complex/complex.god +0 -59
- data/test/configs/complex/simple_server.rb +0 -3
- data/test/configs/contact/contact.god +0 -118
- data/test/configs/contact/simple_server.rb +0 -3
- data/test/configs/daemon_events/daemon_events.god +0 -37
- data/test/configs/daemon_events/simple_server.rb +0 -8
- data/test/configs/daemon_events/simple_server_stop.rb +0 -11
- data/test/configs/daemon_polls/daemon_polls.god +0 -17
- data/test/configs/daemon_polls/simple_server.rb +0 -6
- data/test/configs/degrading_lambda/degrading_lambda.god +0 -31
- data/test/configs/degrading_lambda/tcp_server.rb +0 -15
- data/test/configs/keepalive/keepalive.god +0 -9
- data/test/configs/keepalive/keepalive.rb +0 -12
- data/test/configs/lifecycle/lifecycle.god +0 -25
- data/test/configs/matias/matias.god +0 -50
- data/test/configs/real.rb +0 -59
- data/test/configs/running_load/running_load.god +0 -16
- data/test/configs/stop_options/simple_server.rb +0 -12
- data/test/configs/stop_options/stop_options.god +0 -39
- data/test/configs/stress/simple_server.rb +0 -3
- data/test/configs/stress/stress.god +0 -15
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +0 -26
- data/test/configs/test.rb +0 -61
- data/test/configs/usr1_trapper.rb +0 -10
- data/test/helper.rb +0 -172
- data/test/suite.rb +0 -6
- data/test/test_airbrake.rb +0 -14
- data/test/test_behavior.rb +0 -18
- data/test/test_campfire.rb +0 -22
- data/test/test_condition.rb +0 -52
- data/test/test_conditions_disk_usage.rb +0 -50
- data/test/test_conditions_http_response_code.rb +0 -109
- data/test/test_conditions_process_running.rb +0 -40
- data/test/test_conditions_socket_responding.rb +0 -176
- data/test/test_conditions_tries.rb +0 -67
- data/test/test_contact.rb +0 -109
- data/test/test_driver.rb +0 -26
- data/test/test_email.rb +0 -34
- data/test/test_event_handler.rb +0 -82
- data/test/test_god.rb +0 -710
- data/test/test_god_system.rb +0 -201
- data/test/test_handlers_kqueue_handler.rb +0 -16
- data/test/test_hipchat.rb +0 -23
- data/test/test_jabber.rb +0 -29
- data/test/test_logger.rb +0 -55
- data/test/test_metric.rb +0 -74
- data/test/test_process.rb +0 -263
- data/test/test_prowl.rb +0 -15
- data/test/test_registry.rb +0 -15
- data/test/test_sensu.rb +0 -11
- data/test/test_slack.rb +0 -57
- data/test/test_socket.rb +0 -34
- data/test/test_statsd.rb +0 -22
- data/test/test_sugar.rb +0 -42
- data/test/test_system_portable_poller.rb +0 -17
- data/test/test_system_process.rb +0 -30
- data/test/test_task.rb +0 -246
- data/test/test_timeline.rb +0 -37
- data/test/test_trigger.rb +0 -63
- data/test/test_watch.rb +0 -286
- data/test/test_webhook.rb +0 -22
data/lib/god/system/process.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module God
|
2
2
|
module System
|
3
|
-
|
4
3
|
class Process
|
5
4
|
def self.fetch_system_poller
|
6
5
|
@@poller ||= if SlashProcPoller.usable?
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
SlashProcPoller
|
7
|
+
else
|
8
|
+
PortablePoller
|
9
|
+
end
|
11
10
|
end
|
12
11
|
|
13
12
|
def initialize(pid)
|
@@ -45,6 +44,5 @@ module God
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
48
|
-
|
49
47
|
end
|
50
48
|
end
|
@@ -5,27 +5,27 @@ module God
|
|
5
5
|
@@hertz = 100
|
6
6
|
@@total_mem = nil
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
MEMINFO_PATH = '/proc/meminfo'.freeze
|
9
|
+
UPTIME_PATH = '/proc/uptime'.freeze
|
10
10
|
|
11
|
-
|
11
|
+
REQUIRED_PATHS = [MEMINFO_PATH, UPTIME_PATH].freeze
|
12
12
|
|
13
13
|
# FreeBSD has /proc by default, but nothing mounted there!
|
14
14
|
# So we should check for the actual required paths!
|
15
|
-
# Returns true if +
|
15
|
+
# Returns true if +REQUIRED_PATHS+ are readable.
|
16
16
|
def self.usable?
|
17
|
-
|
18
|
-
test(
|
17
|
+
REQUIRED_PATHS.all? do |path|
|
18
|
+
test('r', path) && readable?(path)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize(pid)
|
23
23
|
super(pid)
|
24
|
+
return if @@total_mem
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
26
|
+
# in K
|
27
|
+
File.open(MEMINFO_PATH) do |f|
|
28
|
+
@@total_mem = f.gets.split[1]
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -45,7 +45,7 @@ module God
|
|
45
45
|
def percent_cpu
|
46
46
|
stats = stat
|
47
47
|
total_time = stats[:utime].to_i + stats[:stime].to_i # in jiffies
|
48
|
-
seconds = uptime - stats[:starttime].to_i / @@hertz
|
48
|
+
seconds = uptime - (stats[:starttime].to_i / @@hertz)
|
49
49
|
if seconds == 0
|
50
50
|
0
|
51
51
|
else
|
@@ -55,21 +55,19 @@ module God
|
|
55
55
|
0
|
56
56
|
end
|
57
57
|
|
58
|
-
private
|
59
|
-
|
60
58
|
# Some systems (CentOS?) have a /proc, but they can hang when trying to
|
61
59
|
# read from them. Try to use this sparingly as it is expensive.
|
62
60
|
def self.readable?(path)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
false
|
67
|
-
end
|
61
|
+
Timeout.timeout(1) { File.read(path) }
|
62
|
+
rescue Timeout::Error
|
63
|
+
false
|
68
64
|
end
|
69
65
|
|
66
|
+
private
|
67
|
+
|
70
68
|
# in seconds
|
71
69
|
def uptime
|
72
|
-
File.read(
|
70
|
+
File.read(UPTIME_PATH).split[0].to_f
|
73
71
|
end
|
74
72
|
|
75
73
|
def stat
|
data/lib/god/task.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module God
|
2
|
-
|
3
2
|
class Task
|
4
3
|
# Public: Gets/Sets the String name of the task.
|
5
4
|
attr_accessor :name
|
@@ -33,7 +32,7 @@ module God
|
|
33
32
|
attr_accessor :state, :behaviors, :metrics, :directory
|
34
33
|
|
35
34
|
def initialize
|
36
|
-
@autostart
|
35
|
+
@autostart = true
|
37
36
|
|
38
37
|
# initial state is unmonitored
|
39
38
|
self.state = :unmonitored
|
@@ -42,7 +41,7 @@ module God
|
|
42
41
|
self.behaviors = []
|
43
42
|
|
44
43
|
# the list of conditions for each action
|
45
|
-
self.metrics = {nil => [], :unmonitored => [], :stop => []}
|
44
|
+
self.metrics = { nil => [], :unmonitored => [], :stop => [] }
|
46
45
|
|
47
46
|
# the condition -> metric lookup
|
48
47
|
self.directory = {}
|
@@ -55,8 +54,8 @@ module God
|
|
55
54
|
#
|
56
55
|
# Returns nothing.
|
57
56
|
def prepare
|
58
|
-
|
59
|
-
|
57
|
+
valid_states.each do |state|
|
58
|
+
metrics[state] ||= []
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
@@ -67,21 +66,21 @@ module God
|
|
67
66
|
valid = true
|
68
67
|
|
69
68
|
# A name must be specified.
|
70
|
-
if
|
69
|
+
if name.nil?
|
71
70
|
valid = false
|
72
|
-
applog(self, :error,
|
71
|
+
applog(self, :error, 'No name String was specified.')
|
73
72
|
end
|
74
73
|
|
75
74
|
# Valid states must be specified.
|
76
|
-
if
|
75
|
+
if valid_states.nil?
|
77
76
|
valid = false
|
78
|
-
applog(self, :error,
|
77
|
+
applog(self, :error, 'No valid_states Array or Symbols was specified.')
|
79
78
|
end
|
80
79
|
|
81
80
|
# An initial state must be specified.
|
82
|
-
if
|
81
|
+
if initial_state.nil?
|
83
82
|
valid = false
|
84
|
-
applog(self, :error,
|
83
|
+
applog(self, :error, 'No initial_state Symbol was specified.')
|
85
84
|
end
|
86
85
|
|
87
86
|
valid
|
@@ -101,7 +100,7 @@ module God
|
|
101
100
|
#
|
102
101
|
# Returns the canonical Hash.
|
103
102
|
def canonical_hash_form(to)
|
104
|
-
to.instance_of?(Symbol) ? {true => to} : to
|
103
|
+
to.instance_of?(Symbol) ? { true => to } : to
|
105
104
|
end
|
106
105
|
|
107
106
|
# Public: Define a transition handler which consists of a set of conditions
|
@@ -118,8 +117,8 @@ module God
|
|
118
117
|
|
119
118
|
Array(start_states).each do |start_state|
|
120
119
|
# Validate start state.
|
121
|
-
unless
|
122
|
-
abort "Invalid state :#{start_state}. Must be one of the symbols #{
|
120
|
+
unless valid_states.include?(start_state)
|
121
|
+
abort "Invalid state :#{start_state}. Must be one of the symbols #{valid_states.map { |x| ":#{x}" }.join(', ')}"
|
123
122
|
end
|
124
123
|
|
125
124
|
# Create a new metric to hold the task, end states, and conditions.
|
@@ -137,12 +136,12 @@ module God
|
|
137
136
|
|
138
137
|
# Populate the condition -> metric directory.
|
139
138
|
m.conditions.each do |c|
|
140
|
-
|
139
|
+
directory[c] = m
|
141
140
|
end
|
142
141
|
|
143
142
|
# Record the metric.
|
144
|
-
|
145
|
-
|
143
|
+
metrics[start_state] ||= []
|
144
|
+
metrics[start_state] << m
|
146
145
|
end
|
147
146
|
end
|
148
147
|
|
@@ -159,11 +158,11 @@ module God
|
|
159
158
|
|
160
159
|
# Populate the condition -> metric directory.
|
161
160
|
m.conditions.each do |c|
|
162
|
-
|
161
|
+
directory[c] = m
|
163
162
|
end
|
164
163
|
|
165
164
|
# Record the metric.
|
166
|
-
|
165
|
+
metrics[nil] << m
|
167
166
|
end
|
168
167
|
|
169
168
|
###########################################################################
|
@@ -176,14 +175,14 @@ module God
|
|
176
175
|
#
|
177
176
|
# Returns nothing.
|
178
177
|
def monitor
|
179
|
-
|
178
|
+
move(initial_state)
|
180
179
|
end
|
181
180
|
|
182
181
|
# Disable monitoring.
|
183
182
|
#
|
184
183
|
# Returns nothing.
|
185
184
|
def unmonitor
|
186
|
-
|
185
|
+
move(:unmonitored)
|
187
186
|
end
|
188
187
|
|
189
188
|
# Move to the given state.
|
@@ -192,40 +191,31 @@ module God
|
|
192
191
|
#
|
193
192
|
# Returns this Task.
|
194
193
|
def move(to_state)
|
195
|
-
if
|
196
|
-
# Called from outside Driver. Send an async message to Driver.
|
197
|
-
self.driver.message(:move, [to_state])
|
198
|
-
else
|
194
|
+
if driver.in_driver_context?
|
199
195
|
# Called from within Driver. Record original info.
|
200
196
|
orig_to_state = to_state
|
201
|
-
from_state =
|
197
|
+
from_state = state
|
202
198
|
|
203
199
|
# Log.
|
204
|
-
msg = "#{
|
200
|
+
msg = "#{name} move '#{from_state}' to '#{to_state}'"
|
205
201
|
applog(self, :info, msg)
|
206
202
|
|
207
203
|
# Cleanup from current state.
|
208
|
-
|
209
|
-
|
210
|
-
if to_state == :unmonitored
|
211
|
-
self.metrics[nil].each { |m| m.disable }
|
212
|
-
end
|
204
|
+
driver.clear_events
|
205
|
+
metrics[from_state].each(&:disable)
|
206
|
+
metrics[nil].each(&:disable) if to_state == :unmonitored
|
213
207
|
|
214
208
|
# Perform action.
|
215
|
-
|
209
|
+
action(to_state)
|
216
210
|
|
217
211
|
# Enable simple mode.
|
218
|
-
if [:start, :restart].include?(to_state) &&
|
219
|
-
to_state = :up
|
220
|
-
end
|
212
|
+
to_state = :up if [:start, :restart].include?(to_state) && metrics[to_state].empty?
|
221
213
|
|
222
214
|
# Move to new state.
|
223
|
-
|
215
|
+
metrics[to_state].each(&:enable)
|
224
216
|
|
225
217
|
# If no from state, enable lifecycle metric.
|
226
|
-
if from_state == :unmonitored
|
227
|
-
self.metrics[nil].each { |m| m.enable }
|
228
|
-
end
|
218
|
+
metrics[nil].each(&:enable) if from_state == :unmonitored
|
229
219
|
|
230
220
|
# Set state.
|
231
221
|
self.state = to_state
|
@@ -234,8 +224,11 @@ module God
|
|
234
224
|
Trigger.broadcast(self, :state_change, [from_state, orig_to_state])
|
235
225
|
|
236
226
|
# Log.
|
237
|
-
msg = "#{
|
227
|
+
msg = "#{name} moved '#{from_state}' to '#{to_state}'"
|
238
228
|
applog(self, :info, msg)
|
229
|
+
else
|
230
|
+
# Called from outside Driver. Send an async message to Driver.
|
231
|
+
driver.message(:move, [to_state])
|
239
232
|
end
|
240
233
|
|
241
234
|
self
|
@@ -247,7 +240,7 @@ module God
|
|
247
240
|
#
|
248
241
|
# Returns nothing.
|
249
242
|
def trigger(condition)
|
250
|
-
|
243
|
+
driver.message(:handle_event, [condition])
|
251
244
|
end
|
252
245
|
|
253
246
|
def signal(sig)
|
@@ -261,49 +254,43 @@ module God
|
|
261
254
|
###########################################################################
|
262
255
|
|
263
256
|
def method_missing(sym, *args)
|
264
|
-
unless (sym.to_s
|
265
|
-
super
|
266
|
-
end
|
257
|
+
super unless /=$/.match?(sym.to_s)
|
267
258
|
|
268
259
|
base = sym.to_s.chop.intern
|
269
260
|
|
270
|
-
unless
|
271
|
-
super
|
272
|
-
end
|
261
|
+
super unless valid_states.include?(base)
|
273
262
|
|
274
263
|
self.class.send(:attr_accessor, base)
|
275
|
-
|
264
|
+
send(sym, *args)
|
276
265
|
end
|
277
266
|
|
278
267
|
# Perform the given action.
|
279
268
|
#
|
280
|
-
#
|
281
|
-
#
|
269
|
+
# action - The Symbol action.
|
270
|
+
# condition - The Condition.
|
282
271
|
#
|
283
272
|
# Returns this Task.
|
284
|
-
def action(
|
285
|
-
if !
|
273
|
+
def action(action, condition = nil)
|
274
|
+
if !driver.in_driver_context?
|
286
275
|
# Called from outside Driver. Send an async message to Driver.
|
287
|
-
|
288
|
-
|
276
|
+
driver.message(:action, [action, condition])
|
277
|
+
elsif respond_to?(action)
|
289
278
|
# Called from within Driver.
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
raise NotImplementedError
|
306
|
-
end
|
279
|
+
command = send(action)
|
280
|
+
|
281
|
+
case command
|
282
|
+
when String
|
283
|
+
msg = "#{name} #{action}: #{command}"
|
284
|
+
applog(self, :info, msg)
|
285
|
+
|
286
|
+
system(command)
|
287
|
+
when Proc
|
288
|
+
msg = "#{name} #{action}: lambda"
|
289
|
+
applog(self, :info, msg)
|
290
|
+
|
291
|
+
command.call
|
292
|
+
else
|
293
|
+
raise NotImplementedError
|
307
294
|
end
|
308
295
|
end
|
309
296
|
end
|
@@ -316,19 +303,19 @@ module God
|
|
316
303
|
|
317
304
|
def attach(condition)
|
318
305
|
case condition
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
306
|
+
when PollCondition
|
307
|
+
driver.schedule(condition, 0)
|
308
|
+
when EventCondition, TriggerCondition
|
309
|
+
condition.register
|
323
310
|
end
|
324
311
|
end
|
325
312
|
|
326
313
|
def detach(condition)
|
327
314
|
case condition
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
315
|
+
when PollCondition
|
316
|
+
condition.reset
|
317
|
+
when EventCondition, TriggerCondition
|
318
|
+
condition.deregister
|
332
319
|
end
|
333
320
|
end
|
334
321
|
|
@@ -360,55 +347,53 @@ module God
|
|
360
347
|
# Returns nothing.
|
361
348
|
def handle_poll(condition)
|
362
349
|
# Lookup metric.
|
363
|
-
metric =
|
350
|
+
metric = directory[condition]
|
364
351
|
|
365
352
|
# Run the test.
|
366
353
|
begin
|
367
354
|
result = condition.test
|
368
355
|
rescue Object => e
|
369
356
|
cname = condition.class.to_s.split('::').last
|
370
|
-
message = format("Unhandled exception in %
|
371
|
-
cname, e.class, e.message, e.backtrace.join("\n"))
|
357
|
+
message = format("Unhandled exception in %{cname} condition - (%{class}): %{message}\n%{backtrace}",
|
358
|
+
cname: cname, class: e.class, message: e.message, backtrace: e.backtrace.join("\n"))
|
372
359
|
applog(self, :error, message)
|
373
360
|
result = false
|
374
361
|
end
|
375
362
|
|
376
363
|
# Log.
|
377
|
-
messages =
|
364
|
+
messages = log_line(self, metric, condition, result)
|
378
365
|
|
379
366
|
# Notify.
|
380
|
-
if result && condition.notify
|
381
|
-
self.notify(condition, messages.last)
|
382
|
-
end
|
367
|
+
notify(condition, messages.last) if result && condition.notify
|
383
368
|
|
384
369
|
# After-condition.
|
385
370
|
condition.after
|
386
371
|
|
387
372
|
# Get the destination.
|
388
373
|
dest =
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
374
|
+
if result && condition.transition
|
375
|
+
# Condition override.
|
376
|
+
condition.transition
|
377
|
+
else
|
378
|
+
# Regular.
|
379
|
+
metric.destination && metric.destination[result]
|
380
|
+
end
|
396
381
|
|
397
382
|
# Transition or reschedule.
|
398
383
|
if dest
|
399
384
|
# Transition.
|
400
385
|
begin
|
401
|
-
|
386
|
+
move(dest)
|
402
387
|
rescue EventRegistrationFailedError
|
403
|
-
msg =
|
388
|
+
msg = "#{name} Event registration failed, moving back to previous state"
|
404
389
|
applog(self, :info, msg)
|
405
390
|
|
406
|
-
dest =
|
391
|
+
dest = state
|
407
392
|
retry
|
408
393
|
end
|
409
394
|
else
|
410
395
|
# Reschedule.
|
411
|
-
|
396
|
+
driver.schedule(condition)
|
412
397
|
end
|
413
398
|
end
|
414
399
|
|
@@ -420,29 +405,20 @@ module God
|
|
420
405
|
# Returns nothing.
|
421
406
|
def handle_event(condition)
|
422
407
|
# Lookup metric.
|
423
|
-
metric =
|
408
|
+
metric = directory[condition]
|
424
409
|
|
425
410
|
# Log.
|
426
|
-
messages =
|
411
|
+
messages = log_line(self, metric, condition, true)
|
427
412
|
|
428
413
|
# Notify.
|
429
|
-
if condition.notify
|
430
|
-
self.notify(condition, messages.last)
|
431
|
-
end
|
414
|
+
notify(condition, messages.last) if condition.notify
|
432
415
|
|
433
416
|
# Get the destination.
|
434
|
-
dest =
|
435
|
-
if condition.transition
|
436
|
-
# Condition override.
|
437
|
-
condition.transition
|
438
|
-
else
|
439
|
-
# Regular.
|
440
|
-
metric.destination && metric.destination[true]
|
441
|
-
end
|
417
|
+
dest = condition.transition || (metric.destination && metric.destination[true])
|
442
418
|
|
443
|
-
|
444
|
-
|
445
|
-
|
419
|
+
return unless dest
|
420
|
+
|
421
|
+
move(dest)
|
446
422
|
end
|
447
423
|
|
448
424
|
# Determine whether a trigger happened.
|
@@ -465,11 +441,11 @@ module God
|
|
465
441
|
# Returns the Array of String messages.
|
466
442
|
def log_line(watch, metric, condition, result)
|
467
443
|
status =
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
444
|
+
if trigger?(metric, result)
|
445
|
+
'[trigger]'
|
446
|
+
else
|
447
|
+
'[ok]'
|
448
|
+
end
|
473
449
|
|
474
450
|
messages = []
|
475
451
|
|
@@ -485,7 +461,7 @@ module God
|
|
485
461
|
end
|
486
462
|
|
487
463
|
# Log.
|
488
|
-
debug_message = watch.name
|
464
|
+
debug_message = "#{watch.name} #{condition.base_name} [#{result}] #{dest_desc(metric, condition)}"
|
489
465
|
applog(watch, :debug, debug_message)
|
490
466
|
|
491
467
|
messages
|
@@ -499,13 +475,11 @@ module God
|
|
499
475
|
# Returns the formatted String.
|
500
476
|
def dest_desc(metric, condition)
|
501
477
|
if condition.transition
|
502
|
-
{true => condition.transition}.inspect
|
478
|
+
{ true => condition.transition }.inspect
|
479
|
+
elsif metric.destination
|
480
|
+
metric.destination.inspect
|
503
481
|
else
|
504
|
-
|
505
|
-
metric.destination.inspect
|
506
|
-
else
|
507
|
-
'none'
|
508
|
-
end
|
482
|
+
'none'
|
509
483
|
end
|
510
484
|
end
|
511
485
|
|
@@ -521,16 +495,16 @@ module God
|
|
521
495
|
|
522
496
|
# Resolve contacts.
|
523
497
|
resolved_contacts =
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
498
|
+
spec[:contacts].inject([]) do |acc, contact_name_or_group|
|
499
|
+
cons = Array(God.contacts[contact_name_or_group] || God.contact_groups[contact_name_or_group])
|
500
|
+
unmatched << contact_name_or_group if cons.empty?
|
501
|
+
acc += cons
|
502
|
+
acc
|
503
|
+
end
|
530
504
|
|
531
505
|
# Warn about unmatched contacts.
|
532
506
|
unless unmatched.empty?
|
533
|
-
msg = "#{condition.watch.name} no matching contacts for '#{unmatched.join(
|
507
|
+
msg = "#{condition.watch.name} no matching contacts for '#{unmatched.join(', ')}'"
|
534
508
|
applog(condition.watch, :warn, msg)
|
535
509
|
end
|
536
510
|
|
@@ -539,12 +513,12 @@ module God
|
|
539
513
|
host = `hostname`.chomp rescue 'none'
|
540
514
|
begin
|
541
515
|
c.notify(message, Time.now, spec[:priority], spec[:category], host)
|
542
|
-
msg = "#{condition.watch.name} #{c.info
|
543
|
-
applog(condition.watch, :info, msg
|
516
|
+
msg = "#{condition.watch.name} #{c.info || "notification sent for contact: #{c.name}"} (#{c.base_name})"
|
517
|
+
applog(condition.watch, :info, msg)
|
544
518
|
rescue Exception => e
|
545
519
|
applog(condition.watch, :error, "#{e.message} #{e.backtrace}")
|
546
520
|
msg = "#{condition.watch.name} Failed to deliver notification for contact: #{c.name} (#{c.base_name})"
|
547
|
-
applog(condition.watch, :error, msg
|
521
|
+
applog(condition.watch, :error, msg)
|
548
522
|
end
|
549
523
|
end
|
550
524
|
end
|
data/lib/god/timeline.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module God
|
2
|
-
|
3
2
|
class Timeline < Array
|
4
3
|
# Instantiate a new Timeline
|
5
4
|
# +max_size+ is the maximum size to which the timeline should grow
|
@@ -15,11 +14,10 @@ module God
|
|
15
14
|
#
|
16
15
|
# Returns Timeline
|
17
16
|
def push(val)
|
18
|
-
|
17
|
+
concat([val])
|
19
18
|
shift if size > @max_size
|
20
19
|
end
|
21
20
|
|
22
|
-
|
21
|
+
alias << push
|
23
22
|
end
|
24
|
-
|
25
23
|
end
|
data/lib/god/trigger.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module God
|
2
|
-
|
3
2
|
class Trigger
|
4
|
-
|
5
3
|
class << self
|
6
4
|
attr_accessor :triggers # {task.name => condition}
|
7
5
|
end
|
@@ -12,32 +10,30 @@ module God
|
|
12
10
|
|
13
11
|
def self.register(condition)
|
14
12
|
@mutex.synchronize do
|
15
|
-
|
16
|
-
|
13
|
+
triggers[condition.watch.name] ||= []
|
14
|
+
triggers[condition.watch.name] << condition
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
18
|
def self.deregister(condition)
|
21
19
|
@mutex.synchronize do
|
22
|
-
|
23
|
-
|
20
|
+
triggers[condition.watch.name].delete(condition)
|
21
|
+
triggers.delete(condition.watch.name) if triggers[condition.watch.name].empty?
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
25
|
def self.broadcast(task, message, payload)
|
28
|
-
return unless
|
26
|
+
return unless triggers[task.name]
|
29
27
|
|
30
28
|
@mutex.synchronize do
|
31
|
-
|
29
|
+
triggers[task.name].each do |t|
|
32
30
|
t.process(message, payload)
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
def self.reset
|
38
|
-
|
36
|
+
triggers.clear
|
39
37
|
end
|
40
|
-
|
41
38
|
end
|
42
|
-
|
43
39
|
end
|
data/lib/god/version.rb
CHANGED