reacter 0.0.4 → 0.0.5

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.
@@ -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