reacter 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
1
  #------------------------------------------------------------------------------#
2
2
  # Adapter
3
3
  #
4
+ require 'eventmachine'
4
5
  require 'reacter/message'
5
6
  require 'reacter/config'
6
7
  require 'reacter/util'
@@ -6,24 +6,17 @@ require 'reacter/agent'
6
6
  class Reacter
7
7
  class DeciderAgent < Agent
8
8
  class EmitAlert < Exception; end
9
-
10
9
  # local memory persistence mechanism for state tracking
11
10
  class MemoryPersist
12
11
  class<<self
13
- def setup()
12
+ def setup(config={})
14
13
  @_alerts = {}
15
14
  end
16
15
 
17
16
  def init(source, metric)
18
17
  # initialize in-memory alert tracking (per source, per metric)
19
18
  @_alerts[source] ||= {}
20
- @_alerts[source][metric] ||= ({
21
- :count => 1,
22
- :last_state => nil,
23
- :last_seen => nil,
24
- :new_alert => false,
25
- :has_ever_failed => false
26
- })
19
+ @_alerts[source][metric] ||= DEFAULT_PERSISTENCE_OBJECT
27
20
  end
28
21
 
29
22
  def get(source, metric, key)
@@ -38,18 +31,38 @@ class Reacter
38
31
 
39
32
  # redis persistence mechanism for shared state tracking
40
33
  class RedisPersist
41
- #require 'redis'
34
+ require 'redis'
35
+ require 'hiredis'
36
+ require 'msgpack'
37
+
42
38
  class<<self
43
- def setup()
39
+ def setup(config={})
40
+ @_redis = Redis.new({
41
+ :host => config.get(:host),
42
+ :port => config.get(:port),
43
+ :path => config.get(:socket),
44
+ :driver => config.get(:driver, :hiredis).to_sym
45
+ })
46
+
47
+ @_ttl = config.get('ttl', 600)
44
48
  end
45
49
 
46
50
  def init(source, metric)
51
+ DEFAULT_PERSISTENCE_OBJECT.each do |key, value|
52
+ @_redis.multi do
53
+ @_redis.set("#{source}:#{metric}:#{key}", value.to_msgpack)
54
+ end
55
+ end
47
56
  end
48
57
 
49
58
  def get(source, metric, key)
59
+ MessagePack.unpack(@_redis.get("#{source}:#{metric}:#{key}"))
50
60
  end
51
61
 
52
62
  def set(source, metric, key, value)
63
+ k = "#{source}:#{metric}:#{key}"
64
+ @_redis.set(k, value.to_msgpack)
65
+ @_redis.expire(k, @_ttl)
53
66
  end
54
67
  end
55
68
  end
@@ -57,6 +70,14 @@ class Reacter
57
70
  STATES=[:okay, :warning, :critical]
58
71
  COMPARISONS=%w{not is above below}
59
72
  DEFAULT_PERSISTENCE='memory'
73
+ DEFAULT_PERSISTENCE_OBJECT=({
74
+ :count => 1,
75
+ :last_state => nil,
76
+ :last_seen => nil,
77
+ :new_alert => false,
78
+ :has_ever_failed => false,
79
+ :total_value => nil
80
+ })
60
81
 
61
82
  def initialize()
62
83
  super
@@ -67,7 +88,7 @@ class Reacter
67
88
  end
68
89
 
69
90
  @_persistence = DeciderAgent.const_get(@config.get('options.persistence.type', DEFAULT_PERSISTENCE).capitalize+'Persist')
70
- @_persistence.setup()
91
+ @_persistence.setup(@config.get('options.persistence', {}))
71
92
  end
72
93
 
73
94
  def received(message)
@@ -5,8 +5,31 @@ require 'reacter/agent'
5
5
 
6
6
  class Reacter
7
7
  class LoggerAgent < Agent
8
+ def initialize()
9
+ super
10
+
11
+ case @config.get(:file, 'stdout')
12
+ when 'stderr'
13
+ @stream = STDERR
14
+ when 'stdout'
15
+ @stream = STDOUT
16
+ else
17
+ @stream = File.open(File.expand_path(@config.get(:file)), 'a+')
18
+ end
19
+
20
+ @output_format = @config.get(:format)
21
+ end
22
+
8
23
  def received(message)
9
- Util.info("logger: [#{message.state or :unknown}] #{message.source}/#{message.metric}")
24
+ if @output_format.nil?
25
+ line = "logger: [#{message.state or :unknown}] #{message.source}/#{message.metric} = #{message.value}"
26
+ else
27
+ line = Message.dump(message, @output_format)
28
+ end
29
+
30
+ @stream.puts(line)
31
+ @stream.flush()
32
+
10
33
  message
11
34
  end
12
35
  end
data/lib/reacter/core.rb CHANGED
@@ -13,7 +13,7 @@ class Reacter
13
13
  super
14
14
 
15
15
  @_dispatch_queue = EM::Queue.new
16
- @_adapter = nil
16
+ @_adapters = []
17
17
  @_agents = []
18
18
 
19
19
  Reacter.load_config(args.first || {})
@@ -26,15 +26,18 @@ class Reacter
26
26
  adapter_config = Reacter.get('global.adapter', nil)
27
27
 
28
28
  if adapter_config
29
- type = adapter_config.get('type')
29
+ adapter_config = [adapter_config] if adapter_config.is_a?(Hash)
30
30
 
31
- @_adapter = Adapter.create(type)
31
+ adapter_config.each do |adapter|
32
+ type = adapter.get('type')
32
33
 
33
- if @_adapter
34
- @_adapter.connect()
35
- else
36
- raise "Adapter '#{type}' not found, exiting"
37
- exit 1
34
+ if (instance = Adapter.create(type, adapter))
35
+ instance.connect()
36
+ @_adapters << instance
37
+ else
38
+ raise "Adapter '#{type}' not found, exiting"
39
+ exit 1
40
+ end
38
41
  end
39
42
  else
40
43
  Util.fatal("No adapters specified, exiting")
@@ -55,8 +58,9 @@ class Reacter
55
58
  end
56
59
 
57
60
  def run()
58
- Util.info("Start listening using #{@_adapter.type} adapter...")
59
-
61
+ @_adapters.each do |adapter|
62
+ Util.info("Start listening using #{adapter.type} adapter...")
63
+ end
60
64
 
61
65
  # agent message dispatch subprocess
62
66
  dispatch = proc do |messages|
@@ -73,9 +77,14 @@ class Reacter
73
77
 
74
78
  # enter polling loop
75
79
  begin
76
- @_adapter.poll do |messages|
77
- @_dispatch_queue.push(messages)
78
- @_dispatch_queue.pop(dispatch)
80
+ @_adapters.each do |adapter|
81
+ poller = proc do
82
+ adapter.poll do |messages|
83
+ dispatch.call(messages)
84
+ end
85
+ end
86
+
87
+ EM.defer(poller)
79
88
  end
80
89
 
81
90
  rescue AdapterConnectionFailed => e
@@ -40,6 +40,10 @@ class Reacter
40
40
  end
41
41
 
42
42
  class<<self
43
+ def format=(format)
44
+ @_format = format
45
+ end
46
+
43
47
  def load_parsers()
44
48
  unless defined?(@@_parsers)
45
49
  @@_parsers = {}
@@ -57,7 +61,7 @@ class Reacter
57
61
  load_parsers() unless defined?(@@_parsers)
58
62
 
59
63
  if @@_parsers
60
- format = DEFAULT_FORMAT unless format
64
+ format = (@_format or DEFAULT_FORMAT) unless format
61
65
 
62
66
  if @@_parsers.has_key?(format.to_sym)
63
67
  return @@_parsers[format.to_sym].dump(message)
@@ -67,35 +71,48 @@ class Reacter
67
71
  return nil
68
72
  end
69
73
 
70
- def parse(body)
74
+ def parse(body, format=nil)
71
75
  load_parsers()
72
76
 
77
+ # set format override if one was set
78
+ format = @_format unless format
79
+
73
80
  # split strings into lines
74
81
  body = body.lines if body.is_a?(String)
75
82
  messages = []
76
83
 
77
- if body.respond_to?(:each)
78
- body.each do |message|
79
- # strings need to be detected and parsed
80
- if message.is_a?(String)
81
- next if message.strip.chomp.empty?
82
-
83
- # use first parser that claims it can handle this string
84
- @@_parsers.each do |name, parser|
85
- if parser.detected?(message)
86
- #Util.debug("Using parser #{name}")
87
- m = parser.parse(message)
88
- (m.is_a?(Array) ? messages += m : messages << m)
89
- next
84
+ # format not specified, autodetect
85
+ if format.nil?
86
+ if body.respond_to?(:each)
87
+ body.each do |message|
88
+ # strings need to be detected and parsed
89
+ if message.is_a?(String)
90
+ next if message.strip.chomp.empty?
91
+
92
+ # use first parser that claims it can handle this string
93
+ @@_parsers.each do |name, parser|
94
+ if parser.detected?(message)
95
+ #Util.debug("Using parser #{name}")
96
+ m = parser.parse(message)
97
+ (m.is_a?(Array) ? messages += m : messages << m)
98
+ next
99
+ end
90
100
  end
91
- end
92
101
 
93
- # hashes go directly into the stack
94
- elsif message.is_a?(Hash)
95
- messages << message
102
+ # hashes go directly into the stack
103
+ elsif message.is_a?(Hash)
104
+ messages << message
105
+ end
96
106
  end
97
107
  end
98
-
108
+ else
109
+ # format given, attempt to use it
110
+ begin
111
+ m = @@_parsers[format].parse(message)
112
+ (m.is_a?(Array) ? messages += m : messages << m)
113
+ rescue
114
+ raise "Error parsing format '#{format}'"
115
+ end
99
116
  end
100
117
 
101
118
  messages.collect{|i| Message.new(i) }
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reacter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Gary Hetzel
@@ -12,46 +13,37 @@ date: 2013-03-18 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: eventmachine
15
- requirement: !ruby/object:Gem::Requirement
16
+ requirement: &9815500 !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '>='
25
- - !ruby/object:Gem::Version
26
- version: '0'
24
+ version_requirements: *9815500
27
25
  - !ruby/object:Gem::Dependency
28
26
  name: deep_merge
29
- requirement: !ruby/object:Gem::Requirement
27
+ requirement: &9813980 !ruby/object:Gem::Requirement
28
+ none: false
30
29
  requirements:
31
- - - '>='
30
+ - - ! '>='
32
31
  - !ruby/object:Gem::Version
33
32
  version: '0'
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
35
+ version_requirements: *9813980
41
36
  - !ruby/object:Gem::Dependency
42
37
  name: hashlib
43
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &9813340 !ruby/object:Gem::Requirement
39
+ none: false
44
40
  requirements:
45
- - - '>='
41
+ - - ! '>='
46
42
  - !ruby/object:Gem::Version
47
43
  version: '0'
48
44
  type: :runtime
49
45
  prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
46
+ version_requirements: *9813340
55
47
  description: A utility for consuming, transforming, and routing monitoring data from
56
48
  various sources
57
49
  email: ghetzel@outbrain.com
@@ -80,25 +72,26 @@ files:
80
72
  - bin/reacter
81
73
  homepage: http://outbrain.github.com/reacter/
82
74
  licenses: []
83
- metadata: {}
84
75
  post_install_message:
85
76
  rdoc_options: []
86
77
  require_paths:
87
78
  - lib
88
79
  required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
89
81
  requirements:
90
- - - '>='
82
+ - - ! '>='
91
83
  - !ruby/object:Gem::Version
92
84
  version: '0'
93
85
  required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
94
87
  requirements:
95
- - - '>='
88
+ - - ! '>='
96
89
  - !ruby/object:Gem::Version
97
90
  version: '0'
98
91
  requirements: []
99
92
  rubyforge_project:
100
- rubygems_version: 2.0.0
93
+ rubygems_version: 1.8.11
101
94
  signing_key:
102
- specification_version: 4
95
+ specification_version: 3
103
96
  summary: Reacter monitoring processor
104
97
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 7174eaf70cf7ce3c97eee6d272710eb0be8a85fd
4
- data.tar.gz: 55627a20739dcb898e1815b5b79c895186b0bbe1
5
- SHA512:
6
- metadata.gz: b7477ce807b0b94a396a2abc35ec741c0bd7c57c6a833314e9dad6354b3f7de40b15ae5f04d3a4ff11acb5103ecab91361fdab7b9e81ce348e57a4af682144ee
7
- data.tar.gz: fc26e258fac195b3a259dc1789ac35a72a9e277b8616d117cd921afeb850e2415b2e0a183b2a497e1d629305cc9ec4d6be483434c01dc56a0c999504de3d655d