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