fluent-plugin-sampling-filter 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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ TAGOMORI Satoshi <tagomoris _at_ gmail.com>
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "simplecov", ">= 0"
13
+ gem "rdoc"
14
+ end
15
+
16
+ gem "fluentd"
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012- TAGOMORI Satoshi
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,50 @@
1
+ = fluent-plugin-sampling-filter
2
+
3
+ == Component
4
+
5
+ === SamplingFilterOutput
6
+
7
+ Do sampling from matching messages to analyse and report messages behavior, and emit sampled messages with modified tag.
8
+
9
+ - sampling rate per tags, or for all
10
+ - remove_prefix of tags for input messages, and add_prefix of tags for output(sampled) messages
11
+
12
+ == Configuration
13
+
14
+ === SamplingFilterOutput
15
+
16
+ Pickup 1/10 messages about each tags(default: 'sample_unit tag'), and add tag prefix 'sampled'.
17
+
18
+ <match **>
19
+ type sampling_filter
20
+ interval 10
21
+ add_prefix sampled
22
+ </match>
23
+
24
+ <match sampled.**>
25
+ # output configurations where to send sampled messages
26
+ </match>
27
+
28
+ Pickup 1/100 messages of all matched messages, and modify tags from input.** to output.**
29
+
30
+ <match input.**>
31
+ type sampling_filter
32
+ interval 100
33
+ sample_unit all
34
+ remove_prefix input
35
+ add_prefix output
36
+ </match>
37
+
38
+ <match sampled.**>
39
+ # output configurations where to send sampled messages
40
+ </match>
41
+
42
+ == TODO
43
+
44
+ - consider what to do next
45
+ - patches welcome!
46
+
47
+ == Copyright
48
+
49
+ Copyright:: Copyright (c) 2012- TAGOMORI Satoshi (tagomoris)
50
+ License:: Apache License, Version 2.0
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "fluent-plugin-sampling-filter"
18
+ gem.homepage = "http://github.com/tagomoris/fluent-plugin-sampling-filter"
19
+ # gem.license = "MIT"
20
+ gem.summary = %Q{fluentd plugin to pickup sample data from matched massages}
21
+ gem.description = %Q{fluentd plugin to pickup sample data from matched massages}
22
+ gem.email = "tagomoris@gmail.com"
23
+ gem.authors = ["TAGOMORI Satoshi"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ # require 'rcov/rcovtask'
36
+ # Rcov::RcovTask.new do |test|
37
+ # test.libs << 'test'
38
+ # test.pattern = 'test/**/test_*.rb'
39
+ # test.verbose = true
40
+ # test.rcov_opts << '--exclude "gems/*"'
41
+ # end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "fluent-plugin-sampling-filter #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,64 @@
1
+ class Fluent::SamplingFilterOutput < Fluent::Output
2
+ Fluent::Plugin.register_output('sampling_filter', self)
3
+
4
+ config_param :interval, :integer
5
+ config_param :sample_unit, :string, :default => 'tag'
6
+ config_param :remove_prefix, :string, :default => nil
7
+ config_param :add_prefix, :string, :default => 'sampled'
8
+
9
+ def configure(conf)
10
+ super
11
+
12
+ if @remove_prefix
13
+ @removed_prefix_string = @remove_prefix + '.'
14
+ @removed_length = @removed_prefix_string.length
15
+ end
16
+ @added_prefix_string = @add_prefix + '.'
17
+
18
+ @sample_unit = case @sample_unit
19
+ when 'tag'
20
+ :tag
21
+ when 'all'
22
+ :all
23
+ else
24
+ raise Fluent::ConfigError, "sample_unit allows only 'tag' or 'all'"
25
+ end
26
+ @counts = {}
27
+ end
28
+
29
+ def emit_sampled(tag, time_record_pairs)
30
+ if @remove_prefix and
31
+ ( (tag.start_with?(@removed_prefix_string) and tag.length > @removed_length) or tag == @remove_prefix)
32
+ tag = tag[@removed_length..-1]
33
+ end
34
+ tag = if tag.length > 0
35
+ @added_prefix_string + tag
36
+ else
37
+ @add_prefix
38
+ end
39
+
40
+ time_record_pairs.each {|t,r|
41
+ Fluent::Engine.emit(tag, t, r)
42
+ }
43
+ end
44
+
45
+ def emit(tag, es, chain)
46
+ t = if @sample_unit == :all
47
+ 'all'
48
+ else
49
+ tag
50
+ end
51
+ @counts[t] ||= 0
52
+ pairs = []
53
+ es.each {|time,record|
54
+ @counts[t] += 1
55
+ if @counts[t] == @interval
56
+ pairs.push [time, record]
57
+ @counts[t] = 0
58
+ end
59
+ }
60
+ emit_sampled(tag, pairs)
61
+
62
+ chain.next
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'fluent/test'
16
+ require 'fluent/plugin/out_sampling_filter'
17
+
18
+ class Test::Unit::TestCase
19
+ end
@@ -0,0 +1,100 @@
1
+ require 'helper'
2
+
3
+ class SamplingFilterOutputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ interval 10
10
+ sample_unit tag
11
+ remove_prefix input
12
+ add_prefix sampled
13
+ ]
14
+
15
+ def create_driver(conf=CONFIG,tag='test')
16
+ Fluent::Test::OutputTestDriver.new(Fluent::SamplingFilterOutput, tag).configure(conf)
17
+ end
18
+
19
+ def test_configure
20
+ assert_raise(Fluent::ConfigError) {
21
+ d = create_driver('')
22
+ }
23
+ d = create_driver %[
24
+ interval 5
25
+ ]
26
+
27
+ assert_equal 5, d.instance.interval
28
+ assert_equal :tag, d.instance.sample_unit
29
+ assert_nil d.instance.remove_prefix
30
+ assert_equal 'sampled', d.instance.add_prefix
31
+
32
+ d = create_driver %[
33
+ interval 1000
34
+ sample_unit all
35
+ remove_prefix test
36
+ add_prefix output
37
+ ]
38
+ assert_equal 1000, d.instance.interval
39
+ assert_equal :all, d.instance.sample_unit
40
+ assert_equal 'test', d.instance.remove_prefix
41
+ assert_equal 'output', d.instance.add_prefix
42
+ end
43
+
44
+ # CONFIG = %[
45
+ # interval 10
46
+ # sample_unit tag
47
+ # remove_prefix input
48
+ # add_prefix sampled
49
+ # ]
50
+ def test_emit
51
+ d1 = create_driver(CONFIG, 'input.hoge1')
52
+ time = Time.parse("2012-01-02 13:14:15").to_i
53
+ d1.run do
54
+ d1.emit({'field1' => 'record1', 'field2' => 1})
55
+ d1.emit({'field1' => 'record2', 'field2' => 2})
56
+ d1.emit({'field1' => 'record3', 'field2' => 3})
57
+ d1.emit({'field1' => 'record4', 'field2' => 4})
58
+ d1.emit({'field1' => 'record5', 'field2' => 5})
59
+ d1.emit({'field1' => 'record6', 'field2' => 6})
60
+ d1.emit({'field1' => 'record7', 'field2' => 7})
61
+ d1.emit({'field1' => 'record8', 'field2' => 8})
62
+ d1.emit({'field1' => 'record9', 'field2' => 9})
63
+ d1.emit({'field1' => 'record10', 'field2' => 10})
64
+ d1.emit({'field1' => 'record11', 'field2' => 11})
65
+ d1.emit({'field1' => 'record12', 'field2' => 12})
66
+ end
67
+ emits = d1.emits
68
+ assert_equal 1, emits.length
69
+ assert_equal 'sampled.hoge1', emits[0][0] # tag
70
+ assert_equal 'record10', emits[0][2]['field1']
71
+ assert_equal 10, emits[0][2]['field2']
72
+
73
+ d2 = create_driver(%[
74
+ interval 3
75
+ ], 'input.hoge2')
76
+ time = Time.parse("2012-01-02 13:14:15").to_i
77
+ d2.run do
78
+ d2.emit({'field1' => 'record1', 'field2' => 1})
79
+ d2.emit({'field1' => 'record2', 'field2' => 2})
80
+ d2.emit({'field1' => 'record3', 'field2' => 3})
81
+ d2.emit({'field1' => 'record4', 'field2' => 4})
82
+ d2.emit({'field1' => 'record5', 'field2' => 5})
83
+ d2.emit({'field1' => 'record6', 'field2' => 6})
84
+ d2.emit({'field1' => 'record7', 'field2' => 7})
85
+ d2.emit({'field1' => 'record8', 'field2' => 8})
86
+ d2.emit({'field1' => 'record9', 'field2' => 9})
87
+ d2.emit({'field1' => 'record10', 'field2' => 10})
88
+ d2.emit({'field1' => 'record11', 'field2' => 11})
89
+ d2.emit({'field1' => 'record12', 'field2' => 12})
90
+ end
91
+ emits = d2.emits
92
+ assert_equal 4, emits.length
93
+ assert_equal 'sampled.input.hoge2', emits[0][0] # tag
94
+
95
+ assert_equal 'record3', emits[0][2]['field1']
96
+ assert_equal 'record6', emits[1][2]['field1']
97
+ assert_equal 'record9', emits[2][2]['field1']
98
+ assert_equal 'record12', emits[3][2]['field1']
99
+ end
100
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-sampling-filter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fluentd
16
+ requirement: &2154789280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2154789280
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ requirement: &2154788800 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2154788800
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &2154788320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2154788320
47
+ - !ruby/object:Gem::Dependency
48
+ name: jeweler
49
+ requirement: &2154787840 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.4
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2154787840
58
+ - !ruby/object:Gem::Dependency
59
+ name: simplecov
60
+ requirement: &2154787360 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2154787360
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: &2154786880 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2154786880
80
+ description: fluentd plugin to pickup sample data from matched massages
81
+ email: tagomoris@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files:
85
+ - LICENSE.txt
86
+ - README.rdoc
87
+ files:
88
+ - .document
89
+ - AUTHORS
90
+ - Gemfile
91
+ - LICENSE.txt
92
+ - README.rdoc
93
+ - Rakefile
94
+ - VERSION
95
+ - lib/fluent/plugin/out_sampling_filter.rb
96
+ - test/helper.rb
97
+ - test/plugin/test_out_sampling_filter.rb
98
+ homepage: http://github.com/tagomoris/fluent-plugin-sampling-filter
99
+ licenses: []
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: 3531476844839040291
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.8.6
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: fluentd plugin to pickup sample data from matched massages
125
+ test_files: []