@@ -11,6 +11,8 @@ module Agents |
||
11 | 11 |
|
12 | 12 |
The `type` can be one of #{VALID_COMPARISON_TYPES.map { |t| "`#{t}`" }.to_sentence} and compares with the `value`. |
13 | 13 |
|
14 |
+ The `value` can be a single value or an array of values. In the case of an array, if one or more values match then the rule matches. |
|
15 |
+ |
|
14 | 16 |
All rules must match for the Agent to match. The resulting Event will have a payload message of `message`. You can include extractions in the message, for example: `I saw a bar of: <foo.bar>` |
15 | 17 |
|
16 | 18 |
Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent. |
@@ -49,26 +51,33 @@ module Agents |
||
49 | 51 |
incoming_events.each do |event| |
50 | 52 |
match = options['rules'].all? do |rule| |
51 | 53 |
value_at_path = Utils.value_at(event['payload'], rule['path']) |
52 |
- case rule['type'] |
|
53 |
- when "regex" |
|
54 |
- value_at_path.to_s =~ Regexp.new(rule['value'], Regexp::IGNORECASE) |
|
55 |
- when "!regex" |
|
56 |
- value_at_path.to_s !~ Regexp.new(rule['value'], Regexp::IGNORECASE) |
|
57 |
- when "field>value" |
|
58 |
- value_at_path.to_f > rule['value'].to_f |
|
59 |
- when "field>=value" |
|
60 |
- value_at_path.to_f >= rule['value'].to_f |
|
61 |
- when "field<value" |
|
62 |
- value_at_path.to_f < rule['value'].to_f |
|
63 |
- when "field<=value" |
|
64 |
- value_at_path.to_f <= rule['value'].to_f |
|
65 |
- when "field==value" |
|
66 |
- value_at_path.to_s == rule['value'].to_s |
|
67 |
- when "field!=value" |
|
68 |
- value_at_path.to_s != rule['value'].to_s |
|
69 |
- else |
|
70 |
- raise "Invalid type of #{rule['type']} in TriggerAgent##{id}" |
|
54 |
+ rule_values = rule['value'] |
|
55 |
+ if !rule_values.kind_of?(Array) then rule_values = [rule_values] end |
|
56 |
+ |
|
57 |
+ match_found = false |
|
58 |
+ rule_values.each do |rule_value| |
|
59 |
+ match_found ||= case rule['type'] |
|
60 |
+ when "regex" |
|
61 |
+ value_at_path.to_s =~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
62 |
+ when "!regex" |
|
63 |
+ value_at_path.to_s !~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
64 |
+ when "field>value" |
|
65 |
+ value_at_path.to_f > rule_value.to_f |
|
66 |
+ when "field>=value" |
|
67 |
+ value_at_path.to_f >= rule_value.to_f |
|
68 |
+ when "field<value" |
|
69 |
+ value_at_path.to_f < rule_value.to_f |
|
70 |
+ when "field<=value" |
|
71 |
+ value_at_path.to_f <= rule_value.to_f |
|
72 |
+ when "field==value" |
|
73 |
+ value_at_path.to_s == rule_value.to_s |
|
74 |
+ when "field!=value" |
|
75 |
+ value_at_path.to_s != rule_value.to_s |
|
76 |
+ else |
|
77 |
+ raise "Invalid type of #{rule['type']} in TriggerAgent##{id}" |
|
78 |
+ end |
|
71 | 79 |
end |
80 |
+ match_found |
|
72 | 81 |
end |
73 | 82 |
|
74 | 83 |
if match |
@@ -71,6 +71,28 @@ describe Agents::TriggerAgent do |
||
71 | 71 |
}.should change { Event.count }.by(1) |
72 | 72 |
end |
73 | 73 |
|
74 |
+ it "handles array of regex" do |
|
75 |
+ @event.payload['foo']['bar']['baz'] = "a222b" |
|
76 |
+ @checker.options['rules'][0] = { |
|
77 |
+ 'type' => "regex", |
|
78 |
+ 'value' => ["a\\db", "a\\Wb"], |
|
79 |
+ 'path' => "foo.bar.baz", |
|
80 |
+ } |
|
81 |
+ lambda { |
|
82 |
+ @checker.receive([@event]) |
|
83 |
+ }.should_not change { Event.count } |
|
84 |
+ |
|
85 |
+ @event.payload['foo']['bar']['baz'] = "a2b" |
|
86 |
+ lambda { |
|
87 |
+ @checker.receive([@event]) |
|
88 |
+ }.should change { Event.count }.by(1) |
|
89 |
+ |
|
90 |
+ @event.payload['foo']['bar']['baz'] = "a b" |
|
91 |
+ lambda { |
|
92 |
+ @checker.receive([@event]) |
|
93 |
+ }.should change { Event.count }.by(1) |
|
94 |
+ end |
|
95 |
+ |
|
74 | 96 |
it "handles negated regex" do |
75 | 97 |
@event.payload['foo']['bar']['baz'] = "a2b" |
76 | 98 |
@checker.options['rules'][0] = { |
@@ -89,6 +111,24 @@ describe Agents::TriggerAgent do |
||
89 | 111 |
}.should change { Event.count }.by(1) |
90 | 112 |
end |
91 | 113 |
|
114 |
+ it "handles array of negated regex" do |
|
115 |
+ @event.payload['foo']['bar']['baz'] = "a2b" |
|
116 |
+ @checker.options['rules'][0] = { |
|
117 |
+ 'type' => "!regex", |
|
118 |
+ 'value' => ["a\\db", "a2b"], |
|
119 |
+ 'path' => "foo.bar.baz", |
|
120 |
+ } |
|
121 |
+ |
|
122 |
+ lambda { |
|
123 |
+ @checker.receive([@event]) |
|
124 |
+ }.should_not change { Event.count } |
|
125 |
+ |
|
126 |
+ @event.payload['foo']['bar']['baz'] = "a3b" |
|
127 |
+ lambda { |
|
128 |
+ @checker.receive([@event]) |
|
129 |
+ }.should change { Event.count }.by(1) |
|
130 |
+ end |
|
131 |
+ |
|
92 | 132 |
it "puts can extract values into the message based on paths" do |
93 | 133 |
@checker.receive([@event]) |
94 | 134 |
Event.last.payload['message'].should == "I saw 'a2b' from Joe" |
@@ -109,6 +149,21 @@ describe Agents::TriggerAgent do |
||
109 | 149 |
}.should_not change { Event.count } |
110 | 150 |
end |
111 | 151 |
|
152 |
+ it "handles array of numerical comparisons" do |
|
153 |
+ @event.payload['foo']['bar']['baz'] = "5" |
|
154 |
+ @checker.options['rules'].first['value'] = [6, 3] |
|
155 |
+ @checker.options['rules'].first['type'] = "field<value" |
|
156 |
+ |
|
157 |
+ lambda { |
|
158 |
+ @checker.receive([@event]) |
|
159 |
+ }.should change { Event.count }.by(1) |
|
160 |
+ |
|
161 |
+ @checker.options['rules'].first['value'] = [4, 3] |
|
162 |
+ lambda { |
|
163 |
+ @checker.receive([@event]) |
|
164 |
+ }.should_not change { Event.count } |
|
165 |
+ end |
|
166 |
+ |
|
112 | 167 |
it "handles exact comparisons" do |
113 | 168 |
@event.payload['foo']['bar']['baz'] = "hello world" |
114 | 169 |
@checker.options['rules'].first['type'] = "field==value" |
@@ -124,6 +179,21 @@ describe Agents::TriggerAgent do |
||
124 | 179 |
}.should change { Event.count }.by(1) |
125 | 180 |
end |
126 | 181 |
|
182 |
+ it "handles array of exact comparisons" do |
|
183 |
+ @event.payload['foo']['bar']['baz'] = "hello world" |
|
184 |
+ @checker.options['rules'].first['type'] = "field==value" |
|
185 |
+ |
|
186 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello universe"] |
|
187 |
+ lambda { |
|
188 |
+ @checker.receive([@event]) |
|
189 |
+ }.should_not change { Event.count } |
|
190 |
+ |
|
191 |
+ @checker.options['rules'].first['value'] = ["hello world", "hello universe"] |
|
192 |
+ lambda { |
|
193 |
+ @checker.receive([@event]) |
|
194 |
+ }.should change { Event.count }.by(1) |
|
195 |
+ end |
|
196 |
+ |
|
127 | 197 |
it "handles negated comparisons" do |
128 | 198 |
@event.payload['foo']['bar']['baz'] = "hello world" |
129 | 199 |
@checker.options['rules'].first['type'] = "field!=value" |
@@ -140,6 +210,22 @@ describe Agents::TriggerAgent do |
||
140 | 210 |
}.should change { Event.count }.by(1) |
141 | 211 |
end |
142 | 212 |
|
213 |
+ it "handles array of negated comparisons" do |
|
214 |
+ @event.payload['foo']['bar']['baz'] = "hello world" |
|
215 |
+ @checker.options['rules'].first['type'] = "field!=value" |
|
216 |
+ @checker.options['rules'].first['value'] = ["hello world", "hello world"] |
|
217 |
+ |
|
218 |
+ lambda { |
|
219 |
+ @checker.receive([@event]) |
|
220 |
+ }.should_not change { Event.count } |
|
221 |
+ |
|
222 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello world"] |
|
223 |
+ |
|
224 |
+ lambda { |
|
225 |
+ @checker.receive([@event]) |
|
226 |
+ }.should change { Event.count }.by(1) |
|
227 |
+ end |
|
228 |
+ |
|
143 | 229 |
it "does fine without dots in the path" do |
144 | 230 |
@event.payload = { 'hello' => "world" } |
145 | 231 |
@checker.options['rules'].first['type'] = "field==value" |