sensu 0.8.0 → 0.8.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/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  pkg/*
2
2
  *~
3
+ *.vagrant
3
4
  \#*
4
5
  dump.rdb
5
6
  .DS_Store
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ branches:
2
+ except:
3
+ - hacking
4
+ notifications:
5
+ irc:
6
+ - "irc.freenode.net#sensu"
7
+ env:
8
+ - RACK_ENV=development
9
+ rvm:
10
+ - 1.8.7
11
+ - 1.9.2
12
+ - 1.9.3
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sensu (0.8.0)
4
+ sensu (0.8.3)
5
5
  amqp (= 0.7.4)
6
6
  async_sinatra
7
+ cabin (= 0.1.7)
7
8
  em-hiredis
8
- em-syslog
9
9
  hashie
10
10
  json
11
11
  rack (~> 1.3.4)
@@ -20,32 +20,39 @@ GEM
20
20
  async_sinatra (0.5.0)
21
21
  rack (>= 1.2.1)
22
22
  sinatra (>= 1.0)
23
- callsite (0.0.6)
24
- bundler (~> 1.0.0)
23
+ bacon (1.1.0)
24
+ cabin (0.1.7)
25
+ json
25
26
  daemons (1.1.4)
27
+ diff-lcs (1.1.3)
26
28
  em-hiredis (0.1.0)
27
29
  hiredis (~> 0.3.0)
28
- em-syslog (0.0.2)
29
- eventmachine
30
- em-ventually (0.1.2)
31
- callsite (~> 0.0.5)
30
+ em-spec (0.2.5)
31
+ bacon
32
32
  eventmachine
33
+ rspec (~> 2.6.0)
34
+ test-unit
33
35
  eventmachine (0.12.10)
34
36
  hashie (1.2.0)
35
37
  hiredis (0.3.2)
36
38
  json (1.6.1)
37
- mime-types (1.16)
38
- minitest (2.7.0)
39
39
  rack (1.3.5)
40
40
  rack-protection (1.1.4)
41
41
  rack
42
42
  rake (0.9.2)
43
- rest-client (1.6.7)
44
- mime-types (>= 1.16)
43
+ rspec (2.6.0)
44
+ rspec-core (~> 2.6.0)
45
+ rspec-expectations (~> 2.6.0)
46
+ rspec-mocks (~> 2.6.0)
47
+ rspec-core (2.6.4)
48
+ rspec-expectations (2.6.0)
49
+ diff-lcs (~> 1.1.2)
50
+ rspec-mocks (2.6.0)
45
51
  sinatra (1.3.1)
46
52
  rack (~> 1.3, >= 1.3.4)
47
53
  rack-protection (~> 1.1, >= 1.1.2)
48
54
  tilt (~> 1.3, >= 1.3.3)
55
+ test-unit (2.4.0)
49
56
  thin (1.2.11)
50
57
  daemons (>= 1.0.9)
51
58
  eventmachine (>= 0.12.6)
@@ -57,8 +64,6 @@ PLATFORMS
57
64
  ruby
58
65
 
59
66
  DEPENDENCIES
60
- em-ventually
61
- minitest (~> 2.7.0)
67
+ em-spec
62
68
  rake
63
- rest-client
64
69
  sensu!
data/README.org CHANGED
@@ -1,28 +1,35 @@
1
1
  * Welcome to Sensu
2
- Sensu is a monitoring system framework.
2
+ Sensu, a monitoring framework that aims to be simple, malleable, and scalable.
3
3
 
4
4
  [[https://github.com/sonian/sensu/raw/master/sensu-logo.png]]
5
5
 
6
- Checks can utilize user created plugins, returning an exit status code and outputting to STDOUT.
6
+ [[http://portertech.ca/2011/11/01/sensu-a-monitoring-framework][Blog post]]
7
7
 
8
- Check results are handled by user created handlers, receiving JSON formatted event data from STDIN.
8
+ [[http://www.sonian.com/cloud-tools/cloud-monitoring-sensu/][Homepage]]
9
9
  * Documentation
10
- Documentation can be found [[https://github.com/sonian/sensu/wiki][HERE]].
10
+ Find it [[https://github.com/sonian/sensu/wiki][HERE]].
11
+ * Other Projects
12
+ - [[https://github.com/sonian/sensu-plugins][Sensu Community Plugins]]
13
+ - [[https://github.com/sonian/sensu-dashboard][Sensu Dashboard]]
11
14
  * License
12
15
  Sensu is released under the [[https://github.com/sonian/sensu/blob/master/MIT-LICENSE.txt][MIT license]].
13
16
  * Contributing
14
- - [[http://help.github.com/fork-a-repo/][Fork]] [[https://github.com/sonian/sensu][Sensu]]
17
+ - [[http://help.github.com/fork-a-repo/][Fork]] Sensu
15
18
  - Use a [[https://github.com/dchelimsky/rspec/wiki/Topic-Branches][topic branch]]
16
19
  - Create a [[http://help.github.com/send-pull-requests/][pull request]]
17
20
 
18
21
  Keep it simple.
19
22
  ** Testing
20
- *** Requirements
23
+ *** Travis CI
24
+ [[https://secure.travis-ci.org/sonian/sensu.png]]
25
+ *** System Dependencies
26
+ - Ruby (MRI) & Rubygems
21
27
  - RabbitMQ
22
28
  - Redis
23
29
  *** Running
24
30
  : bundle install
25
- : rake test
31
+ : rake
26
32
  * Contributors
27
- - Sean Porter ([[https://twitter.com/#!/portertech][@portertech]])
28
- - Justin Kolberg ([[https://twitter.com/#!/amdprophet][@amdprophet]])
33
+ - [[http://twitter.com/portertech][Sean Porter]]
34
+ - [[http://twitter.com/amdprophet][Justin Kolberg]]
35
+ - [[http://twitter.com/kartar][James Turnbull]]
data/bin/sensu-api CHANGED
@@ -6,4 +6,5 @@ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE_
6
6
  require 'sensu/api'
7
7
 
8
8
  options = Sensu::Config.read_arguments(ARGV)
9
+ options['type'] = 'api'
9
10
  Sensu::API.run(options)
data/bin/sensu-client CHANGED
@@ -4,4 +4,5 @@ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE_
4
4
  require 'sensu/client'
5
5
 
6
6
  options = Sensu::Config.read_arguments(ARGV)
7
+ options['type'] = 'client'
7
8
  Sensu::Client.run(options)
data/bin/sensu-server CHANGED
@@ -6,4 +6,5 @@ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE_
6
6
  require 'sensu/server'
7
7
 
8
8
  options = Sensu::Config.read_arguments(ARGV)
9
+ options['type'] = 'server'
9
10
  Sensu::Server.run(options)
data/lib/sensu.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sensu
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.4"
3
3
  end
data/lib/sensu/api.rb CHANGED
@@ -13,10 +13,7 @@ module Sensu
13
13
 
14
14
  %w[INT TERM].each do |signal|
15
15
  Signal.trap(signal) do
16
- EM.warning('[process] -- ' + signal + ' -- stopping sensu api')
17
- EM.add_timer(1) do
18
- EM.stop
19
- end
16
+ self.stop(signal)
20
17
  end
21
18
  end
22
19
  end
@@ -25,17 +22,19 @@ module Sensu
25
22
  def self.setup(options={})
26
23
  config = Sensu::Config.new(options)
27
24
  @settings = config.settings
28
- EM.syslog_setup(@settings.syslog.host, @settings.syslog.port)
29
- EM.debug('[setup] -- connecting to redis')
30
- set :redis, EM::Hiredis.connect('redis://' + @settings.redis.host + ':' + @settings.redis.port.to_s)
31
- EM.debug('[setup] -- connecting to rabbitmq')
25
+ $logger = config.logger
26
+ $logger.debug('[setup] -- connecting to redis')
27
+ $redis = EM::Hiredis.connect('redis://' + @settings.redis.host + ':' + @settings.redis.port.to_s)
28
+ $logger.debug('[setup] -- connecting to rabbitmq')
32
29
  connection = AMQP.connect(@settings.rabbitmq.to_hash.symbolize_keys)
33
- set :amq, MQ.new(connection)
30
+ $amq = MQ.new(connection)
34
31
  end
35
32
 
36
- helpers do
37
- include Rack::Utils
38
- alias_method :conn, :settings
33
+ def self.stop(signal)
34
+ $logger.warn('[process] -- ' + signal + ' -- stopping sensu api')
35
+ EM.add_timer(1) do
36
+ EM.stop
37
+ end
39
38
  end
40
39
 
41
40
  before do
@@ -43,12 +42,12 @@ module Sensu
43
42
  end
44
43
 
45
44
  aget '/clients' do
46
- EM.debug('[clients] -- ' + request.ip + ' -- GET -- request for client list')
45
+ $logger.debug('[clients] -- ' + request.ip + ' -- GET -- request for client list')
47
46
  current_clients = Array.new
48
- conn.redis.smembers('clients').callback do |clients|
47
+ $redis.smembers('clients').callback do |clients|
49
48
  unless clients.empty?
50
49
  clients.each_with_index do |client, index|
51
- conn.redis.get('client:' + client).callback do |client_json|
50
+ $redis.get('client:' + client).callback do |client_json|
52
51
  current_clients.push(JSON.parse(client_json))
53
52
  body current_clients.to_json if index == clients.size - 1
54
53
  end
@@ -60,34 +59,34 @@ module Sensu
60
59
  end
61
60
 
62
61
  aget '/client/:name' do |client|
63
- EM.debug('[client] -- ' + request.ip + ' -- GET -- request for client -- ' + client)
64
- conn.redis.get('client:' + client).callback do |client_json|
62
+ $logger.debug('[client] -- ' + request.ip + ' -- GET -- request for client -- ' + client)
63
+ $redis.get('client:' + client).callback do |client_json|
65
64
  status 404 if client_json.nil?
66
65
  body client_json
67
66
  end
68
67
  end
69
68
 
70
69
  adelete '/client/:name' do |client|
71
- EM.debug('[client] -- ' + request.ip + ' -- DELETE -- request for client -- ' + client)
72
- conn.redis.sismember('clients', client).callback do |client_exists|
70
+ $logger.debug('[client] -- ' + request.ip + ' -- DELETE -- request for client -- ' + client)
71
+ $redis.sismember('clients', client).callback do |client_exists|
73
72
  unless client_exists == 0
74
- conn.redis.exists('events:' + client).callback do |events_exist|
73
+ $redis.exists('events:' + client).callback do |events_exist|
75
74
  unless events_exist == 0
76
- conn.redis.hgetall('events:' + client).callback do |events|
75
+ $redis.hgetall('events:' + client).callback do |events|
77
76
  Hash[*events].keys.each do |check_name|
78
77
  check = {:name => check_name, :issued => Time.now.to_i, :status => 0, :output => 'Client is being removed'}
79
- conn.amq.queue('results').publish({:client => client, :check => check}.to_json)
78
+ $amq.queue('results').publish({:client => client, :check => check}.to_json)
80
79
  end
81
80
  EM.add_timer(5) do
82
- conn.redis.srem('clients', client)
83
- conn.redis.del('events:' + client)
84
- conn.redis.del('client:' + client)
81
+ $redis.srem('clients', client)
82
+ $redis.del('events:' + client)
83
+ $redis.del('client:' + client)
85
84
  end
86
85
  end
87
86
  else
88
- conn.redis.srem('clients', client)
89
- conn.redis.del('events:' + client)
90
- conn.redis.del('client:' + client)
87
+ $redis.srem('clients', client)
88
+ $redis.del('events:' + client)
89
+ $redis.del('client:' + client)
91
90
  end
92
91
  status 204
93
92
  body nil
@@ -100,12 +99,12 @@ module Sensu
100
99
  end
101
100
 
102
101
  aget '/events' do
103
- EM.debug('[events] -- ' + request.ip + ' -- GET -- request for event list')
102
+ $logger.debug('[events] -- ' + request.ip + ' -- GET -- request for event list')
104
103
  current_events = Hash.new
105
- conn.redis.smembers('clients').callback do |clients|
104
+ $redis.smembers('clients').callback do |clients|
106
105
  unless clients.empty?
107
106
  clients.each_with_index do |client, index|
108
- conn.redis.hgetall('events:' + client).callback do |events|
107
+ $redis.hgetall('events:' + client).callback do |events|
109
108
  client_events = Hash[*events]
110
109
  client_events.each do |key, value|
111
110
  client_events[key] = JSON.parse(value)
@@ -121,8 +120,8 @@ module Sensu
121
120
  end
122
121
 
123
122
  aget '/event/:client/:check' do |client, check|
124
- EM.debug('[event] -- ' + request.ip + ' -- GET -- request for event -- ' + client + ' -- ' + check)
125
- conn.redis.hgetall('events:' + client).callback do |events|
123
+ $logger.debug('[event] -- ' + request.ip + ' -- GET -- request for event -- ' + client + ' -- ' + check)
124
+ $redis.hgetall('events:' + client).callback do |events|
126
125
  client_events = Hash[*events]
127
126
  event = client_events[check]
128
127
  status 404 if event.nil?
@@ -131,21 +130,21 @@ module Sensu
131
130
  end
132
131
 
133
132
  apost '/stash/*' do |path|
134
- EM.debug('[stash] -- ' + request.ip + ' -- POST -- request for stash -- ' + path)
133
+ $logger.debug('[stash] -- ' + request.ip + ' -- POST -- request for stash -- ' + path)
135
134
  begin
136
135
  stash = JSON.parse(request.body.read)
137
136
  rescue JSON::ParserError
138
137
  status 400
139
138
  body nil
140
139
  end
141
- conn.redis.set('stash:' + path, stash.to_json).callback do
140
+ $redis.set('stash:' + path, stash.to_json).callback do
142
141
  status 201
143
142
  body nil
144
143
  end
145
144
  end
146
145
 
147
146
  apost '/stashes' do
148
- EM.debug('[stashes] -- ' + request.ip + ' -- POST -- request for multiple stashes')
147
+ $logger.debug('[stashes] -- ' + request.ip + ' -- POST -- request for multiple stashes')
149
148
  begin
150
149
  paths = JSON.parse(request.body.read)
151
150
  rescue JSON::ParserError
@@ -155,7 +154,7 @@ module Sensu
155
154
  stashes = Hash.new
156
155
  if paths.is_a?(Array)
157
156
  paths.each_with_index do |path, index|
158
- conn.redis.get('stash:' + path).callback do |stash|
157
+ $redis.get('stash:' + path).callback do |stash|
159
158
  stashes[path] = JSON.parse(stash) unless stash.nil?
160
159
  body stashes.to_json if index == paths.size - 1
161
160
  end
@@ -167,18 +166,18 @@ module Sensu
167
166
  end
168
167
 
169
168
  aget '/stash/*' do |path|
170
- EM.debug('[stash] -- ' + request.ip + ' -- GET -- request for stash -- ' + path)
171
- conn.redis.get('stash:' + path).callback do |stash|
169
+ $logger.debug('[stash] -- ' + request.ip + ' -- GET -- request for stash -- ' + path)
170
+ $redis.get('stash:' + path).callback do |stash|
172
171
  status 404 if stash.nil?
173
172
  body stash
174
173
  end
175
174
  end
176
175
 
177
176
  adelete '/stash/*' do |path|
178
- EM.debug('[stash] -- ' + request.ip + ' -- DELETE -- request for stash -- ' + path)
179
- conn.redis.exists('stash:' + path).callback do |stash_exist|
177
+ $logger.debug('[stash] -- ' + request.ip + ' -- DELETE -- request for stash -- ' + path)
178
+ $redis.exists('stash:' + path).callback do |stash_exist|
180
179
  unless stash_exist == 0
181
- conn.redis.del('stash:' + path).callback do
180
+ $redis.del('stash:' + path).callback do
182
181
  status 204
183
182
  body nil
184
183
  end
@@ -189,31 +188,21 @@ module Sensu
189
188
  end
190
189
  end
191
190
 
192
- apost '/test' do
193
- EM.debug('[test] -- ' + request.ip + ' -- POST -- seeding for minitest')
194
- client = '{
195
- "name": "test",
196
- "address": "localhost",
197
- "subscriptions": [
198
- "foo",
199
- "bar"
200
- ]
201
- }'
202
- conn.redis.set('client:test', client).callback do
203
- conn.redis.sadd('clients', 'test').callback do
204
- conn.redis.hset('events:test', 'test', {
191
+ def self.test(options={})
192
+ self.setup(options)
193
+ $redis.set('client:test', @settings.client).callback do
194
+ $redis.sadd('clients', @settings.client.name).callback do
195
+ $redis.hset('events:' + @settings.client.name, 'test', {
205
196
  :status => 2,
206
197
  :output => 'CRITICAL',
207
198
  :flapping => false,
208
199
  :occurrences => 1
209
200
  }.to_json).callback do
210
- conn.redis.set('stash:test/test', '{"key": "value"}').callback do
211
- status 201
212
- body nil
213
- end
201
+ $redis.set('stash:test/test', '{"key": "value"}')
214
202
  end
215
203
  end
216
204
  end
205
+ self.run!(:port => @settings.api.port)
217
206
  end
218
207
  end
219
208
  end
data/lib/sensu/client.rb CHANGED
@@ -13,34 +13,39 @@ module Sensu
13
13
 
14
14
  %w[INT TERM].each do |signal|
15
15
  Signal.trap(signal) do
16
- EM.warning('[process] -- ' + signal + ' -- stopping sensu client')
17
- EM.add_timer(1) do
18
- EM.stop
19
- end
16
+ client.stop(signal)
20
17
  end
21
18
  end
22
19
  end
23
20
  end
24
21
 
25
22
  def initialize(options={})
26
- config = Sensu::Config.new(:config_file => options[:config_file])
23
+ config = Sensu::Config.new(options)
27
24
  @settings = config.settings
28
- EM.syslog_setup(@settings.syslog.host, @settings.syslog.port)
25
+ @logger = config.logger
26
+ end
27
+
28
+ def stop(signal)
29
+ @logger.warn('[process] -- ' + signal + ' -- stopping sensu client')
30
+ EM.add_timer(1) do
31
+ EM.stop
32
+ end
29
33
  end
30
34
 
31
35
  def setup_amqp
32
- EM.debug("[amqp] -- connecting to rabbitmq")
36
+ @logger.debug('[amqp] -- connecting to rabbitmq')
33
37
  connection = AMQP.connect(@settings.rabbitmq.to_hash.symbolize_keys)
34
38
  @amq = MQ.new(connection)
35
39
  end
36
40
 
37
41
  def publish_keepalive
38
- EM.debug('[keepalive] -- publishing keepalive -- ' + @settings.client.timestamp.to_s)
42
+ @logger.debug('[keepalive] -- publishing keepalive -- ' + @settings.client.timestamp.to_s)
39
43
  @keepalive_queue ||= @amq.queue('keepalives')
40
44
  @keepalive_queue.publish(@settings.client.to_json)
41
45
  end
42
46
 
43
47
  def setup_keepalives
48
+ @logger.debug('[keepalive] -- setup keepalives')
44
49
  @settings.client.timestamp = Time.now.to_i
45
50
  publish_keepalive
46
51
  EM.add_periodic_timer(30) do
@@ -50,7 +55,7 @@ module Sensu
50
55
  end
51
56
 
52
57
  def publish_result(check)
53
- EM.info('[result] -- publishing check result -- ' + check.name)
58
+ @logger.info('[result] -- publishing check result -- ' + check.name)
54
59
  @result_queue ||= @amq.queue('results')
55
60
  @result_queue.publish({
56
61
  :client => @settings.client.name,
@@ -59,6 +64,7 @@ module Sensu
59
64
  end
60
65
 
61
66
  def execute_check(check)
67
+ @logger.debug('[execute] -- executing check -- ' + check.name)
62
68
  @checks_in_progress ||= Array.new
63
69
  if @settings.checks.key?(check.name)
64
70
  unless @checks_in_progress.include?(check.name)
@@ -82,7 +88,7 @@ module Sensu
82
88
  end
83
89
  EM.defer(execute, publish)
84
90
  else
85
- EM.warning('[execute] -- missing client attributes -- ' + unmatched_tokens.join(', ') + ' -- ' + check.name)
91
+ @logger.warn('[execute] -- missing client attributes -- ' + unmatched_tokens.join(', ') + ' -- ' + check.name)
86
92
  check.status = 3
87
93
  check.output = 'Missing client attributes: ' + unmatched_tokens.join(', ')
88
94
  check.internal = true
@@ -91,7 +97,7 @@ module Sensu
91
97
  end
92
98
  end
93
99
  else
94
- EM.warning('[execute] -- unkown check -- ' + check.name)
100
+ @logger.warn('[execute] -- unkown check -- ' + check.name)
95
101
  check.status = 3
96
102
  check.output = 'Unknown check'
97
103
  check.internal = true
@@ -101,22 +107,24 @@ module Sensu
101
107
  end
102
108
 
103
109
  def setup_subscriptions
110
+ @logger.debug('[subscribe] -- setup subscriptions')
104
111
  @check_queue = @amq.queue(UUIDTools::UUID.random_create.to_s, :exclusive => true)
105
112
  @settings.client.subscriptions.each do |exchange|
106
- EM.debug('[subscribe] -- queue binding to exchange -- ' + exchange)
113
+ @logger.debug('[subscribe] -- queue binding to exchange -- ' + exchange)
107
114
  @check_queue.bind(@amq.fanout(exchange))
108
115
  end
109
116
  @check_queue.subscribe do |check_json|
110
117
  check = Hashie::Mash.new(JSON.parse(check_json))
111
- EM.info('[subscribe] -- received check -- ' + check.name)
118
+ @logger.info('[subscribe] -- received check -- ' + check.name)
112
119
  execute_check(check)
113
120
  end
114
121
  end
115
122
 
116
123
  def setup_queue_monitor
124
+ @logger.debug('[monitor] -- setup queue monitor')
117
125
  EM.add_periodic_timer(5) do
118
126
  unless @check_queue.subscribed?
119
- EM.warning('[monitor] -- reconnecting to rabbitmq')
127
+ @logger.warn('[monitor] -- reconnecting to rabbitmq')
120
128
  @check_queue.delete
121
129
  EM.add_timer(1) do
122
130
  setup_subscriptions
@@ -126,8 +134,9 @@ module Sensu
126
134
  end
127
135
 
128
136
  def setup_socket
129
- EM.debug('[socket] -- starting up socket server')
137
+ @logger.debug('[socket] -- starting up socket server')
130
138
  EM.start_server('127.0.0.1', 3030, ClientSocket) do |socket|
139
+ socket.logger = @logger
131
140
  socket.client_name = @settings.client.name
132
141
  socket.result_queue = @amq.queue('results')
133
142
  end
@@ -135,35 +144,32 @@ module Sensu
135
144
  end
136
145
 
137
146
  class ClientSocket < EM::Connection
138
- attr_accessor :client_name, :result_queue
139
-
140
- def post_init
141
- EM.debug('[socket] -- client connected')
142
- end
147
+ attr_accessor :logger, :client_name, :result_queue
143
148
 
144
149
  def receive_data(data)
150
+ @logger.debug('[socket] -- client connected')
145
151
  begin
146
152
  check = Hashie::Mash.new(JSON.parse(data))
147
153
  validates = %w[name status output].all? do |key|
148
154
  check.key?(key)
149
155
  end
150
156
  if validates
151
- EM.info('[socket] -- publishing check result -- ' + check.name)
157
+ @logger.info('[socket] -- publishing check result -- ' + check.name)
152
158
  @result_queue.publish({
153
159
  :client => @client_name,
154
160
  :check => check.to_hash
155
161
  }.to_json)
156
162
  else
157
- EM.warning('[socket] -- a check name, exit status, and output are required -- e.g. {name: x, status: 0, output: "y"}')
163
+ @logger.warn('[socket] -- a check name, exit status, and output are required -- e.g. {name: x, status: 0, output: "y"}')
158
164
  end
159
165
  rescue JSON::ParserError
160
- EM.warning('[socket] -- could not parse check result -- expecting JSON')
166
+ @logger.warn('[socket] -- could not parse check result -- expecting JSON')
161
167
  end
162
168
  close_connection
163
169
  end
164
170
 
165
171
  def unbind
166
- EM.debug('[socket] -- client disconnected')
172
+ @logger.debug('[socket] -- client disconnected')
167
173
  end
168
174
  end
169
175
  end
data/lib/sensu/config.rb CHANGED
@@ -4,42 +4,83 @@ require 'json'
4
4
  require 'hashie'
5
5
  require 'uuidtools'
6
6
  require 'amqp'
7
- require 'em/syslog'
7
+ require 'cabin'
8
+ require 'cabin/outputs/em-stdlib-logger'
8
9
  require File.join(File.dirname(__FILE__), 'helpers')
9
10
 
10
11
  module Sensu
11
12
  class Config
12
- attr_accessor :settings
13
+ attr_accessor :settings, :logger
13
14
 
14
15
  def initialize(options={})
15
16
  config_file = options[:config_file] || '/etc/sensu/config.json'
16
- @settings = Hashie::Mash.new(JSON.parse(File.open(config_file, 'r').read))
17
- validate_config
17
+ if File.readable?(config_file)
18
+ begin
19
+ @settings = Hashie::Mash.new(JSON.parse(File.open(config_file, 'r').read))
20
+ rescue JSON::ParserError => e
21
+ invalid_config('configuration file must be valid JSON: ' + e)
22
+ end
23
+ else
24
+ invalid_config('configuration file does not exist or is not readable: ' + config_file)
25
+ end
26
+ @logger = Cabin::Channel.new
27
+ log_dir = File.writable?('/var/log') ? '/var/log' : '/tmp'
28
+ ruby_logger = Logger.new(File.join(log_dir, 'sensu.log'))
29
+ @logger.subscribe(Cabin::Outputs::EmStdlibLogger.new(ruby_logger))
30
+ @logger.level = options[:verbose] ? 'debug' : 'info'
31
+ validate_config(options['type'])
18
32
  end
19
33
 
20
- def validate_config
34
+ def validate_config(type)
35
+ @logger.debug('[config] -- validating configuration')
36
+ has_keys(%w[rabbitmq])
37
+ case type
38
+ when 'server'
39
+ has_keys(%w[redis handlers checks])
40
+ when 'api'
41
+ has_keys(%w[redis api])
42
+ when 'client'
43
+ has_keys(%w[client checks])
44
+ end
21
45
  @settings.checks.each do |name, details|
22
46
  unless details.interval.is_a?(Integer) && details.interval > 0
23
- raise 'configuration invalid, missing interval for check ' + name
47
+ invalid_config('missing interval for check ' + name)
24
48
  end
25
49
  unless details.command.is_a?(String)
26
- raise 'configuration invalid, missing command for check ' + name
50
+ invalid_config('missing command for check ' + name)
27
51
  end
28
52
  unless details.subscribers.is_a?(Array) && details.subscribers.count > 0
29
- raise 'configuration invalid, missing subscribers for check ' + name
53
+ invalid_config('missing subscribers for check ' + name)
30
54
  end
31
55
  end
32
56
  unless @settings.client.name.is_a?(String)
33
- raise 'configuration invalid, client must have a name'
57
+ invalid_config('client must have a name')
34
58
  end
35
59
  unless @settings.client.address.is_a?(String)
36
- raise 'configuration invalid, client must have an address (ip or hostname)'
60
+ invalid_config('client must have an address (ip or hostname)')
37
61
  end
38
62
  unless @settings.client.subscriptions.is_a?(Array) && @settings.client.subscriptions.count > 0
39
- raise 'configuration invalid, client must have subscriptions'
63
+ invalid_config('client must have subscriptions')
64
+ end
65
+ if type
66
+ @logger.debug('[config] -- configuration valid -- running ' + type)
67
+ puts 'configuration valid -- running ' + type
40
68
  end
41
69
  end
42
70
 
71
+ def has_keys(keys)
72
+ keys.each do |key|
73
+ unless @settings.key?(key)
74
+ invalid_config('missing the following key: ' + key)
75
+ end
76
+ end
77
+ end
78
+
79
+ def invalid_config(message)
80
+ @logger.error('[config] -- configuration invalid -- ' + message)
81
+ raise 'configuration invalid, ' + message
82
+ end
83
+
43
84
  def self.read_arguments(arguments)
44
85
  options = Hash.new
45
86
  optparse = OptionParser.new do |opts|
@@ -54,10 +95,12 @@ module Sensu
54
95
  options[:worker] = true
55
96
  end
56
97
  end
57
- options[:config_file] = nil
58
98
  opts.on('-c', '--config FILE', 'Sensu JSON config FILE (default: /etc/sensu/config.json)') do |file|
59
99
  options[:config_file] = file
60
100
  end
101
+ opts.on('-v', '--verbose', 'Enable verbose logging') do
102
+ options[:verbose] = true
103
+ end
61
104
  end
62
105
  optparse.parse!(arguments)
63
106
  options
data/lib/sensu/server.rb CHANGED
@@ -21,38 +21,43 @@ module Sensu
21
21
 
22
22
  %w[INT TERM].each do |signal|
23
23
  Signal.trap(signal) do
24
- EM.warning('[process] -- ' + signal + ' -- stopping sensu server')
25
- EM.add_timer(1) do
26
- EM.stop
27
- end
24
+ server.stop(signal)
28
25
  end
29
26
  end
30
27
  end
31
28
  end
32
29
 
33
30
  def initialize(options={})
34
- config = Sensu::Config.new(:config_file => options[:config_file])
31
+ config = Sensu::Config.new(options)
35
32
  @settings = config.settings
33
+ @logger = config.logger
36
34
  @is_worker = options[:worker]
37
- EM.syslog_setup(@settings.syslog.host, @settings.syslog.port)
35
+ end
36
+
37
+ def stop(signal)
38
+ @logger.warn('[process] -- ' + signal + ' -- stopping sensu server')
39
+ EM.add_timer(1) do
40
+ EM.stop
41
+ end
38
42
  end
39
43
 
40
44
  def setup_redis
41
- EM.debug('[redis] -- connecting to redis')
45
+ @logger.debug('[redis] -- connecting to redis')
42
46
  @redis = EM::Hiredis.connect('redis://' + @settings.redis.host + ':' + @settings.redis.port.to_s)
43
47
  end
44
48
 
45
49
  def setup_amqp
46
- EM.debug('[amqp] -- connecting to rabbitmq')
50
+ @logger.debug('[amqp] -- connecting to rabbitmq')
47
51
  connection = AMQP.connect(@settings.rabbitmq.to_hash.symbolize_keys)
48
52
  @amq = MQ.new(connection)
49
53
  end
50
54
 
51
55
  def setup_keepalives
56
+ @logger.debug('[keepalive] -- setup keepalive')
52
57
  @keepalive_queue = @amq.queue('keepalives')
53
58
  @keepalive_queue.subscribe do |keepalive_json|
54
59
  client = Hashie::Mash.new(JSON.parse(keepalive_json))
55
- EM.debug('[keepalive] -- received keepalive -- ' + client.name)
60
+ @logger.debug('[keepalive] -- received keepalive -- ' + client.name)
56
61
  @redis.set('client:' + client.name, keepalive_json).callback do
57
62
  @redis.sadd('clients', client.name)
58
63
  end
@@ -71,18 +76,19 @@ module Sensu
71
76
  end
72
77
  report = proc do |output|
73
78
  output.split(/\n+/).each do |line|
74
- EM.info('[handler] -- ' + line)
79
+ @logger.info('[handler] -- ' + line)
75
80
  end
76
81
  end
77
82
  if @settings.handlers.key?(event.check.handler)
78
- EM.debug('[event] -- handling event -- ' + [event.check.handler, event.client.name, event.check.name].join(' -- '))
83
+ @logger.debug('[event] -- handling event -- ' + [event.check.handler, event.client.name, event.check.name].join(' -- '))
79
84
  EM.defer(handler, report)
80
85
  else
81
- EM.warning('[event] -- handler does not exist -- ' + event.check.handler)
86
+ @logger.warn('[event] -- handler does not exist -- ' + event.check.handler)
82
87
  end
83
88
  end
84
89
 
85
90
  def process_result(result)
91
+ @logger.debug('[result] -- processing result for ' + [result.client, result.check.name].join(' -- '))
86
92
  @redis.get('client:' + result.client).callback do |client_json|
87
93
  unless client_json.nil?
88
94
  client = Hashie::Mash.new(JSON.parse(client_json))
@@ -136,7 +142,7 @@ module Sensu
136
142
  end
137
143
  end
138
144
  else
139
- EM.debug('[result] -- check is flapping -- ' + client.name + ' -- ' + check.name)
145
+ @logger.debug('[result] -- check is flapping -- ' + client.name + ' -- ' + check.name)
140
146
  @redis.hset('events:' + client.name, check.name, previous_event.merge({'flapping' => true}).to_json)
141
147
  end
142
148
  elsif check['status'] != 0
@@ -165,15 +171,17 @@ module Sensu
165
171
  end
166
172
 
167
173
  def setup_results
174
+ @logger.debug('[result] -- setup results')
168
175
  @result_queue = @amq.queue('results')
169
176
  @result_queue.subscribe do |result_json|
170
177
  result = Hashie::Mash.new(JSON.parse(result_json))
171
- EM.info('[result] -- received result -- ' + result.client + ' -- ' + result.check.name)
178
+ @logger.info('[result] -- received result -- ' + result.client + ' -- ' + result.check.name)
172
179
  process_result(result)
173
180
  end
174
181
  end
175
182
 
176
183
  def setup_publisher(options={})
184
+ @logger.debug('[publisher] -- setup publisher')
177
185
  exchanges = Hash.new
178
186
  stagger = options[:test] ? 0 : 7
179
187
  @settings.checks.each_with_index do |(name, details), index|
@@ -185,7 +193,7 @@ module Sensu
185
193
  end
186
194
  interval = options[:test] ? 0.5 : details.interval
187
195
  EM.add_periodic_timer(interval) do
188
- EM.info('[publisher] -- publishing check -- ' + name + ' -- ' + exchange)
196
+ @logger.info('[publisher] -- publishing check -- ' + name + ' -- ' + exchange)
189
197
  exchanges[exchange].publish({'name' => name, 'issued' => Time.now.to_i}.to_json)
190
198
  end
191
199
  end
@@ -195,8 +203,9 @@ module Sensu
195
203
  end
196
204
 
197
205
  def setup_keepalive_monitor
206
+ @logger.debug('[keepalive] -- setup keepalive monitor')
198
207
  EM.add_periodic_timer(30) do
199
- EM.debug('[keepalive] -- checking for stale clients')
208
+ @logger.debug('[keepalive] -- checking for stale clients')
200
209
  @redis.smembers('clients').callback do |clients|
201
210
  clients.each do |client_id|
202
211
  @redis.get('client:' + client_id).callback do |client_json|
@@ -234,13 +243,14 @@ module Sensu
234
243
  end
235
244
 
236
245
  def setup_queue_monitor
246
+ @logger.debug('[monitor] -- setup queue monitor')
237
247
  EM.add_periodic_timer(5) do
238
248
  unless @keepalive_queue.subscribed?
239
- EM.warning('[monitor] -- reconnecting to rabbitmq')
249
+ @logger.warn('[monitor] -- reconnecting to rabbitmq')
240
250
  setup_keepalives
241
251
  end
242
252
  unless @result_queue.subscribed?
243
- EM.warning('[monitor] -- reconnecting to rabbitmq')
253
+ @logger.warn('[monitor] -- reconnecting to rabbitmq')
244
254
  setup_results
245
255
  end
246
256
  end
data/sensu.gemspec CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |s|
7
7
  s.authors = ["Sean Porter", "Justin Kolberg"]
8
8
  s.email = ["sean.porter@sonian.net", "justin.kolberg@sonian.net"]
9
9
  s.homepage = "https://github.com/sonian/sensu"
10
- s.summary = %q{A server monitoring framework}
11
- s.description = %q{A server monitoring framework using the publish-subscribe model}
10
+ s.summary = %q{A monitoring framework}
11
+ s.description = %q{A monitoring framework that aims to be simple, malleable, and scalable. Uses the publish/subscribe model.}
12
12
  s.license = "MIT"
13
13
  s.has_rdoc = false
14
14
 
@@ -16,16 +16,14 @@ Gem::Specification.new do |s|
16
16
  s.add_dependency("json")
17
17
  s.add_dependency("hashie")
18
18
  s.add_dependency("uuidtools")
19
- s.add_dependency("em-syslog")
19
+ s.add_dependency("cabin", "0.1.7")
20
20
  s.add_dependency("em-hiredis")
21
21
  s.add_dependency("rack", "~> 1.3.4")
22
22
  s.add_dependency("async_sinatra")
23
23
  s.add_dependency("thin")
24
24
 
25
25
  s.add_development_dependency("rake")
26
- s.add_development_dependency("minitest", "~> 2.7.0")
27
- s.add_development_dependency("em-ventually")
28
- s.add_development_dependency("rest-client")
26
+ s.add_development_dependency("em-spec")
29
27
 
30
28
  s.files = `git ls-files`.split("\n").reject {|f| f =~ /(dist|test|png)/}
31
29
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
data/sensu.windows CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
6
6
  s.authors = ["Sean Porter", "Justin Kolberg"]
7
7
  s.email = ["sean.porter@sonian.net", "justin.kolberg@sonian.net"]
8
8
  s.homepage = "https://github.com/sonian/sensu"
9
- s.summary = %q{A server monitoring framework}
10
- s.description = %q{A server monitoring framework using the publish-subscribe model}
9
+ s.summary = %q{A monitoring framework}
10
+ s.description = %q{A monitoring framework that aims to be simple, malleable, and scalable. Uses the publish/subscribe model.}
11
11
  s.license = "MIT"
12
12
  s.has_rdoc = false
13
13
 
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency("json")
24
24
  s.add_dependency("hashie")
25
25
  s.add_dependency("uuidtools")
26
- s.add_dependency("em-syslog")
26
+ s.add_dependency("cabin", "0.1.7")
27
27
 
28
28
  s.files = `git ls-files`.split("\n").reject {|f| f =~ /(dist|test|server|api|png)/}
29
29
  s.executables = "sensu-client"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 55
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 0
10
- version: 0.8.0
9
+ - 4
10
+ version: 0.8.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sean Porter
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-10-31 00:00:00 -07:00
19
+ date: 2011-11-09 00:00:00 -08:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -78,17 +78,19 @@ dependencies:
78
78
  type: :runtime
79
79
  version_requirements: *id004
80
80
  - !ruby/object:Gem::Dependency
81
- name: em-syslog
81
+ name: cabin
82
82
  prerelease: false
83
83
  requirement: &id005 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
- - - ">="
86
+ - - "="
87
87
  - !ruby/object:Gem::Version
88
- hash: 3
88
+ hash: 21
89
89
  segments:
90
90
  - 0
91
- version: "0"
91
+ - 1
92
+ - 7
93
+ version: 0.1.7
92
94
  type: :runtime
93
95
  version_requirements: *id005
94
96
  - !ruby/object:Gem::Dependency
@@ -164,25 +166,9 @@ dependencies:
164
166
  type: :development
165
167
  version_requirements: *id010
166
168
  - !ruby/object:Gem::Dependency
167
- name: minitest
169
+ name: em-spec
168
170
  prerelease: false
169
171
  requirement: &id011 !ruby/object:Gem::Requirement
170
- none: false
171
- requirements:
172
- - - ~>
173
- - !ruby/object:Gem::Version
174
- hash: 19
175
- segments:
176
- - 2
177
- - 7
178
- - 0
179
- version: 2.7.0
180
- type: :development
181
- version_requirements: *id011
182
- - !ruby/object:Gem::Dependency
183
- name: em-ventually
184
- prerelease: false
185
- requirement: &id012 !ruby/object:Gem::Requirement
186
172
  none: false
187
173
  requirements:
188
174
  - - ">="
@@ -192,22 +178,8 @@ dependencies:
192
178
  - 0
193
179
  version: "0"
194
180
  type: :development
195
- version_requirements: *id012
196
- - !ruby/object:Gem::Dependency
197
- name: rest-client
198
- prerelease: false
199
- requirement: &id013 !ruby/object:Gem::Requirement
200
- none: false
201
- requirements:
202
- - - ">="
203
- - !ruby/object:Gem::Version
204
- hash: 3
205
- segments:
206
- - 0
207
- version: "0"
208
- type: :development
209
- version_requirements: *id013
210
- description: A server monitoring framework using the publish-subscribe model
181
+ version_requirements: *id011
182
+ description: A monitoring framework that aims to be simple, malleable, and scalable. Uses the publish/subscribe model.
211
183
  email:
212
184
  - sean.porter@sonian.net
213
185
  - justin.kolberg@sonian.net
@@ -221,6 +193,7 @@ extra_rdoc_files: []
221
193
 
222
194
  files:
223
195
  - .gitignore
196
+ - .travis.yml
224
197
  - Gemfile
225
198
  - Gemfile.lock
226
199
  - MIT-LICENSE.txt
@@ -270,6 +243,6 @@ rubyforge_project:
270
243
  rubygems_version: 1.3.7
271
244
  signing_key:
272
245
  specification_version: 3
273
- summary: A server monitoring framework
246
+ summary: A monitoring framework
274
247
  test_files: []
275
248