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.
- data/lib/reacter/adapter.rb +1 -0
- data/lib/reacter/agents/decider.rb +33 -12
- data/lib/reacter/agents/logger.rb +24 -1
- data/lib/reacter/core.rb +22 -13
- data/lib/reacter/message.rb +37 -20
- metadata +20 -27
- checksums.yaml +0 -7
data/lib/reacter/adapter.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
29
|
+
adapter_config = [adapter_config] if adapter_config.is_a?(Hash)
|
30
30
|
|
31
|
-
|
31
|
+
adapter_config.each do |adapter|
|
32
|
+
type = adapter.get('type')
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
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
|
-
@
|
77
|
-
|
78
|
-
|
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
|
data/lib/reacter/message.rb
CHANGED
@@ -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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
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
|
+
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:
|
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:
|
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:
|
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:
|
93
|
+
rubygems_version: 1.8.11
|
101
94
|
signing_key:
|
102
|
-
specification_version:
|
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
|