fluent-plugin-notifier 0.0.2 → 0.1.0

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/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