sensu 0.9.2 → 0.9.3.beta
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/lib/sensu.rb +1 -1
- data/lib/sensu/client.rb +30 -25
- data/lib/sensu/config.rb +3 -0
- data/lib/sensu/patches/ruby.rb +10 -10
- data/lib/sensu/server.rb +71 -66
- metadata +12 -9
data/lib/sensu.rb
CHANGED
data/lib/sensu/client.rb
CHANGED
@@ -10,6 +10,7 @@ module Sensu
|
|
10
10
|
if options[:pid_file]
|
11
11
|
Process.write_pid(options[:pid_file])
|
12
12
|
end
|
13
|
+
EM::threadpool_size = 16
|
13
14
|
EM::run do
|
14
15
|
client.setup_amqp
|
15
16
|
client.setup_keepalives
|
@@ -150,13 +151,13 @@ module Sensu
|
|
150
151
|
|
151
152
|
def setup_standalone(options={})
|
152
153
|
@logger.debug('[standalone] -- setup standalone')
|
153
|
-
|
154
|
+
standalone_check_count = 0
|
154
155
|
@settings.checks.each do |name, details|
|
155
156
|
if details.standalone
|
156
|
-
|
157
|
-
check = Hashie::Mash.new(details.merge(
|
157
|
+
standalone_check_count += 1
|
158
|
+
check = Hashie::Mash.new(details.merge(:name => name))
|
158
159
|
stagger = options[:test] ? 0 : 7
|
159
|
-
@timers << EM::Timer.new(stagger*
|
160
|
+
@timers << EM::Timer.new(stagger*standalone_check_count) do
|
160
161
|
interval = options[:test] ? 0.5 : details.interval
|
161
162
|
@timers << EM::PeriodicTimer.new(interval) do
|
162
163
|
check.issued = Time.now.to_i
|
@@ -207,29 +208,33 @@ module Sensu
|
|
207
208
|
attr_accessor :settings, :logger, :amq
|
208
209
|
|
209
210
|
def receive_data(data)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
211
|
+
if data == 'ping'
|
212
|
+
@logger.debug('[socket] -- received ping')
|
213
|
+
send_data('pong')
|
214
|
+
else
|
215
|
+
@logger.debug('[socket] -- received data -- ' + data)
|
216
|
+
begin
|
217
|
+
check = Hashie::Mash.new(JSON.parse(data))
|
218
|
+
validates = %w[name output].all? do |key|
|
219
|
+
check[key].is_a?(String)
|
220
|
+
end
|
221
|
+
check.status ||= 0
|
222
|
+
if validates && check.status.is_a?(Integer)
|
223
|
+
@logger.info('[socket] -- publishing check result -- ' + [check.name, check.status, check.output].join(' -- '))
|
224
|
+
@amq.queue('results').publish({
|
225
|
+
:client => @settings.client.name,
|
226
|
+
:check => check.to_hash
|
227
|
+
}.to_json)
|
228
|
+
send_data('ok')
|
229
|
+
else
|
230
|
+
@logger.warn('[socket] -- check name and output must be strings, status defaults to 0 -- e.g. {"name": "x", "output": "y"}')
|
231
|
+
send_data('invalid')
|
232
|
+
end
|
233
|
+
rescue JSON::ParserError => error
|
234
|
+
@logger.warn('[socket] -- check result must be valid JSON: ' + error.to_s)
|
235
|
+
send_data('invalid')
|
224
236
|
end
|
225
|
-
rescue JSON::ParserError => error
|
226
|
-
@logger.warn('[socket] -- check result must be valid JSON: ' + error.to_s)
|
227
237
|
end
|
228
|
-
close_connection
|
229
|
-
end
|
230
|
-
|
231
|
-
def unbind
|
232
|
-
@logger.debug('[socket] -- connection closed')
|
233
238
|
end
|
234
239
|
end
|
235
240
|
end
|
data/lib/sensu/config.rb
CHANGED
@@ -55,6 +55,9 @@ module Sensu
|
|
55
55
|
|
56
56
|
def validate_common_settings
|
57
57
|
@settings.checks.each do |name, details|
|
58
|
+
if details.key?('status') || details.key?('output')
|
59
|
+
invalid_config('reserved key (status or output) defined in check ' + name)
|
60
|
+
end
|
58
61
|
unless details.interval.is_a?(Integer) && details.interval > 0
|
59
62
|
invalid_config('missing interval for check ' + name)
|
60
63
|
end
|
data/lib/sensu/patches/ruby.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
class Array
|
2
|
+
def deep_merge(other_array, &merger)
|
3
|
+
concat(other_array).uniq
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
class Hash
|
2
8
|
def symbolize_keys(item=self)
|
3
9
|
case item
|
@@ -31,17 +37,11 @@ class Hash
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
|
-
def deep_merge(
|
35
|
-
merger
|
36
|
-
|
37
|
-
value1.merge(value2, &merger)
|
38
|
-
elsif value1.is_a?(Array) && value2.is_a?(Array)
|
39
|
-
value1.concat(value2).uniq
|
40
|
-
else
|
41
|
-
value2
|
42
|
-
end
|
40
|
+
def deep_merge(other_hash, &merger)
|
41
|
+
merger ||= proc do |key, oldval, newval|
|
42
|
+
oldval.deep_merge(newval, &merger) rescue newval
|
43
43
|
end
|
44
|
-
|
44
|
+
merge(other_hash, &merger)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
data/lib/sensu/server.rb
CHANGED
@@ -91,22 +91,20 @@ module Sensu
|
|
91
91
|
details = @settings.handlers[handler]
|
92
92
|
case details['type']
|
93
93
|
when 'pipe'
|
94
|
-
|
95
|
-
output = ''
|
94
|
+
execute = proc do
|
96
95
|
Bundler.with_clean_env do
|
97
96
|
begin
|
98
97
|
IO.popen(details.command + ' 2>&1', 'r+') do |io|
|
99
98
|
io.write(event.to_json)
|
100
99
|
io.close_write
|
101
|
-
|
100
|
+
io.read
|
102
101
|
end
|
103
102
|
rescue Errno::EPIPE => error
|
104
|
-
|
103
|
+
handler + ' -- broken pipe: ' + error.to_s
|
105
104
|
end
|
106
105
|
end
|
107
|
-
output
|
108
106
|
end
|
109
|
-
EM::defer(
|
107
|
+
EM::defer(execute, report)
|
110
108
|
when 'amqp'
|
111
109
|
exchange = details.exchange.name
|
112
110
|
exchange_type = details.exchange.key?('type') ? details.exchange['type'].to_sym : :direct
|
@@ -130,79 +128,86 @@ module Sensu
|
|
130
128
|
@redis.get('client:' + result.client).callback do |client_json|
|
131
129
|
unless client_json.nil?
|
132
130
|
client = Hashie::Mash.new(JSON.parse(client_json))
|
133
|
-
check = @settings.checks.key?(result.check.name) ?
|
134
|
-
event = Hashie::Mash.new(
|
131
|
+
check = @settings.checks.key?(result.check.name) ? @settings.checks[result.check.name].merge(result.check) : result.check
|
132
|
+
event = Hashie::Mash.new(
|
135
133
|
:client => client,
|
136
134
|
:check => check,
|
137
135
|
:occurrences => 1
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
136
|
+
)
|
137
|
+
history_key = 'history:' + client.name + ':' + check.name
|
138
|
+
@redis.rpush(history_key, check.status).callback do
|
139
|
+
@redis.lrange(history_key, -21, -1).callback do |history|
|
140
|
+
event.check.history = history
|
141
|
+
total_state_change = 0
|
142
|
+
unless history.count < 21
|
143
|
+
state_changes = 0
|
144
|
+
change_weight = 0.8
|
145
|
+
history.each do |status|
|
146
|
+
previous_status ||= status
|
147
|
+
unless status == previous_status
|
148
|
+
state_changes += change_weight
|
149
|
+
end
|
150
|
+
change_weight += 0.02
|
151
|
+
previous_status = status
|
152
|
+
end
|
153
|
+
total_state_change = (state_changes.fdiv(20) * 100).to_i
|
154
|
+
@redis.lpop(history_key)
|
155
|
+
end
|
156
|
+
@redis.hget('events:' + client.name, check.name).callback do |event_json|
|
157
|
+
previous_occurrence = event_json ? Hashie::Mash.new(JSON.parse(event_json)) : false
|
158
|
+
is_flapping = false
|
159
|
+
if check.key?('low_flap_threshold') && check.key?('high_flap_threshold')
|
160
|
+
was_flapping = previous_occurrence ? previous_occurrence.flapping : false
|
161
|
+
is_flapping = case
|
162
|
+
when total_state_change >= check.high_flap_threshold
|
163
|
+
true
|
164
|
+
when was_flapping && total_state_change <= check.low_flap_threshold
|
165
|
+
false
|
166
|
+
else
|
167
|
+
was_flapping
|
157
168
|
end
|
158
|
-
total_state_change = (state_changes.fdiv(20) * 100).to_i
|
159
|
-
@redis.lpop(history_key)
|
160
169
|
end
|
161
|
-
|
162
|
-
previous_occurrence
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
170
|
+
if check.status != 0
|
171
|
+
if previous_occurrence && check.status == previous_occurrence.status
|
172
|
+
event.occurrences = previous_occurrence.occurrences += 1
|
173
|
+
end
|
174
|
+
@redis.hset('events:' + client.name, check.name, {
|
175
|
+
:status => check.status,
|
176
|
+
:output => check.output,
|
177
|
+
:flapping => is_flapping,
|
178
|
+
:occurrences => event.occurrences
|
179
|
+
}.to_json).callback do
|
180
|
+
unless check.handle == false
|
181
|
+
event.check.flapping = is_flapping
|
182
|
+
event.action = 'create'
|
183
|
+
handle_event(event)
|
171
184
|
else
|
172
|
-
|
185
|
+
@logger.debug('[result] -- handling disabled -- ' + [client.name, check.name, check.status].join(' -- '))
|
173
186
|
end
|
174
187
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
188
|
+
elsif previous_occurrence
|
189
|
+
unless is_flapping
|
190
|
+
unless check.auto_resolve == false && !check.force_resolve
|
191
|
+
@redis.hdel('events:' + client.name, check.name).callback do
|
192
|
+
unless check.handle == false
|
193
|
+
event.action = 'resolve'
|
194
|
+
handle_event(event)
|
195
|
+
else
|
196
|
+
@logger.debug('[result] -- handling disabled -- ' + [client.name, check.name, check.status].join(' -- '))
|
183
197
|
end
|
184
198
|
end
|
185
|
-
else
|
186
|
-
@logger.debug('[result] -- check is flapping -- ' + client.name + ' -- ' + check.name)
|
187
|
-
@redis.hset('events:' + client.name, check.name, previous_occurrence.merge({'flapping' => true}).to_json)
|
188
|
-
end
|
189
|
-
elsif check.status != 0
|
190
|
-
if previous_occurrence && check.status == previous_occurrence.status
|
191
|
-
event.occurrences = previous_occurrence.occurrences += 1
|
192
199
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
:occurrences => event.occurrences
|
198
|
-
}.to_json).callback do
|
199
|
-
unless check.handle == false
|
200
|
+
else
|
201
|
+
@logger.debug('[result] -- check is flapping -- ' + [client.name, check.name, check.status].join(' -- '))
|
202
|
+
@redis.hset('events:' + client.name, check.name, previous_occurrence.merge(:flapping => true).to_json).callback do
|
203
|
+
if check['type'] == 'metric'
|
200
204
|
event.check.flapping = is_flapping
|
201
|
-
event.action = 'create'
|
202
205
|
handle_event(event)
|
203
206
|
end
|
204
207
|
end
|
205
208
|
end
|
209
|
+
elsif check['type'] == 'metric'
|
210
|
+
handle_event(event)
|
206
211
|
end
|
207
212
|
end
|
208
213
|
end
|
@@ -225,7 +230,7 @@ module Sensu
|
|
225
230
|
@logger.debug('[publisher] -- setup publisher')
|
226
231
|
stagger = options[:test] ? 0 : 7
|
227
232
|
@settings.checks.each_with_index do |(name, details), index|
|
228
|
-
check_request = Hashie::Mash.new(
|
233
|
+
check_request = Hashie::Mash.new(:name => name)
|
229
234
|
unless details.publish == false || details.standalone
|
230
235
|
@timers << EM::Timer.new(stagger*index) do
|
231
236
|
details.subscribers.each do |exchange|
|
@@ -250,13 +255,13 @@ module Sensu
|
|
250
255
|
@redis.get('client:' + client_id).callback do |client_json|
|
251
256
|
client = Hashie::Mash.new(JSON.parse(client_json))
|
252
257
|
time_since_last_keepalive = Time.now.to_i - client.timestamp
|
253
|
-
result = Hashie::Mash.new(
|
258
|
+
result = Hashie::Mash.new(
|
254
259
|
:client => client.name,
|
255
260
|
:check => {
|
256
261
|
:name => 'keepalive',
|
257
262
|
:issued => Time.now.to_i
|
258
263
|
}
|
259
|
-
|
264
|
+
)
|
260
265
|
case
|
261
266
|
when time_since_last_keepalive >= 180
|
262
267
|
result.check.status = 2
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 31098117
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
|
9
|
+
- 3
|
10
|
+
- beta
|
11
|
+
version: 0.9.3.beta
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Sean Porter
|
@@ -16,7 +17,7 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2012-01-
|
20
|
+
date: 2012-01-12 00:00:00 -08:00
|
20
21
|
default_executable:
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
@@ -258,12 +259,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
258
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
260
|
none: false
|
260
261
|
requirements:
|
261
|
-
- - "
|
262
|
+
- - ">"
|
262
263
|
- !ruby/object:Gem::Version
|
263
|
-
hash:
|
264
|
+
hash: 25
|
264
265
|
segments:
|
265
|
-
-
|
266
|
-
|
266
|
+
- 1
|
267
|
+
- 3
|
268
|
+
- 1
|
269
|
+
version: 1.3.1
|
267
270
|
requirements: []
|
268
271
|
|
269
272
|
rubyforge_project:
|