sensu 0.8.0 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
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