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.
- data/.document +5 -0
- data/AUTHORS +1 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +13 -0
- data/README.rdoc +50 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/fluent/plugin/out_sampling_filter.rb +64 -0
- data/test/helper.rb +19 -0
- data/test/plugin/test_out_sampling_filter.rb +100 -0
- metadata +125 -0
data/.document
ADDED
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"
|
data/LICENSE.txt
ADDED
|
@@ -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.
|
data/README.rdoc
ADDED
|
@@ -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
|
data/Rakefile
ADDED
|
@@ -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
|
data/test/helper.rb
ADDED
|
@@ -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: []
|