fluent-plugin-notifier 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -27,6 +27,7 @@ To notify apache logs with over 1000000 (microseconds) duration for CRITICAL , o
27
27
  warn_regexp 5\d\d
28
28
  crit_regexp 500
29
29
  target_key_pattern ^status.*$
30
+ exclude_key_pattern ^status_ignore_.*$ # key name not to notify about...
30
31
  </def>
31
32
  </match>
32
33
 
@@ -53,7 +54,7 @@ If you want to get every 5 minutes notifications (after 1 minutes notifications)
53
54
 
54
55
  ## TODO
55
56
 
56
- * long run
57
+ * patches welcome!
57
58
 
58
59
  ## Copyright
59
60
 
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "fluent-plugin-notifier"
4
- gem.version = "0.0.2"
4
+ gem.version = "0.1.0"
5
5
  gem.authors = ["TAGOMORI Satoshi"]
6
6
  gem.email = ["tagomoris@gmail.com"]
7
7
  gem.summary = %q{check matched messages and emit alert message}
@@ -13,6 +13,7 @@ Gem::Specification.new do |gem|
13
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
14
  gem.require_paths = ["lib"]
15
15
 
16
+ gem.add_development_dependency "rake"
16
17
  gem.add_development_dependency "fluentd"
17
18
  gem.add_runtime_dependency "fluentd"
18
19
  end
@@ -167,7 +167,7 @@ class Fluent::NotifierOutput < Fluent::Output
167
167
  class Definition
168
168
  attr_accessor :tag, :tag_warn, :tag_crit
169
169
  attr_accessor :intervals, :repetitions
170
- attr_accessor :pattern, :check, :target_keys, :target_key_pattern, :exclude_keys, :exclude_key_pattern
170
+ attr_accessor :pattern, :check, :target_keys, :target_key_pattern, :exclude_key_pattern
171
171
  attr_accessor :crit_threshold, :warn_threshold # for 'numeric_upward', 'numeric_downward'
172
172
  attr_accessor :crit_regexp, :warn_regexp # for 'string_find'
173
173
 
@@ -195,7 +195,6 @@ class Fluent::NotifierOutput < Fluent::Output
195
195
  end
196
196
  when 'target_keys'
197
197
  @target_keys = element['target_keys'].split(',')
198
- @exclude_keys = (element['exclude_keys'] || '').split(',')
199
198
  when 'target_key_pattern'
200
199
  @target_key_pattern = Regexp.compile(element['target_key_pattern'])
201
200
  @exclude_key_pattern = Regexp.compile(element['exclude_key_pattern'] || '^$')
@@ -223,7 +222,7 @@ class Fluent::NotifierOutput < Fluent::Output
223
222
 
224
223
  def match?(key)
225
224
  if @target_keys
226
- @target_keys.include?(key) and not @exclude_keys.include?(key)
225
+ @target_keys.include?(key)
227
226
  elsif @target_key_pattern
228
227
  @target_key_pattern.match(key) and not @exclude_key_pattern.match(key)
229
228
  end
@@ -242,61 +241,64 @@ class Fluent::NotifierOutput < Fluent::Output
242
241
  def check(tag, time, record, key)
243
242
  case @check
244
243
  when :upward
245
- if @crit_threshold and record[key].to_f >= @crit_threshold
244
+ value = record[key].to_f
245
+ if @crit_threshold and value >= @crit_threshold
246
246
  {
247
247
  :hashkey => @pattern + "\t" + tag + "\t" + key,
248
248
  :match_def => self,
249
249
  :emit_tag => (@tag_crit || @tag),
250
250
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'numeric_upward', 'level' => 'crit',
251
- 'threshold' => @crit_threshold, 'value' => record[key], 'message_time' => Time.at(time).to_s
251
+ 'threshold' => @crit_threshold, 'value' => value, 'message_time' => Time.at(time).to_s
252
252
  }
253
- elsif @warn_threshold and record[key].to_f >= @warn_threshold
253
+ elsif @warn_threshold and value >= @warn_threshold
254
254
  {
255
255
  :hashkey => @pattern + "\t" + tag + "\t" + key,
256
256
  :match_def => self,
257
257
  :emit_tag => (@tag_warn || @tag),
258
258
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'numeric_upward', 'level' => 'warn',
259
- 'threshold' => @warn_threshold, 'value' => record[key], 'message_time' => Time.at(time).to_s
259
+ 'threshold' => @warn_threshold, 'value' => value, 'message_time' => Time.at(time).to_s
260
260
  }
261
261
  else
262
262
  nil
263
263
  end
264
264
  when :downward
265
- if @crit_threshold and record[key].to_f <= @crit_threshold
265
+ value = record[key].to_f
266
+ if @crit_threshold and value <= @crit_threshold
266
267
  {
267
268
  :hashkey => @pattern + "\t" + tag + "\t" + key,
268
269
  :match_def => self,
269
270
  :emit_tag => (@tag_crit || @tag),
270
271
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'numeric_downward', 'level' => 'crit',
271
- 'threshold' => @crit_threshold, 'value' => record[key], 'message_time' => Time.at(time).to_s
272
+ 'threshold' => @crit_threshold, 'value' => value, 'message_time' => Time.at(time).to_s
272
273
  }
273
- elsif @warn_threshold and record[key].to_f <= @warn_threshold
274
+ elsif @warn_threshold and value <= @warn_threshold
274
275
  {
275
276
  :hashkey => @pattern + "\t" + tag + "\t" + key,
276
277
  :match_def => self,
277
278
  :emit_tag => (@tag_warn || @tag),
278
279
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'numeric_downward', 'level' => 'warn',
279
- 'threshold' => @warn_threshold, 'value' => record[key], 'message_time' => Time.at(time).to_s
280
+ 'threshold' => @warn_threshold, 'value' => value, 'message_time' => Time.at(time).to_s
280
281
  }
281
282
  else
282
283
  nil
283
284
  end
284
285
  when :find
285
- if @crit_regexp and @crit_regexp.match(record[key].to_s)
286
+ str = record[key].to_s
287
+ if @crit_regexp and @crit_regexp.match(str)
286
288
  {
287
289
  :hashkey => @pattern + "\t" + tag + "\t" + key,
288
290
  :match_def => self,
289
291
  :emit_tag => (@tag_crit || @tag),
290
292
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'string_find', 'level' => 'crit',
291
- 'regexp' => @crit_regexp.inspect, 'value' => record[key], 'message_time' => Time.at(time).to_s
293
+ 'regexp' => @crit_regexp.inspect, 'value' => str, 'message_time' => Time.at(time).to_s
292
294
  }
293
- elsif @warn_regexp and @warn_regexp.match(record[key].to_s)
295
+ elsif @warn_regexp and @warn_regexp.match(str)
294
296
  {
295
297
  :hashkey => @pattern + "\t" + tag + "\t" + key,
296
298
  :match_def => self,
297
299
  :emit_tag => (@tag_warn || @tag),
298
300
  'pattern' => @pattern, 'target_tag' => tag, 'target_key' => key, 'check_type' => 'string_find', 'level' => 'warn',
299
- 'regexp' => @warn_regexp.inspect, 'value' => record[key], 'message_time' => Time.at(time).to_s
301
+ 'regexp' => @warn_regexp.inspect, 'value' => str, 'message_time' => Time.at(time).to_s
300
302
  }
301
303
  else
302
304
  nil
@@ -0,0 +1,143 @@
1
+ require 'helper'
2
+
3
+ class NotifierOutputDefinitionTest < Test::Unit::TestCase
4
+ TEST_DEFAULTS = {
5
+ :tag => 'n', :tag_warn => nil, :tag_crit => nil,
6
+ :interval_1st => 60, :repetitions_1st => 5,
7
+ :interval_2nd => 300, :repetitions_2nd => 5,
8
+ :interval_3rd => 1800
9
+ }
10
+
11
+ TEST_CONF1 = {
12
+ 'tag' => 'notify',
13
+ 'pattern' => 'name1', 'target_keys' => 'field1,field2',
14
+ 'check' => 'numeric_upward', 'warn_threshold' => '1', 'crit_threshold' => '2',
15
+ }
16
+
17
+ TEST_CONF2 = {
18
+ 'tag_warn' => 'warn', 'tag_crit' => 'crit',
19
+ 'pattern' => 'name2', 'target_key_pattern' => '^field\d$',
20
+ 'check' => 'string_find', 'warn_regexp' => 'WARN', 'crit_regexp' => 'CRIT',
21
+ 'interval_1st' => 5, 'repetitions_1st' => 1,
22
+ 'interval_2nd' => 6, 'repetitions_2nd' => 2,
23
+ 'interval_3rd' => 7
24
+ }
25
+
26
+ def test_init
27
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF1, TEST_DEFAULTS)
28
+ assert_equal 'name1', d.pattern
29
+ assert_equal ['field1','field2'], d.target_keys
30
+ assert_equal :upward, d.instance_eval{ @check }
31
+ assert_equal 2.0, d.crit_threshold
32
+ assert_equal 1.0, d.warn_threshold
33
+ assert_equal 'notify', d.tag
34
+ assert_nil d.tag_warn
35
+ assert_nil d.tag_crit
36
+ assert_equal [60, 300, 1800], d.intervals
37
+ assert_equal [5, 5], d.repetitions
38
+
39
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF2, TEST_DEFAULTS)
40
+ assert_equal 'name2', d.pattern
41
+ assert_equal /^field\d$/, d.target_key_pattern
42
+ assert_equal /^$/, d.exclude_key_pattern
43
+ assert_equal :find, d.instance_eval{ @check }
44
+ assert_equal /WARN/, d.warn_regexp
45
+ assert_equal /CRIT/, d.crit_regexp
46
+ assert_equal 'n', d.tag
47
+ assert_equal 'warn', d.tag_warn
48
+ assert_equal 'crit', d.tag_crit
49
+ assert_equal [5, 6, 7], d.intervals
50
+ assert_equal [1, 2], d.repetitions
51
+ end
52
+
53
+ def test_match
54
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF1, TEST_DEFAULTS)
55
+ assert_equal true, d.match?('field1')
56
+ assert_equal true, d.match?('field2')
57
+ assert ! d.match?('field0')
58
+ assert ! d.match?('field')
59
+ assert ! d.match?('')
60
+
61
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF2, TEST_DEFAULTS)
62
+ assert_equal true, d.match?('field0')
63
+ assert_equal true, d.match?('field1')
64
+ assert_equal true, d.match?('field9')
65
+ assert ! d.match?('field')
66
+ assert ! d.match?('fieldx')
67
+ assert ! d.match?(' field0')
68
+ assert ! d.match?('field0 ')
69
+
70
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF2.merge({'exclude_key_pattern' => '^field[7-9]$'}), TEST_DEFAULTS)
71
+ assert_equal true, d.match?('field0')
72
+ assert_equal true, d.match?('field1')
73
+ assert ! d.match?('field7')
74
+ assert ! d.match?('field8')
75
+ assert ! d.match?('field9')
76
+ end
77
+
78
+ def test_check_numeric
79
+ t = Time.strptime('2012-07-19 14:40:30', '%Y-%m-%d %T')
80
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF1, TEST_DEFAULTS)
81
+ r = d.check('test.tag', t.to_i, {'field1' => '0.8', 'field2' => '1.5'}, 'field1')
82
+ assert_nil r
83
+
84
+ r = d.check('test.tag', t.to_i, {'field1' => '0.8', 'field2' => '1.5'}, 'field2')
85
+ assert_equal "name1\ttest.tag\tfield2", r[:hashkey]
86
+ assert_equal d, r[:match_def]
87
+ assert_equal 'notify', r[:emit_tag]
88
+ assert_equal 'name1', r['pattern']
89
+ assert_equal 'test.tag', r['target_tag']
90
+ assert_equal 'field2', r['target_key']
91
+ assert_equal 'numeric_upward', r['check_type']
92
+ assert_equal 'warn', r['level']
93
+ assert_equal 1.0, r['threshold']
94
+ assert_equal 1.5, r['value']
95
+ assert_equal t.to_s, r['message_time']
96
+
97
+ r = d.check('test.tag', t.to_i, {'field1' => '200', 'field2' => '1.5'}, 'field1')
98
+ assert_equal "name1\ttest.tag\tfield1", r[:hashkey]
99
+ assert_equal d, r[:match_def]
100
+ assert_equal 'notify', r[:emit_tag]
101
+ assert_equal 'name1', r['pattern']
102
+ assert_equal 'test.tag', r['target_tag']
103
+ assert_equal 'field1', r['target_key']
104
+ assert_equal 'numeric_upward', r['check_type']
105
+ assert_equal 'crit', r['level']
106
+ assert_equal 2.0, r['threshold']
107
+ assert_equal 200.0, r['value']
108
+ assert_equal t.to_s, r['message_time']
109
+ end
110
+
111
+ def test_check_string
112
+ t = Time.strptime('2012-07-19 14:40:30', '%Y-%m-%d %T')
113
+ d = Fluent::NotifierOutput::Definition.new(TEST_CONF2, TEST_DEFAULTS)
114
+ r = d.check('test.tag', t.to_i, {'field0' => 'hoge pos', 'field1' => 'CRIT fooooooo baaaaarrrrrrr'}, 'field0')
115
+ assert_nil r
116
+
117
+ r = d.check('test.tag', t.to_i, {'field0' => 'hoge pos', 'field1' => 'CRIT fooooooo baaaaarrrrrrr'}, 'field1')
118
+ assert_equal "name2\ttest.tag\tfield1", r[:hashkey]
119
+ assert_equal d, r[:match_def]
120
+ assert_equal 'crit', r[:emit_tag]
121
+ assert_equal 'name2', r['pattern']
122
+ assert_equal 'test.tag', r['target_tag']
123
+ assert_equal 'field1', r['target_key']
124
+ assert_equal 'string_find', r['check_type']
125
+ assert_equal 'crit', r['level']
126
+ assert_equal '/CRIT/', r['regexp']
127
+ assert_equal 'CRIT fooooooo baaaaarrrrrrr', r['value']
128
+ assert_equal t.to_s, r['message_time']
129
+
130
+ r = d.check('test.tag', t.to_i, {'field0' => 'hoge pos (WARN) check!', 'field1' => 'CRIT fooooooo baaaaarrrrrrr'}, 'field0')
131
+ assert_equal "name2\ttest.tag\tfield0", r[:hashkey]
132
+ assert_equal d, r[:match_def]
133
+ assert_equal 'warn', r[:emit_tag]
134
+ assert_equal 'name2', r['pattern']
135
+ assert_equal 'test.tag', r['target_tag']
136
+ assert_equal 'field0', r['target_key']
137
+ assert_equal 'string_find', r['check_type']
138
+ assert_equal 'warn', r['level']
139
+ assert_equal '/WARN/', r['regexp']
140
+ assert_equal 'hoge pos (WARN) check!', r['value']
141
+ assert_equal t.to_s, r['message_time']
142
+ end
143
+ end
@@ -0,0 +1,9 @@
1
+ require 'helper'
2
+
3
+ class NotifierOutputTest < Test::Unit::TestCase
4
+ CONFIG = %[
5
+ ]
6
+ def create_driver(conf=CONFIG,tag='test')
7
+ Fluent::Test::OutputTestDriver.new(Fluent::NotifierOutput, tag).configure(conf)
8
+ end
9
+ end
@@ -0,0 +1,76 @@
1
+ require 'helper'
2
+
3
+ class NotifierOutputStateTest < Test::Unit::TestCase
4
+ TEST_DEF_DEFAULTS = {
5
+ :tag => 'n', :tag_warn => nil, :tag_crit => nil,
6
+ :interval_1st => 60, :repetitions_1st => 5,
7
+ :interval_2nd => 300, :repetitions_2nd => 5,
8
+ :interval_3rd => 1800
9
+ }
10
+ TEST_DEF_CONF1 = {
11
+ 'tag' => 'notify',
12
+ 'pattern' => 'name1', 'target_keys' => 'field1,field2',
13
+ 'check' => 'numeric_upward', 'warn_threshold' => '1', 'crit_threshold' => '2',
14
+ }
15
+ TEST_DEF_CONF2 = {
16
+ 'tag_warn' => 'warn', 'tag_crit' => 'crit',
17
+ 'pattern' => 'name2', 'target_key_pattern' => '^field\d$',
18
+ 'check' => 'string_find', 'warn_regexp' => 'WARN', 'crit_regexp' => 'CRIT',
19
+ 'interval_1st' => 5, 'repetitions_1st' => 1,
20
+ 'interval_2nd' => 6, 'repetitions_2nd' => 2,
21
+ 'interval_3rd' => 7
22
+ }
23
+
24
+ def test_init
25
+ s = Fluent::NotifierOutput::State.new({
26
+ :pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'
27
+ })
28
+ assert_equal 'name1', s.pattern
29
+ assert_equal 'test.tag', s.target_tag
30
+ assert_equal 'field1', s.target_key
31
+ assert_equal 'warn', s.level
32
+ assert_equal 0, s.stage
33
+ assert_equal 1, s.counter
34
+ assert (s.first_notified <= Fluent::Engine.now)
35
+ assert (s.last_notified <= Fluent::Engine.now)
36
+ end
37
+
38
+ def test_suppress?
39
+ s = Fluent::NotifierOutput::State.new({
40
+ :pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'
41
+ })
42
+ d = Fluent::NotifierOutput::Definition.new(TEST_DEF_CONF1, TEST_DEF_DEFAULTS)
43
+ s.last_notified = Fluent::Engine.now - TEST_DEF_DEFAULTS[:interval_1st] + 5
44
+ assert_equal true, s.suppress?(d, {:pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'})
45
+ s.last_notified = Fluent::Engine.now - TEST_DEF_DEFAULTS[:interval_1st] - 5
46
+ assert_equal false, s.suppress?(d, {:pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'})
47
+
48
+ s = Fluent::NotifierOutput::State.new({
49
+ :pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'
50
+ })
51
+ d = Fluent::NotifierOutput::Definition.new(TEST_DEF_CONF1, TEST_DEF_DEFAULTS)
52
+ assert_equal true, s.suppress?(d, {:pattern => 'name1', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'crit'})
53
+ end
54
+
55
+ def test_update_notified
56
+ s = Fluent::NotifierOutput::State.new({
57
+ :pattern => 'name2', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'
58
+ })
59
+ d = Fluent::NotifierOutput::Definition.new(TEST_DEF_CONF2, TEST_DEF_DEFAULTS)
60
+
61
+ assert_equal 0, s.stage
62
+ assert_equal 1, s.counter
63
+
64
+ s.update_notified(d, {:pattern => 'name2', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'})
65
+ assert_equal 1, s.stage
66
+ assert_equal 0, s.counter
67
+
68
+ s.update_notified(d, {:pattern => 'name2', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'warn'})
69
+ assert_equal 1, s.stage
70
+ assert_equal 1, s.counter
71
+
72
+ s.update_notified(d, {:pattern => 'name2', :target_tag => 'test.tag', :target_key => 'field1', 'level' => 'crit'})
73
+ assert_equal 0, s.stage
74
+ assert_equal 1, s.counter
75
+ end
76
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-notifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-18 00:00:00.000000000 Z
12
+ date: 2012-07-19 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: fluentd
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -58,7 +74,9 @@ files:
58
74
  - fluent-plugin-notifier.gemspec
59
75
  - lib/fluent/plugin/out_notifier.rb
60
76
  - test/helper.rb
77
+ - test/plugin/test_def.rb
61
78
  - test/plugin/test_out_notifier.rb
79
+ - test/plugin/test_state.rb
62
80
  homepage: https://github.com/tagomoris/fluent-plugin-notifier
63
81
  licenses: []
64
82
  post_install_message:
@@ -85,4 +103,6 @@ specification_version: 3
85
103
  summary: check matched messages and emit alert message
86
104
  test_files:
87
105
  - test/helper.rb
106
+ - test/plugin/test_def.rb
88
107
  - test/plugin/test_out_notifier.rb
108
+ - test/plugin/test_state.rb