fluent-plugin-suppress 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69911b60cb792ed60fc4c5f8f79898f096d9f470
4
- data.tar.gz: a6d7d239f7b98cc6e18cd3070f91c448737d8437
3
+ metadata.gz: 2aae4d23ad644c4d3108686f8fed825e7f399b16
4
+ data.tar.gz: c5b4aacdd63741a43111a400b032fcf3f8776df1
5
5
  SHA512:
6
- metadata.gz: 909949a7666e44bdace8f470119b78af50df9f4313da325b32bed250034a13bffee6a608ea0a61bdeca4c7662ef084115a4140dabfe82b009265af4a151c5690
7
- data.tar.gz: 7060f98358b1ab852367bde79fe7aa4dc3d1e245a54a772d8b2d4ae6408b14bfad7dea50e412d8a0cd7a151cf5a2465ea83fa7c0c3d94f4270ac1800a2c1a5fa
6
+ metadata.gz: c1df1e8f388f1827a6e2530e15bc35b8636928903f4d89e34b09a8c662237442a02899df4c03251db65fbeda6c308639ca1d78a5edaa9625d5e56ca51549e793
7
+ data.tar.gz: 815337b3468853a34c8171dfe1f43b431698cf34b91633eb3228fac64885d39812e650fb304dce88fb57d9974d3e225f59d742cbe0bf1e7daccc877a38f76cfb
@@ -0,0 +1,100 @@
1
+ # fluent-plugin-suppress
2
+
3
+ [![Build Status](https://travis-ci.org/fujiwara/fluent-plugin-suppress.svg?branch=master)](https://travis-ci.org/fujiwara/fluent-plugin-suppress)
4
+
5
+ ## SuppressOutout / SuppressFilter
6
+
7
+ Fluentd plugin to suppress same messages.
8
+
9
+ ## Configuration
10
+
11
+ fluentd.conf
12
+
13
+ ```
14
+ <match foo.**>
15
+ type suppress
16
+ interval 10
17
+ num 2
18
+ attr_keys host,message
19
+ add_tag_prefix sp.
20
+ </match>
21
+ ```
22
+
23
+ In `interval` sec, `num` messages which grouped by `attr_keys` value, add tag prefix "`sp.`" and pass to follow process. Other messages will be removed.
24
+
25
+ Input messages:
26
+
27
+ ```
28
+ 2012-11-22T11:22:33 foo.info {"id":1,"host":"web01","message":"error!!"}
29
+ 2012-11-22T11:22:34 foo.info {"id":2,"host":"web01","message":"error!!"}
30
+ * 2012-11-22T11:22:35 foo.info {"id":3,"host":"web01","message":"error!!"}
31
+ * 2012-11-22T11:22:36 foo.info {"id":4,"host":"web01","message":"error!!"}
32
+ 2012-11-22T11:22:37 foo.info {"id":5,"host":"app01","message":"error!!"}
33
+ * 2012-11-22T11:22:38 foo.info {"id":6,"host":"web01","message":"error!!"}
34
+ * 2012-11-22T11:22:39 foo.info {"id":7,"host":"web01","message":"error!!"}
35
+ * 2012-11-22T11:22:40 foo.info {"id":8,"host":"web01","message":"error!!"}
36
+ 2012-11-22T11:22:45 foo.info {"id":9,"host":"web01","message":"error!!"}
37
+ ```
38
+ (* = suppressed)
39
+
40
+ Output messages:
41
+
42
+ ```
43
+ 2012-11-22T11:22:33 sp.foo.info {"id":1,"host":"web01","message":"error!!"}
44
+ 2012-11-22T11:22:34 sp.foo.info {"id":2,"host":"web01","message":"error!!"}
45
+ 2012-11-22T11:22:37 sp.foo.info {"id":5,"host":"app01","message":"error!!"}
46
+ 2012-11-22T11:22:45 sp.foo.info {"id":9,"host":"web01","message":"error!!"}
47
+ ```
48
+
49
+ ### Filter plugin
50
+
51
+ Fluentd >= v0.12 can use filter plugin.
52
+
53
+ ```
54
+ <filter foo.**>
55
+ type suppress
56
+ interval 10
57
+ num 2
58
+ attr_keys host,message
59
+ </filter>
60
+ ```
61
+
62
+ Filter plugin will not replace a tag.
63
+
64
+ ### Group by nested key name
65
+
66
+ `attr_keys` allows nested key name (eg. `foo.bar`).
67
+
68
+ ```
69
+ <match foo.**>
70
+ type suppress
71
+ attr_keys data.host, data.message
72
+ </match>
73
+ ```
74
+
75
+ Input messages will be suppressed by key data.host and data.message.
76
+
77
+ ```
78
+ 2012-11-22T11:22:33 foo.info {"id":1,"data":{"host":"web01","message":"error!!"}}
79
+ 2012-11-22T11:22:34 foo.info {"id":2,"data":{"host":"web01","message":"error!!"}}
80
+ ```
81
+
82
+ ### Suppressing by tag only
83
+
84
+ If `attr_keys` is not specified, records will be suppressed by tag only.
85
+
86
+ ```
87
+ <match foo.**>
88
+ type suppress
89
+ ...
90
+ </match>
91
+ ```
92
+
93
+ ## TODO
94
+
95
+ patches welcome!
96
+
97
+ ## Copyright
98
+
99
+ Copyright (c) 2012- FUJIWARA Shunichiro
100
+ License Apache License, Version 2.0
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
14
14
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
15
  gem.name = "fluent-plugin-suppress"
16
16
  gem.require_paths = ["lib"]
17
- gem.version = "0.0.5"
17
+ gem.version = "0.0.6"
18
18
 
19
19
  gem.add_runtime_dependency "fluentd", ">= 0.10.0"
20
20
  gem.add_development_dependency "rake", ">= 0.9.2"
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Fluent
3
+ class SuppressFilter < Filter
4
+ Fluent::Plugin.register_filter('suppress', self)
5
+
6
+ config_param :attr_keys, :string, :default => nil
7
+ config_param :num, :integer, :default => 3
8
+ config_param :interval, :integer, :default => 300
9
+
10
+ def configure(conf)
11
+ super
12
+ @keys = @attr_keys ? @attr_keys.split(/ *, */) : nil
13
+ @slots = {}
14
+ end
15
+
16
+ def start
17
+ super
18
+ end
19
+
20
+ def shutdown
21
+ super
22
+ end
23
+
24
+ def filter_stream(tag, es)
25
+ new_es = MultiEventStream.new
26
+ es.each do |time, record|
27
+ if @keys
28
+ keys = @keys.map do |key|
29
+ key.split(/\./).inject(record) {|r, k| r[k] }
30
+ end
31
+ key = tag + "\0" + keys.join("\0")
32
+ else
33
+ key = tag
34
+ end
35
+ slot = @slots[key] ||= []
36
+
37
+ # expire old records time
38
+ expired = time.to_f - @interval
39
+ while slot.first && (slot.first <= expired)
40
+ slot.shift
41
+ end
42
+
43
+ if slot.length >= @num
44
+ log.debug "suppressed record: #{record.to_json}"
45
+ next
46
+ end
47
+
48
+ slot.push(time.to_f)
49
+ new_es.add(time, record)
50
+ end
51
+ return new_es
52
+ end
53
+ end if defined?(Filter) # Support only >= v0.12
54
+ end
@@ -0,0 +1,113 @@
1
+ require 'test/unit'
2
+ require 'fluent/log'
3
+ require 'fluent/test'
4
+ require 'fluent/plugin/filter_suppress'
5
+
6
+ class SuppressFilterTest < Test::Unit::TestCase
7
+ include Fluent
8
+
9
+ def setup
10
+ Fluent::Test.setup
11
+ end
12
+
13
+ CONFIG = %[
14
+ interval 10
15
+ num 2
16
+ attr_keys host, message
17
+ ]
18
+
19
+ CONFIG_WITH_NESTED_KEY = %[
20
+ interval 10
21
+ num 2
22
+ attr_keys data.host, data.message
23
+ ]
24
+
25
+ CONFIG_TAG_ONLY = %[
26
+ interval 10
27
+ num 2
28
+ ]
29
+
30
+ def create_driver(conf = CONFIG, tag='test.info')
31
+ Fluent::Test::FilterTestDriver.new(Fluent::SuppressFilter).configure(conf, tag)
32
+ end
33
+
34
+ def test_emit
35
+ return unless defined? Fluent::Filter
36
+
37
+ d = create_driver(CONFIG)
38
+ es = Fluent::MultiEventStream.new
39
+
40
+ time = Time.parse("2012-11-22 11:22:33 UTC").to_i
41
+ es.add(time + 1, {"id" => 1, "host" => "web01", "message" => "error!!"})
42
+ es.add(time + 2, {"id" => 2, "host" => "web01", "message" => "error!!"})
43
+ es.add(time + 3, {"id" => 3, "host" => "web01", "message" => "error!!"})
44
+ es.add(time + 4, {"id" => 4, "host" => "web01", "message" => "error!!"})
45
+ es.add(time + 4, {"id" => 5, "host" => "app01", "message" => "error!!"})
46
+ es.add(time + 12, {"id" => 6, "host" => "web01", "message" => "error!!"})
47
+ es.add(time + 13, {"id" => 7, "host" => "web01", "message" => "error!!"})
48
+ es.add(time + 14, {"id" => 8, "host" => "web01", "message" => "error!!"})
49
+
50
+ filtered_es = d.filter_stream('test.info', es)
51
+ records = filtered_es.instance_variable_get(:@record_array)
52
+ assert_equal 5, records.length
53
+ assert_equal({"id" => 1, "host" => "web01", "message" => "error!!"}, records[0])
54
+ assert_equal({"id" => 2, "host" => "web01", "message" => "error!!"}, records[1])
55
+ assert_equal({"id" => 5, "host" => "app01", "message" => "error!!"}, records[2])
56
+ assert_equal({"id" => 6, "host" => "web01", "message" => "error!!"}, records[3])
57
+ assert_equal({"id" => 7, "host" => "web01", "message" => "error!!"}, records[4])
58
+ end
59
+
60
+ def test_emit_wtih_nested_key
61
+ return unless defined? Fluent::Filter
62
+
63
+ d = create_driver(CONFIG_WITH_NESTED_KEY)
64
+ es = Fluent::MultiEventStream.new
65
+
66
+ time = Time.parse("2012-11-22 11:22:33 UTC").to_i
67
+ es.add(time + 1, {"id" => 1, "data" => {"host" => "web01", "message" => "error!!"}})
68
+ es.add(time + 2, {"id" => 2, "data" => {"host" => "web01", "message" => "error!!"}})
69
+ es.add(time + 3, {"id" => 3, "data" => {"host" => "web01", "message" => "error!!"}})
70
+ es.add(time + 4, {"id" => 4, "data" => {"host" => "web01", "message" => "error!!"}})
71
+ es.add(time + 4, {"id" => 5, "data" => {"host" => "app01", "message" => "error!!"}})
72
+ es.add(time + 12, {"id" => 6, "data" => {"host" => "web01", "message" => "error!!"}})
73
+ es.add(time + 13, {"id" => 7, "data" => {"host" => "web01", "message" => "error!!"}})
74
+ es.add(time + 14, {"id" => 8, "data" => {"host" => "web01", "message" => "error!!"}})
75
+
76
+ filtered_es = d.filter_stream('test.info', es)
77
+ records = filtered_es.instance_variable_get(:@record_array)
78
+
79
+ assert_equal 5, records.length
80
+ assert_equal({"id"=>1, "data" => {"host"=>"web01", "message"=>"error!!"}}, records[0])
81
+ assert_equal({"id"=>2, "data" => {"host"=>"web01", "message"=>"error!!"}}, records[1])
82
+ assert_equal({"id"=>5, "data" => {"host"=>"app01", "message"=>"error!!"}}, records[2])
83
+ assert_equal({"id"=>6, "data" => {"host"=>"web01", "message"=>"error!!"}}, records[3])
84
+ assert_equal({"id"=>7, "data" => {"host"=>"web01", "message"=>"error!!"}}, records[4])
85
+ end
86
+
87
+ def test_emit_tagonly
88
+ return unless defined? Fluent::Filter
89
+
90
+ d = create_driver(CONFIG_TAG_ONLY)
91
+ es = Fluent::MultiEventStream.new
92
+
93
+ time = Time.parse("2012-11-22 11:22:33 UTC").to_i
94
+ es.add(time + 1, {"id" => 1, "host" => "web01", "message" => "1 error!!"})
95
+ es.add(time + 2, {"id" => 2, "host" => "web02", "message" => "2 error!!"})
96
+ es.add(time + 3, {"id" => 3, "host" => "web03", "message" => "3 error!!"})
97
+ es.add(time + 4, {"id" => 4, "host" => "web04", "message" => "4 error!!"})
98
+ es.add(time + 4, {"id" => 5, "host" => "app05", "message" => "5 error!!"})
99
+ es.add(time + 12,{"id" => 6, "host" => "web06", "message" => "6 error!!"})
100
+ es.add(time + 13,{"id" => 7, "host" => "web07", "message" => "7 error!!"})
101
+ es.add(time + 14,{"id" => 8, "host" => "web08", "message" => "8 error!!"})
102
+
103
+ filtered_es = d.filter_stream('test.info', es)
104
+ records = filtered_es.instance_variable_get(:@record_array)
105
+
106
+ assert_equal 4, records.length
107
+ assert_equal({"id"=>1, "host"=>"web01", "message"=>"1 error!!"}, records[0])
108
+ assert_equal({"id"=>2, "host"=>"web02", "message"=>"2 error!!"}, records[1])
109
+ assert_equal({"id"=>6, "host"=>"web06", "message"=>"6 error!!"}, records[2])
110
+ assert_equal({"id"=>7, "host"=>"web07", "message"=>"7 error!!"}, records[3])
111
+ end
112
+
113
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-suppress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - FUJIWARA Shunichiro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-16 00:00:00.000000000 Z
11
+ date: 2014-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -51,11 +51,13 @@ files:
51
51
  - Gemfile
52
52
  - Gemfile.fluentd.lt.0.10.43
53
53
  - LICENSE
54
- - README.rdoc
54
+ - README.md
55
55
  - Rakefile
56
56
  - fluent-plugin-supress.gemspec
57
+ - lib/fluent/plugin/filter_suppress.rb
57
58
  - lib/fluent/plugin/out_suppress.rb
58
59
  - test/helper.rb
60
+ - test/plugin/test_filter_suppress.rb
59
61
  - test/plugin/test_out_suppress.rb
60
62
  homepage: https://github.com/fujiwara/fluent-plugin-suppress
61
63
  licenses:
@@ -83,4 +85,5 @@ specification_version: 4
83
85
  summary: Fluentd plugin to suppress same messages
84
86
  test_files:
85
87
  - test/helper.rb
88
+ - test/plugin/test_filter_suppress.rb
86
89
  - test/plugin/test_out_suppress.rb
@@ -1,71 +0,0 @@
1
- = fluent-plugin-suppress
2
-
3
- == Component
4
-
5
- === SuppressOutout
6
-
7
- Fluentd plugin to suppress same messages.
8
-
9
- == Configuration
10
-
11
- === SuppressOutput
12
-
13
- fluentd.conf
14
-
15
- <match foo.**>
16
- type suppress
17
- interval 10
18
- num 2
19
- attr_keys host,message
20
- add_tag_prefix sp.
21
- </match>
22
-
23
- In [interval] sec, [num] messages which grouped by attr_keys value, add tag prefix "sp" and pass. Other messages will be removed.
24
-
25
- Input messages:
26
-
27
- 2012-11-22T11:22:33 foo.info {"id":1,"host":"web01","message":"error!!"}
28
- 2012-11-22T11:22:34 foo.info {"id":2,"host":"web01","message":"error!!"}
29
- * 2012-11-22T11:22:35 foo.info {"id":3,"host":"web01","message":"error!!"}
30
- * 2012-11-22T11:22:36 foo.info {"id":4,"host":"web01","message":"error!!"}
31
- 2012-11-22T11:22:37 foo.info {"id":5,"host":"app01","message":"error!!"}
32
- * 2012-11-22T11:22:38 foo.info {"id":6,"host":"web01","message":"error!!"}
33
- * 2012-11-22T11:22:39 foo.info {"id":7,"host":"web01","message":"error!!"}
34
- * 2012-11-22T11:22:40 foo.info {"id":8,"host":"web01","message":"error!!"}
35
- 2012-11-22T11:22:45 foo.info {"id":9,"host":"web01","message":"error!!"}
36
- (* = suppressed)
37
-
38
- Output messages:
39
-
40
- 2012-11-22T11:22:33 sp.foo.info {"id":1,"host":"web01","message":"error!!"}
41
- 2012-11-22T11:22:34 sp.foo.info {"id":2,"host":"web01","message":"error!!"}
42
- 2012-11-22T11:22:37 sp.foo.info {"id":5,"host":"app01","message":"error!!"}
43
- 2012-11-22T11:22:45 sp.foo.info {"id":9,"host":"web01","message":"error!!"}
44
-
45
- attr_keys allows nested key name (eg. foo.bar).
46
-
47
- <match foo.**>
48
- type suppress
49
- attr_keys data.host, data.message
50
- </match>
51
-
52
- Input messages will be suppressed by key data.host and data.message.
53
-
54
- 2012-11-22T11:22:33 foo.info {"id":1,"data":{"host":"web01","message":"error!!"}}
55
- 2012-11-22T11:22:34 foo.info {"id":2,"data":{"host":"web01","message":"error!!"}}
56
-
57
- If attr_keys is not specified, suppressed by tag only.
58
-
59
- <match foo.**>
60
- type suppress
61
- </match>
62
-
63
-
64
- == TODO
65
-
66
- - patches welcome!
67
-
68
- == Copyright
69
-
70
- Copyright:: Copyright (c) 2012- FUJIWARA Shunichiro
71
- License:: Apache License, Version 2.0