fluent-plugin-fork 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9a6046f60ea7ea3def073da545f25629badae3e2
4
+ data.tar.gz: 89c121b947e6e4ecb7c578eb00890f68cc36f8b1
5
+ SHA512:
6
+ metadata.gz: 68a3e769a9fb09e3086026d3ce4ccefd19f488e5949285a8810c1268945b0695a8fd4009e6e10506bd6ae9821275baad6588101e142e6c332bc591ee82fbcb25
7
+ data.tar.gz: 9dee3e9e0ba50b0d03576044e44057780d97d3935d010013b4bb06a069c14a3d0347145f08dbd6d9775a1119c3532e1e121faeed17955c0dcdcd31a2b11e9534
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ ~*
3
+ *~
4
+ .bundle
5
+ Gemfile.lock
6
+ vendor/
7
+ doc/
8
+ tmp/
9
+ log/
10
+ pkg/
11
+ coverage/
12
+ .yardoc
13
+ .rbenv-version
14
+ .ruby-version
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+
8
+ script: "bundle exec rake spec"
9
+
10
+ branches:
11
+ only:
12
+ - master
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Daisuke Taniwaki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ [![Build Status](https://secure.travis-ci.org/dtaniwaki/fluent-plugin-fork.png?branch=master)](http://travis-ci.org/dtaniwaki/fluent-plugin-fork) [![Coverage Status](https://coveralls.io/repos/dtaniwaki/fluent-plugin-fork/badge.png?branch=master)](https://coveralls.io/r/dtaniwaki/fluent-plugin-fork?branch=master)
2
+
3
+ # fluent-plugin-fork
4
+
5
+ Fork output by separating values for fluentd
6
+
7
+ # Installation
8
+
9
+ ### td-agent(Linux)
10
+
11
+ ```
12
+ /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-fork
13
+ ```
14
+
15
+ ### td-agent(Mac)
16
+
17
+ ```
18
+ sudo /usr/local/Cellar/td-agent/1.1.XX/bin/fluent-gem install fluent-plugin-fork
19
+ ```
20
+
21
+ ### fluentd only
22
+
23
+ ```
24
+ gem install fluent-plugin-fork
25
+ ```
26
+
27
+ # Configuration
28
+
29
+ ```
30
+ output_tag tag_to_output
31
+ output_key key_to_output
32
+ separator ,
33
+ fork_key key_to_fork
34
+ max_size 15
35
+ max_fallback log
36
+ no_unique true
37
+ ```
38
+
39
+ ### output_tag
40
+
41
+ Tag to output forked values
42
+
43
+ ### output_key
44
+
45
+ Key name to output forked values
46
+
47
+ ### fork_key
48
+
49
+ Key name to fork
50
+
51
+ ### separator (Optional)
52
+
53
+ Separator to separate the values
54
+
55
+ Default: `,`
56
+
57
+ ### max_size (Optional)
58
+
59
+ Max size of forked values.
60
+
61
+ Default: `nil`
62
+
63
+ ### max_fallback (Optional)
64
+
65
+ Strategy when the size of values exceeds max_size. Only effective when you set max_size.
66
+
67
+ `log` to log the record
68
+ `drop` to drop exceeded values
69
+
70
+ Default: `log`
71
+
72
+ ### no_unique (Optional)
73
+
74
+ Flag to emit redundant values.
75
+
76
+ Default: `false`
77
+
78
+ # Contributing
79
+
80
+ 1. Fork it
81
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
82
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
83
+ 4. Push to the branch (`git push origin my-new-feature`)
84
+ 5. Create new [Pull Request](../../pull/new/master)
85
+
86
+ # Copyright
87
+
88
+ Copyright (c) 2014 Daisuke Taniwaki. See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "fluent-plugin-fork"
5
+ gem.version = "0.1.0"
6
+ gem.authors = ["Daisuke Taniwaki"]
7
+ gem.email = "daisuketaniwaki@gmail.com"
8
+ gem.homepage = "https://github.com/dtaniwaki/fluent-plugin-fork"
9
+ gem.description = "Fork output by separating values for fluentd"
10
+ gem.summary = "Fork output by separating values for fluentd"
11
+ gem.licenses = ["MIT"]
12
+
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_runtime_dependency "fluentd"
19
+ gem.add_development_dependency "rake"
20
+ gem.add_development_dependency "rspec"
21
+ gem.add_development_dependency "coveralls"
22
+ end
@@ -0,0 +1,64 @@
1
+ module Fluent
2
+ class ForkOutput < Output
3
+ class MaxForkSizeError < StandardError; end
4
+
5
+ Fluent::Plugin.register_output('fork', self)
6
+
7
+ unless method_defined?(:log)
8
+ define_method(:log) { $log }
9
+ end
10
+
11
+ def initialize
12
+ super
13
+ end
14
+
15
+ config_param :output_tag, :string
16
+ config_param :output_key, :string
17
+ config_param :fork_key, :string
18
+ config_param :separator, :string, default: ','
19
+ config_param :max_size, :integer, default: nil
20
+ config_param :max_fallback, :string, default: 'log'
21
+ config_param :no_unique, :bool, default: false
22
+
23
+ def configure(conf)
24
+ super
25
+
26
+ fallbacks = %w(drop log)
27
+ raise Fluent::ConfigError, "max_fallback must be one of #{fallbacks.inspect}" unless fallbacks.include?(@max_fallback)
28
+ end
29
+
30
+ def emit(tag, es, chain)
31
+ es.each do |time, record|
32
+ org_value = record[@fork_key]
33
+ if org_value.nil?
34
+ log.trace "#{tag} - #{time}: skip to fork #{@fork_key}=#{org_value}"
35
+ next
36
+ end
37
+ log.trace "#{tag} - #{time}: try to fork #{@fork_key}=#{org_value}"
38
+
39
+ values = org_value.split(@separator)
40
+
41
+ values = values.uniq unless @no_unique
42
+
43
+ if @max_size && @max_size < values.size
44
+ case @max_fallback
45
+ when 'drop'
46
+ log.warn "#{tag} - #{time}: Drop too many forked values (max=#{@max_size}) : #{org_value}"
47
+ values = values.take(@max_size)
48
+ when 'log'
49
+ log.info "#{tag} - #{time}: Too many forked values (max=#{@max_size}) : #{org_value}"
50
+ end
51
+ end
52
+
53
+ values.reject{ |value| value.to_s == '' }.each do |value|
54
+ log.trace "#{tag} - #{time}: reemit #{@output_key}=#{value} for #{@output_tag}"
55
+ Engine.emit(@output_tag, time, record.reject{ |k, v| k == @fork_key }.merge(@output_key => value))
56
+ end
57
+ end
58
+
59
+ chain.next
60
+ rescue => e
61
+ log.error "#{e.message}: #{e.backtrace.join(', ')}"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluent::ForkOutput do
4
+ let(:tag) { "test.fork" }
5
+ let(:required_params) { {output_tag: 'ot', output_key: 'ok', fork_key: 'sk'} }
6
+ let(:params) { required_params }
7
+ let(:config) { params.map{ |k, v| "#{k} #{v}" }.join("\n") }
8
+ subject { Fluent::Test::OutputTestDriver.new(Fluent::ForkOutput, tag).configure(config) }
9
+
10
+ describe "#configure" do
11
+ let(:params) { required_params.merge(separator: '-', max_size: 5, max_fallback: 'drop', no_unique: true) }
12
+ it "does not raise any error" do
13
+ expect{ subject }.not_to raise_error
14
+ expect(subject.instance.output_tag).to eq('ot')
15
+ expect(subject.instance.output_key).to eq('ok')
16
+ expect(subject.instance.fork_key).to eq('sk')
17
+ expect(subject.instance.separator).to eq('-')
18
+ expect(subject.instance.no_unique).to eq(true)
19
+ expect(subject.instance.max_size).to eq(5)
20
+ expect(subject.instance.max_fallback).to eq('drop')
21
+ end
22
+ context "without optional params" do
23
+ let(:params) { required_params }
24
+ it "use default values" do
25
+ expect{ subject }.not_to raise_error
26
+ expect(subject.instance.output_tag).to eq('ot')
27
+ expect(subject.instance.output_key).to eq('ok')
28
+ expect(subject.instance.fork_key).to eq('sk')
29
+ expect(subject.instance.separator).to eq(',')
30
+ expect(subject.instance.no_unique).to eq(false)
31
+ expect(subject.instance.max_size).to eq(nil)
32
+ expect(subject.instance.max_fallback).to eq('log')
33
+ end
34
+ end
35
+ context "with invalid fallback" do
36
+ let(:params) { required_params.merge(max_fallback: 'invalid') }
37
+ it "raise an error" do
38
+ expect{ subject }.to raise_error(Fluent::ConfigError)
39
+ end
40
+ end
41
+ [:output_tag, :output_key, :fork_key].each do |rk|
42
+ context "no #{rk}" do
43
+ let(:params) { required_params.reject{ |k, v| k == rk } }
44
+ it "raises Fluent::ConfigError" do
45
+ expect{ subject }.to raise_error(Fluent::ConfigError)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#run" do
52
+ let(:time) { Time.now.to_i }
53
+ it "forks" do
54
+ subject.run { subject.emit({"sk" => "2,3,4,5"}, time) }
55
+ expect(subject.emits.size).to eq(4)
56
+ expect(subject.emits).to include(["ot", time, {"ok" => "2"}])
57
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
58
+ expect(subject.emits).to include(["ot", time, {"ok" => "4"}])
59
+ expect(subject.emits).to include(["ot", time, {"ok" => "5"}])
60
+ end
61
+ it "forks uniquely" do
62
+ subject.run { subject.emit({"sk" => "2,3,4,3"}, time) }
63
+ expect(subject.emits.size).to eq(3)
64
+ expect(subject.emits).to include(["ot", time, {"ok" => "2"}])
65
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
66
+ expect(subject.emits).to include(["ot", time, {"ok" => "4"}])
67
+ end
68
+ it "forks with other params" do
69
+ subject.run { subject.emit({"sk" => "2,3,4,3", "o1" => 1, "o2" => 2}, time) }
70
+ expect(subject.emits.size).to eq(3)
71
+ expect(subject.emits).to include(["ot", time, {"ok" => "2", "o1" => 1, "o2" => 2}])
72
+ expect(subject.emits).to include(["ot", time, {"ok" => "3", "o1" => 1, "o2" => 2}])
73
+ expect(subject.emits).to include(["ot", time, {"ok" => "4", "o1" => 1, "o2" => 2}])
74
+ end
75
+ context "with no_unique option" do
76
+ let(:params) { required_params.merge(no_unique: true) }
77
+ it "forks for redundant values" do
78
+ subject.run { subject.emit({"sk" => "2,3,4,3"}, time) }
79
+ expect(subject.emits.size).to eq(4)
80
+ expect(subject.emits).to include(["ot", time, {"ok" => "2"}])
81
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
82
+ expect(subject.emits).to include(["ot", time, {"ok" => "4"}])
83
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
84
+ end
85
+ end
86
+ context "with separator option" do
87
+ let(:params) { required_params.merge(separator: '-') }
88
+ it "forks by separating with '-'" do
89
+ subject.run { subject.emit({"sk" => "2-3-4-5"}, time) }
90
+ expect(subject.emits.size).to eq(4)
91
+ expect(subject.emits).to include(["ot", time, {"ok" => "2"}])
92
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
93
+ expect(subject.emits).to include(["ot", time, {"ok" => "4"}])
94
+ expect(subject.emits).to include(["ot", time, {"ok" => "5"}])
95
+ end
96
+ end
97
+ context "with max_size and max_fallback options" do
98
+ describe "log" do
99
+ let(:params) { required_params.merge(max_size: 3, max_fallback: 'log') }
100
+ it "writes a log" do
101
+ expect(subject.instance.log).to receive(:info).with(/Too many forked values/)
102
+ subject.run { subject.emit({"sk" => "2,3,4,5"}, time) }
103
+ end
104
+ end
105
+ describe "drop" do
106
+ let(:params) { required_params.merge(max_size: 3, max_fallback: 'drop') }
107
+ it "drops exceeded values" do
108
+ subject.run { subject.emit({"sk" => "2,3,4,5"}, time) }
109
+ expect(subject.emits.size).to eq(3)
110
+ expect(subject.emits).to include(["ot", time, {"ok" => "2"}])
111
+ expect(subject.emits).to include(["ot", time, {"ok" => "3"}])
112
+ expect(subject.emits).to include(["ot", time, {"ok" => "4"}])
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
5
+ require 'fluent/test'
6
+ require 'fluent/plugin/out_fork'
7
+
8
+ RSpec.configure do |config|
9
+ end
10
+
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-fork
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daisuke Taniwaki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: coveralls
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Fork output by separating values for fluentd
70
+ email: daisuketaniwaki@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".gitignore"
76
+ - ".travis.yml"
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - fluent-plugin-fork.gemspec
82
+ - lib/fluent/plugin/out_fork.rb
83
+ - spec/plugin/out_fork_spec.rb
84
+ - spec/spec_helper.rb
85
+ homepage: https://github.com/dtaniwaki/fluent-plugin-fork
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.0.14
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Fork output by separating values for fluentd
109
+ test_files:
110
+ - spec/plugin/out_fork_spec.rb
111
+ - spec/spec_helper.rb
112
+ has_rdoc: