sensu 0.9.7.beta.3 → 0.9.7.beta.4
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/CHANGELOG.md +9 -1
- data/lib/sensu/api.rb +5 -1
- data/lib/sensu/base.rb +3 -6
- data/lib/sensu/cli.rb +2 -0
- data/lib/sensu/client.rb +66 -69
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/logger.rb +24 -4
- data/lib/sensu/process.rb +1 -1
- data/lib/sensu/redis.rb +1 -1
- data/lib/sensu/server.rb +31 -22
- data/lib/sensu/settings.rb +7 -7
- metadata +4 -5
- data/lib/sensu/patches/ruby.rb +0 -9
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,9 @@ TCP and UDP handler types, for writing event data to sockets.
|
|
9
9
|
|
10
10
|
API resources now support singular & plural, Rails friendly.
|
11
11
|
|
12
|
+
Client safe mode, require local check definition in order to execute
|
13
|
+
a check, disable for simpler deployment (default).
|
14
|
+
|
12
15
|
### Non-backwards compatible changes
|
13
16
|
|
14
17
|
AMQP handlers can no longer use `"send_only_check_output": true`, but
|
@@ -19,6 +22,11 @@ Ruby 1.8.7-p249 is no longer supported, as the AMQP library no longer
|
|
19
22
|
does. Please use the Sensu APT/YUM packages which contain an embedded
|
20
23
|
Ruby.
|
21
24
|
|
25
|
+
Client expects check requests to contain a command, be sure to upgrade
|
26
|
+
servers prior to upgrading clients.
|
27
|
+
|
28
|
+
Check subdue options have been modified, "start" is now "begin".
|
29
|
+
|
22
30
|
### Other
|
23
31
|
|
24
32
|
Improved RabbitMQ and Redis connection recovery.
|
@@ -33,4 +41,4 @@ Improved client socket ping/pong.
|
|
33
41
|
|
34
42
|
Strict dependency version locking.
|
35
43
|
|
36
|
-
Adjusted logging level for metric
|
44
|
+
Adjusted logging level for metric events.
|
data/lib/sensu/api.rb
CHANGED
@@ -18,7 +18,7 @@ module Sensu
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def bootstrap(options={})
|
21
|
-
$logger =
|
21
|
+
$logger = Sensu::Logger.get
|
22
22
|
base = Sensu::Base.new(options)
|
23
23
|
$settings = base.settings
|
24
24
|
if $settings[:api][:user] && $settings[:api][:password]
|
@@ -62,10 +62,14 @@ module Sensu
|
|
62
62
|
exit 2
|
63
63
|
end
|
64
64
|
$rabbitmq = AMQP.connect($settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
65
|
+
$rabbitmq.logger = Sensu::NullLogger.get
|
65
66
|
$rabbitmq.on_tcp_connection_loss do |connection, settings|
|
66
67
|
$logger.warn('reconnecting to rabbitmq')
|
67
68
|
connection.reconnect(false, 10)
|
68
69
|
end
|
70
|
+
$rabbitmq.on_skipped_heartbeats do
|
71
|
+
$logger.warn('skipped rabbitmq heartbeat')
|
72
|
+
end
|
69
73
|
$amq = AMQP::Channel.new($rabbitmq)
|
70
74
|
$amq.auto_recovery = true
|
71
75
|
end
|
data/lib/sensu/base.rb
CHANGED
@@ -2,15 +2,11 @@ require 'rubygems'
|
|
2
2
|
|
3
3
|
gem 'eventmachine', '1.0.0.rc.4'
|
4
4
|
|
5
|
-
require 'optparse'
|
6
5
|
require 'json'
|
7
6
|
require 'time'
|
8
7
|
require 'uri'
|
9
|
-
require 'cabin'
|
10
8
|
require 'amqp'
|
11
9
|
|
12
|
-
require File.join(File.dirname(__FILE__), 'patches', 'ruby')
|
13
|
-
|
14
10
|
require File.join(File.dirname(__FILE__), 'constants')
|
15
11
|
require File.join(File.dirname(__FILE__), 'cli')
|
16
12
|
require File.join(File.dirname(__FILE__), 'logger')
|
@@ -29,8 +25,9 @@ module Sensu
|
|
29
25
|
end
|
30
26
|
|
31
27
|
def setup_logging
|
32
|
-
logger = Sensu::Logger.new
|
33
|
-
logger.
|
28
|
+
logger = Sensu::Logger.new
|
29
|
+
logger.level = @options[:verbose] ? :debug : @options[:log_level] || :info
|
30
|
+
logger.reopen(@options[:log_file])
|
34
31
|
logger.setup_traps
|
35
32
|
end
|
36
33
|
|
data/lib/sensu/cli.rb
CHANGED
data/lib/sensu/client.rb
CHANGED
@@ -12,7 +12,7 @@ module Sensu
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize(options={})
|
15
|
-
@logger =
|
15
|
+
@logger = Sensu::Logger.get
|
16
16
|
base = Sensu::Base.new(options)
|
17
17
|
@settings = base.settings
|
18
18
|
@timers = Array.new
|
@@ -31,10 +31,15 @@ module Sensu
|
|
31
31
|
exit 2
|
32
32
|
end
|
33
33
|
@rabbitmq = AMQP.connect(@settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
34
|
+
@rabbitmq.logger = Sensu::NullLogger.get
|
34
35
|
@rabbitmq.on_tcp_connection_loss do |connection, settings|
|
35
36
|
@logger.warn('reconnecting to rabbitmq')
|
36
37
|
connection.reconnect(false, 10)
|
37
38
|
end
|
39
|
+
@rabbitmq.on_skipped_heartbeats do
|
40
|
+
@logger.warn('skipped rabbitmq heartbeat')
|
41
|
+
@logger.warn('rabbitmq heartbeats are not recommended for clients')
|
42
|
+
end
|
38
43
|
@amq = AMQP::Channel.new(@rabbitmq)
|
39
44
|
@amq.auto_recovery = true
|
40
45
|
end
|
@@ -62,13 +67,7 @@ module Sensu
|
|
62
67
|
:client => @settings[:client][:name],
|
63
68
|
:check => check
|
64
69
|
}
|
65
|
-
|
66
|
-
if @settings.check_exists?(check[:name])
|
67
|
-
if @settings[:checks][check[:name]][:type] == 'metric'
|
68
|
-
log_level = :debug
|
69
|
-
end
|
70
|
-
end
|
71
|
-
@logger.send(log_level, 'publishing check result', {
|
70
|
+
@logger.info('publishing check result', {
|
72
71
|
:payload => payload
|
73
72
|
})
|
74
73
|
@amq.queue('results').publish(payload.to_json)
|
@@ -78,76 +77,62 @@ module Sensu
|
|
78
77
|
@logger.debug('attempting to execute check', {
|
79
78
|
:check => check
|
80
79
|
})
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
95
|
-
if substitute.nil?
|
96
|
-
unmatched_tokens.push(token)
|
97
|
-
end
|
98
|
-
substitute
|
80
|
+
unless @checks_in_progress.include?(check[:name])
|
81
|
+
@logger.debug('executing check', {
|
82
|
+
:check => check
|
83
|
+
})
|
84
|
+
@checks_in_progress.push(check[:name])
|
85
|
+
unmatched_tokens = Array.new
|
86
|
+
command = check[:command].gsub(/:::(.*?):::/) do
|
87
|
+
token = $1.to_s
|
88
|
+
matched = token.split('.').inject(@settings[:client]) do |client, attribute|
|
89
|
+
client[attribute].nil? ? break : client[attribute]
|
90
|
+
end
|
91
|
+
if matched.nil?
|
92
|
+
unmatched_tokens.push(token)
|
99
93
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
check[:status] = $?.exitstatus
|
109
|
-
rescue => error
|
110
|
-
@logger.warn('unexpected error', {
|
111
|
-
:error => error.to_s
|
112
|
-
})
|
113
|
-
check[:output] = 'Unexpected error: ' + error.to_s
|
114
|
-
check[:status] = 2
|
94
|
+
matched
|
95
|
+
end
|
96
|
+
if unmatched_tokens.empty?
|
97
|
+
execute = Proc.new do
|
98
|
+
started = Time.now.to_f
|
99
|
+
begin
|
100
|
+
IO.popen(command + ' 2>&1') do |io|
|
101
|
+
check[:output] = io.read
|
115
102
|
end
|
116
|
-
check[:
|
117
|
-
|
103
|
+
check[:status] = $?.exitstatus
|
104
|
+
rescue => error
|
105
|
+
@logger.warn('unexpected error', {
|
106
|
+
:error => error.to_s
|
107
|
+
})
|
108
|
+
check[:output] = 'Unexpected error: ' + error.to_s
|
109
|
+
check[:status] = 2
|
118
110
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
111
|
+
check[:duration] = ('%.3f' % (Time.now.to_f - started)).to_f
|
112
|
+
check
|
113
|
+
end
|
114
|
+
publish = Proc.new do |check|
|
115
|
+
unless check[:status].nil?
|
116
|
+
publish_result(check)
|
124
117
|
end
|
125
|
-
EM::defer(execute, publish)
|
126
|
-
else
|
127
|
-
@logger.warn('missing client attributes', {
|
128
|
-
:check => check,
|
129
|
-
:unmatched_tokens => unmatched_tokens
|
130
|
-
})
|
131
|
-
check[:output] = 'Missing client attributes: ' + unmatched_tokens.join(', ')
|
132
|
-
check[:status] = 3
|
133
|
-
check[:handle] = false
|
134
|
-
publish_result(check)
|
135
118
|
@checks_in_progress.delete(check[:name])
|
136
119
|
end
|
120
|
+
EM::defer(execute, publish)
|
137
121
|
else
|
138
|
-
@logger.warn('
|
139
|
-
:check => check
|
122
|
+
@logger.warn('missing client attributes', {
|
123
|
+
:check => check,
|
124
|
+
:unmatched_tokens => unmatched_tokens
|
140
125
|
})
|
126
|
+
check[:output] = 'Missing client attributes: ' + unmatched_tokens.join(', ')
|
127
|
+
check[:status] = 3
|
128
|
+
check[:handle] = false
|
129
|
+
publish_result(check)
|
130
|
+
@checks_in_progress.delete(check[:name])
|
141
131
|
end
|
142
132
|
else
|
143
|
-
@logger.warn('
|
133
|
+
@logger.warn('previous check execution in progress', {
|
144
134
|
:check => check
|
145
135
|
})
|
146
|
-
check[:output] = 'Unknown check'
|
147
|
-
check[:status] = 3
|
148
|
-
check[:handle] = false
|
149
|
-
publish_result(check)
|
150
|
-
@checks_in_progress.delete(check[:name])
|
151
136
|
end
|
152
137
|
end
|
153
138
|
|
@@ -159,8 +144,7 @@ module Sensu
|
|
159
144
|
@logger.debug('binding queue to exchange', {
|
160
145
|
:queue => @uniq_queue_name,
|
161
146
|
:exchange => {
|
162
|
-
:name => exchange_name
|
163
|
-
:type => 'fanout'
|
147
|
+
:name => exchange_name
|
164
148
|
}
|
165
149
|
})
|
166
150
|
@check_request_queue.bind(@amq.fanout(exchange_name))
|
@@ -171,7 +155,20 @@ module Sensu
|
|
171
155
|
@logger.info('received check request', {
|
172
156
|
:check => check
|
173
157
|
})
|
174
|
-
|
158
|
+
if @settings.check_exists?(check[:name])
|
159
|
+
check.merge!(@settings[:checks][check[:name]])
|
160
|
+
execute_check(check)
|
161
|
+
elsif @settings[:client][:safe_mode]
|
162
|
+
@logger.warn('check is not defined', {
|
163
|
+
:check => check
|
164
|
+
})
|
165
|
+
check[:output] = 'Check is not defined (safe mode)'
|
166
|
+
check[:status] = 3
|
167
|
+
check[:handle] = false
|
168
|
+
publish_result(check)
|
169
|
+
else
|
170
|
+
execute_check(check)
|
171
|
+
end
|
175
172
|
rescue JSON::ParserError => error
|
176
173
|
@logger.warn('check request payload must be valid json', {
|
177
174
|
:payload => payload,
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/logger.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
require 'cabin'
|
2
|
+
|
1
3
|
module Sensu
|
2
4
|
class Logger
|
3
|
-
def initialize
|
5
|
+
def initialize
|
4
6
|
@logger = Cabin::Channel.get
|
5
7
|
STDOUT.sync = true
|
8
|
+
STDERR.reopen(STDOUT)
|
6
9
|
@logger.subscribe(STDOUT)
|
7
|
-
|
8
|
-
|
10
|
+
end
|
11
|
+
|
12
|
+
def level=(log_level)
|
13
|
+
@logger.level = log_level
|
9
14
|
end
|
10
15
|
|
11
16
|
def reopen(file=nil)
|
@@ -14,8 +19,8 @@ module Sensu
|
|
14
19
|
@log_file = file
|
15
20
|
if File.writable?(file) || !File.exist?(file) && File.writable?(File.dirname(file))
|
16
21
|
STDOUT.reopen(file, 'a')
|
17
|
-
STDERR.reopen(STDOUT)
|
18
22
|
STDOUT.sync = true
|
23
|
+
STDERR.reopen(STDOUT)
|
19
24
|
else
|
20
25
|
@logger.error('log file is not writable', {
|
21
26
|
:log_file => file
|
@@ -36,5 +41,20 @@ module Sensu
|
|
36
41
|
end
|
37
42
|
end
|
38
43
|
end
|
44
|
+
|
45
|
+
def self.get
|
46
|
+
Cabin::Channel.get
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class NullLogger
|
51
|
+
[:debug, :info, :warn, :error, :fatal].each do |method|
|
52
|
+
define_method(method) do |*arguments|
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get
|
57
|
+
self.new
|
58
|
+
end
|
39
59
|
end
|
40
60
|
end
|
data/lib/sensu/process.rb
CHANGED
data/lib/sensu/redis.rb
CHANGED
data/lib/sensu/server.rb
CHANGED
@@ -14,7 +14,7 @@ module Sensu
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def initialize(options={})
|
17
|
-
@logger =
|
17
|
+
@logger = Sensu::Logger.get
|
18
18
|
base = Sensu::Base.new(options)
|
19
19
|
@settings = base.settings
|
20
20
|
@timers = Array.new
|
@@ -59,12 +59,16 @@ module Sensu
|
|
59
59
|
exit 2
|
60
60
|
end
|
61
61
|
@rabbitmq = AMQP.connect(@settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
62
|
+
@rabbitmq.logger = Sensu::NullLogger.get
|
62
63
|
@rabbitmq.on_tcp_connection_loss do |connection, settings|
|
63
64
|
@logger.warn('reconnecting to rabbitmq')
|
64
65
|
resign_as_master do
|
65
66
|
connection.reconnect(false, 10)
|
66
67
|
end
|
67
68
|
end
|
69
|
+
@rabbitmq.on_skipped_heartbeats do
|
70
|
+
@logger.warn('skipped rabbitmq heartbeat')
|
71
|
+
end
|
68
72
|
@amq = AMQP::Channel.new(@rabbitmq)
|
69
73
|
@amq.auto_recovery = true
|
70
74
|
end
|
@@ -86,17 +90,17 @@ module Sensu
|
|
86
90
|
def check_subdued?(check, subdue_at)
|
87
91
|
subdue = false
|
88
92
|
if check[:subdue].is_a?(Hash)
|
89
|
-
if check[:subdue].has_key?(:
|
90
|
-
|
93
|
+
if check[:subdue].has_key?(:begin) && check[:subdue].has_key?(:end)
|
94
|
+
begin_time = Time.parse(check[:subdue][:begin])
|
91
95
|
end_time = Time.parse(check[:subdue][:end])
|
92
|
-
if end_time <
|
96
|
+
if end_time < begin_time
|
93
97
|
if Time.now < end_time
|
94
|
-
|
98
|
+
begin_time = Time.parse('12:00:00 AM')
|
95
99
|
else
|
96
100
|
end_time = Time.parse('11:59:59 PM')
|
97
101
|
end
|
98
102
|
end
|
99
|
-
if Time.now >=
|
103
|
+
if Time.now >= begin_time && Time.now <= end_time
|
100
104
|
subdue = true
|
101
105
|
end
|
102
106
|
end
|
@@ -108,13 +112,12 @@ module Sensu
|
|
108
112
|
end
|
109
113
|
if subdue && check[:subdue].has_key?(:exceptions)
|
110
114
|
subdue = check[:subdue][:exceptions].none? do |exception|
|
111
|
-
Time.now >= Time.parse(exception[:
|
115
|
+
Time.now >= Time.parse(exception[:begin]) && Time.now <= Time.parse(exception[:end])
|
112
116
|
end
|
113
117
|
end
|
114
118
|
end
|
115
119
|
if subdue
|
116
|
-
(
|
117
|
-
(check[:subdue].has_key?(:at) && check[:subdue][:at].to_sym == subdue_at)
|
120
|
+
subdue_at == (check[:subdue][:at] || 'handler').to_sym
|
118
121
|
else
|
119
122
|
false
|
120
123
|
end
|
@@ -191,7 +194,7 @@ module Sensu
|
|
191
194
|
})
|
192
195
|
end
|
193
196
|
else
|
194
|
-
@logger.
|
197
|
+
@logger.warn('unknown mutator', {
|
195
198
|
:mutator => {
|
196
199
|
:name => handler[:mutator]
|
197
200
|
}
|
@@ -208,7 +211,8 @@ module Sensu
|
|
208
211
|
unless check_subdued?(event[:check], :handler)
|
209
212
|
handlers = check_handlers(event[:check])
|
210
213
|
handlers.each do |handler|
|
211
|
-
|
214
|
+
log_level = event[:check][:type] == 'metric' ? :debug : :info
|
215
|
+
@logger.send(log_level, 'handling event', {
|
212
216
|
:event => event,
|
213
217
|
:handler => handler
|
214
218
|
})
|
@@ -416,6 +420,21 @@ module Sensu
|
|
416
420
|
end
|
417
421
|
end
|
418
422
|
|
423
|
+
def publish_check_request(check)
|
424
|
+
payload = {
|
425
|
+
:name => check[:name],
|
426
|
+
:command => check[:command],
|
427
|
+
:issued => Time.now.to_i
|
428
|
+
}
|
429
|
+
@logger.info('publishing check request', {
|
430
|
+
:payload => payload,
|
431
|
+
:subscribers => check[:subscribers]
|
432
|
+
})
|
433
|
+
check[:subscribers].uniq.each do |exchange_name|
|
434
|
+
@amq.fanout(exchange_name).publish(payload.to_json)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
419
438
|
def setup_publisher
|
420
439
|
@logger.debug('scheduling check requests')
|
421
440
|
check_count = 0
|
@@ -427,17 +446,7 @@ module Sensu
|
|
427
446
|
interval = testing? ? 0.5 : check[:interval]
|
428
447
|
@master_timers << EM::PeriodicTimer.new(interval) do
|
429
448
|
unless check_subdued?(check, :publisher)
|
430
|
-
|
431
|
-
:name => check[:name],
|
432
|
-
:issued => Time.now.to_i
|
433
|
-
}
|
434
|
-
@logger.info('publishing check request', {
|
435
|
-
:payload => payload,
|
436
|
-
:subscribers => check[:subscribers]
|
437
|
-
})
|
438
|
-
check[:subscribers].uniq.each do |exchange_name|
|
439
|
-
@amq.fanout(exchange_name).publish(payload.to_json)
|
440
|
-
end
|
449
|
+
publish_check_request(check)
|
441
450
|
end
|
442
451
|
end
|
443
452
|
end
|
data/lib/sensu/settings.rb
CHANGED
@@ -3,7 +3,7 @@ module Sensu
|
|
3
3
|
attr_reader :indifferent_access, :loaded_env, :loaded_files
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@logger =
|
6
|
+
@logger = Sensu::Logger.get
|
7
7
|
@settings = Hash.new
|
8
8
|
[:checks, :handlers, :mutators].each do |key|
|
9
9
|
@settings[key] = Hash.new
|
@@ -224,12 +224,12 @@ module Sensu
|
|
224
224
|
:check => check
|
225
225
|
})
|
226
226
|
end
|
227
|
-
if check[:subdue].has_key?(:
|
227
|
+
if check[:subdue].has_key?(:begin) || check[:subdue].has_key?(:end)
|
228
228
|
begin
|
229
|
-
Time.parse(check[:subdue][:
|
229
|
+
Time.parse(check[:subdue][:begin])
|
230
230
|
Time.parse(check[:subdue][:end])
|
231
231
|
rescue
|
232
|
-
invalid('check subdue
|
232
|
+
invalid('check subdue begin & end times must be valid', {
|
233
233
|
:check => check
|
234
234
|
})
|
235
235
|
end
|
@@ -261,12 +261,12 @@ module Sensu
|
|
261
261
|
:check => check
|
262
262
|
})
|
263
263
|
end
|
264
|
-
if exception.has_key?(:
|
264
|
+
if exception.has_key?(:begin) || exception.has_key?(:end)
|
265
265
|
begin
|
266
|
-
Time.parse(exception[:
|
266
|
+
Time.parse(exception[:begin])
|
267
267
|
Time.parse(exception[:end])
|
268
268
|
rescue
|
269
|
-
invalid('check subdue exception
|
269
|
+
invalid('check subdue exception begin & end times must be valid', {
|
270
270
|
:check => check
|
271
271
|
})
|
272
272
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 62196227
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
9
|
- 7
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 0.9.7.beta.
|
11
|
+
- 4
|
12
|
+
version: 0.9.7.beta.4
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Sean Porter
|
@@ -18,7 +18,7 @@ autorequire:
|
|
18
18
|
bindir: bin
|
19
19
|
cert_chain: []
|
20
20
|
|
21
|
-
date: 2012-
|
21
|
+
date: 2012-09-19 00:00:00 -07:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -197,7 +197,6 @@ files:
|
|
197
197
|
- lib/sensu/client.rb
|
198
198
|
- lib/sensu/constants.rb
|
199
199
|
- lib/sensu/logger.rb
|
200
|
-
- lib/sensu/patches/ruby.rb
|
201
200
|
- lib/sensu/process.rb
|
202
201
|
- lib/sensu/redis.rb
|
203
202
|
- lib/sensu/server.rb
|