fluent-plugin-copy_ex 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e55e9309b56820ce9c6e3889d78a7adef469a666
4
+ data.tar.gz: 819fd35752ace0455f78083abfb998fa6dbd0a78
5
+ SHA512:
6
+ metadata.gz: afb6a9e80ba971b9a2b7916f797f1a15e82e8c45da068819e6af2badd5dc7cfed789b587444e2eac9f7d275919aeef3890e5c201d11d93311d640cb577c0c285
7
+ data.tar.gz: f2aefd89cbb13156b6b14215f8e3b32a7f6f85e406c8d71a508f98f0f1e3f223a85e64f7065f3c5d25608799f684b7b6fb5e21790ad3c2c29428e85c7241261d
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /*.gem
2
+ ~*
3
+ #*
4
+ *~
5
+ .bundle
6
+ Gemfile.lock
7
+ .rbenv-version
8
+ vendor
9
+ doc/*
10
+ tmp/*
11
+ .yardoc
12
+ .ruby-version
13
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - 2.1.*
5
+ gemfile:
6
+ - Gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ ## 0.0.1
2
+
3
+ First version
4
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Same with Fluentd
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # fluent-plugin-copy_ex
2
+
3
+ ## About
4
+
5
+ Fluentd out\_copy extension
6
+
7
+ ## What is this for?
8
+
9
+ Think of `out_copy` configuration as folloings:
10
+
11
+ ```apache
12
+ <match **>
13
+ type copy
14
+ <store>
15
+ type plugin1
16
+ </store>
17
+ <store>
18
+ type plugin2
19
+ </store>
20
+ </match>
21
+ ```
22
+
23
+ In the current Fluentd, when plugin1 raises an error internally, the chain is broken and the plugin2 is not executed.
24
+
25
+ The `out_copy_ex` supplies `ignore_error` option so that it will not break the chain and the plugin2 is executed.
26
+
27
+ See https://github.com/fluent/fluentd/pull/303 for discussions.
28
+
29
+
30
+ ## Configuration
31
+
32
+ ```apache
33
+ <match **>
34
+ type copy_ex
35
+ <store ignore_error>
36
+ type plugin1
37
+ </store>
38
+ <store ignore_error>
39
+ type plugin2
40
+ </store>
41
+ </match>
42
+ ```
43
+
44
+ ## Parameters
45
+
46
+ Basically same with out\_copy plugin. See http://docs.fluentd.org/articles/out_copy
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create new [Pull Request](../../pull/new/master)
55
+
56
+ ## ChangeLog
57
+
58
+ See [CHANGELOG.md](CHANGELOG.md) for details.
59
+
60
+ ## Copyright
61
+
62
+ * Copyright (c) 2014- Naotoshi Seo
63
+ * See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
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/**/*.rb'
8
+ test.verbose = true
9
+ end
10
+ task :default => :test
11
+
12
+ desc 'Open an irb session preloaded with the gem library'
13
+ task :console do
14
+ sh 'irb -rubygems -I lib'
15
+ end
16
+ task :c => :console
@@ -0,0 +1,9 @@
1
+ <match **>
2
+ type copy_ex
3
+ <store ignore-failure>
4
+ type stdout
5
+ </store>
6
+ <store ignore-failure>
7
+ type stdout
8
+ </store>
9
+ </match>
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "fluent-plugin-copy_ex"
6
+ s.version = "0.0.1"
7
+ s.authors = ["Naotoshi Seo"]
8
+ s.email = ["sonots@gmail.com"]
9
+ s.homepage = "https://github.com/sonots/fluent-plugin-copy_ex"
10
+ s.summary = "Fluentd out_copy extension"
11
+ s.description = s.summary
12
+ s.licenses = ["MIT"]
13
+
14
+ s.rubyforge_project = "fluent-plugin-copy_ex"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "fluentd"
22
+ s.add_development_dependency "rake"
23
+ s.add_development_dependency "pry"
24
+ s.add_development_dependency "pry-nav"
25
+ end
@@ -0,0 +1,72 @@
1
+ module Fluent
2
+ class CopyExOutput < MultiOutput
3
+ Plugin.register_output('copy_ex', self)
4
+
5
+ config_param :deep_copy, :bool, :default => false
6
+
7
+ def initialize
8
+ super
9
+ @outputs = []
10
+ @ignore_errors = []
11
+ end
12
+
13
+ attr_reader :outputs, :ignore_errors
14
+
15
+ def configure(conf)
16
+ super
17
+ conf.elements.select {|e|
18
+ e.name == 'store'
19
+ }.each {|e|
20
+ type = e['type']
21
+ unless type
22
+ raise ConfigError, "Missing 'type' parameter on <store> directive"
23
+ end
24
+ log.debug "adding store type=#{type.dump}"
25
+
26
+ output = Plugin.new_output(type)
27
+ output.configure(e)
28
+ @outputs << output
29
+
30
+ @ignore_errors << (e.arg == "ignore_error")
31
+ }
32
+ end
33
+
34
+ def start
35
+ @outputs.each {|o|
36
+ o.start
37
+ }
38
+ end
39
+
40
+ def shutdown
41
+ @outputs.each {|o|
42
+ o.shutdown
43
+ }
44
+ end
45
+
46
+ def emit(tag, es, chain)
47
+ unless es.repeatable?
48
+ m = MultiEventStream.new
49
+ es.each {|time,record|
50
+ m.add(time, record)
51
+ }
52
+ es = m
53
+ end
54
+
55
+ # Here, we do not use OutputChain for custom
56
+ @outputs.each_index do |idx|
57
+ _es = @deep_copy ? es.dup : es
58
+ begin
59
+ @outputs[idx].emit(tag, _es, NullOutputChain.instance)
60
+ rescue => e
61
+ if @ignore_errors[idx]
62
+ log.error :error_class => e.class, :error => e.message
63
+ else
64
+ raise e
65
+ end
66
+ end
67
+ end
68
+
69
+ chain.next
70
+ end
71
+ end
72
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
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
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ require 'fluent/plugin/out_copy_ex'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,208 @@
1
+ require 'fluent/test'
2
+
3
+ class CopyExOutputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ <store>
10
+ type test
11
+ name c0
12
+ </store>
13
+ <store>
14
+ type test
15
+ name c1
16
+ </store>
17
+ <store>
18
+ type test
19
+ name c2
20
+ </store>
21
+ ]
22
+
23
+ IGNORE_ERROR_CONFIG = %[
24
+ <store ignore_error>
25
+ type test
26
+ name c0
27
+ </store>
28
+ <store ignore_error>
29
+ type test
30
+ name c1
31
+ </store>
32
+ <store>
33
+ type test
34
+ name c2
35
+ </store>
36
+ ]
37
+
38
+ def create_driver(conf = CONFIG)
39
+ Fluent::Test::OutputTestDriver.new(Fluent::CopyExOutput).configure(conf)
40
+ end
41
+
42
+ def test_configure
43
+ d = create_driver
44
+
45
+ outputs = d.instance.outputs
46
+ assert_equal 3, outputs.size
47
+ assert_equal Fluent::TestOutput, outputs[0].class
48
+ assert_equal Fluent::TestOutput, outputs[1].class
49
+ assert_equal Fluent::TestOutput, outputs[2].class
50
+ assert_equal "c0", outputs[0].name
51
+ assert_equal "c1", outputs[1].name
52
+ assert_equal "c2", outputs[2].name
53
+ end
54
+
55
+ def test_configure_ignore_error
56
+ d = create_driver(IGNORE_ERROR_CONFIG)
57
+
58
+ outputs = d.instance.outputs
59
+ ignore_errors = d.instance.ignore_errors
60
+ assert_equal outputs.size, ignore_errors.size
61
+ assert_equal true, ignore_errors[0]
62
+ assert_equal true, ignore_errors[1]
63
+ assert_equal false, ignore_errors[2]
64
+ end
65
+
66
+ def test_emit
67
+ d = create_driver
68
+
69
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
70
+ d.emit({"a"=>1}, time)
71
+ d.emit({"a"=>2}, time)
72
+
73
+ d.instance.outputs.each {|o|
74
+ assert_equal [
75
+ [time, {"a"=>1}],
76
+ [time, {"a"=>2}],
77
+ ], o.events
78
+ }
79
+ end
80
+
81
+ def test_msgpack_es_emit_bug
82
+ d = Fluent::Test::OutputTestDriver.new(Fluent::CopyExOutput)
83
+
84
+ outputs = %w(p1 p2).map do |pname|
85
+ p = Fluent::Plugin.new_output('test')
86
+ p.configure('name' => pname)
87
+ p.define_singleton_method(:emit) do |tag, es, chain|
88
+ es.each do |time, record|
89
+ super(tag, [[time, record]], chain)
90
+ end
91
+ end
92
+ p
93
+ end
94
+
95
+ d.instance.instance_eval { @outputs = outputs }
96
+
97
+ es = if defined?(MessagePack::Packer)
98
+ time = Time.parse("2013-05-26 06:37:22 UTC").to_i
99
+ packer = MessagePack::Packer.new
100
+ packer.pack([time, {"a" => 1}])
101
+ packer.pack([time, {"a" => 2}])
102
+ Fluent::MessagePackEventStream.new(packer.to_s)
103
+ else
104
+ events = "#{[time, {"a" => 1}].to_msgpack}#{[time, {"a" => 2}].to_msgpack}"
105
+ Fluent::MessagePackEventStream.new(events)
106
+ end
107
+
108
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
109
+
110
+ d.instance.outputs.each { |o|
111
+ assert_equal [
112
+ [time, {"a"=>1}],
113
+ [time, {"a"=>2}],
114
+ ], o.events
115
+ }
116
+ end
117
+
118
+ def create_event_test_driver(is_deep_copy = false)
119
+ deep_copy_config = %[
120
+ deep_copy true
121
+ ]
122
+
123
+ output1 = Fluent::Plugin.new_output('test')
124
+ output1.configure('name' => 'output1')
125
+ output1.define_singleton_method(:emit) do |tag, es, chain|
126
+ es.each do |time, record|
127
+ record['foo'] = 'bar'
128
+ super(tag, [[time, record]], chain)
129
+ end
130
+ end
131
+
132
+ output2 = Fluent::Plugin.new_output('test')
133
+ output2.configure('name' => 'output2')
134
+ output2.define_singleton_method(:emit) do |tag, es, chain|
135
+ es.each do |time, record|
136
+ super(tag, [[time, record]], chain)
137
+ end
138
+ end
139
+
140
+ outputs = [output1, output2]
141
+
142
+ d = Fluent::Test::OutputTestDriver.new(Fluent::CopyExOutput)
143
+ d = d.configure(deep_copy_config) if is_deep_copy
144
+ d.instance.instance_eval { @outputs = outputs }
145
+ d
146
+ end
147
+
148
+ def test_one_event
149
+ time = Time.parse("2013-05-26 06:37:22 UTC").to_i
150
+
151
+ d = create_event_test_driver(false)
152
+ es = Fluent::OneEventStream.new(time, {"a" => 1})
153
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
154
+
155
+ assert_equal [
156
+ [[time, {"a"=>1, "foo"=>"bar"}]],
157
+ [[time, {"a"=>1, "foo"=>"bar"}]]
158
+ ], d.instance.outputs.map{ |o| o.events }
159
+
160
+ d = create_event_test_driver(true)
161
+ es = Fluent::OneEventStream.new(time, {"a" => 1})
162
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
163
+
164
+ assert_equal [
165
+ [[time, {"a"=>1, "foo"=>"bar"}]],
166
+ [[time, {"a"=>1}]]
167
+ ], d.instance.outputs.map{ |o| o.events }
168
+ end
169
+
170
+ def test_multi_event
171
+ time = Time.parse("2013-05-26 06:37:22 UTC").to_i
172
+
173
+ d = create_event_test_driver(false)
174
+ es = Fluent::MultiEventStream.new
175
+ es.add(time, {"a" => 1})
176
+ es.add(time, {"b" => 2})
177
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
178
+
179
+ assert_equal [
180
+ [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
181
+ [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]]
182
+ ], d.instance.outputs.map{ |o| o.events }
183
+
184
+ d = create_event_test_driver(true)
185
+ es = Fluent::MultiEventStream.new
186
+ es.add(time, {"a" => 1})
187
+ es.add(time, {"b" => 2})
188
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
189
+
190
+ assert_equal [
191
+ [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
192
+ [[time, {"a"=>1}], [time, {"b"=>2}]]
193
+ ], d.instance.outputs.map{ |o| o.events }
194
+ end
195
+
196
+ def test_ignore_error
197
+ d = create_driver(IGNORE_ERROR_CONFIG)
198
+
199
+ # override to raise an error
200
+ d.instance.outputs.first.define_singleton_method(:emit) do |tag, es, chain|
201
+ raise ArgumentError, 'Failed'
202
+ end
203
+
204
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
205
+ assert_nothing_raised { d.emit({"a"=>1}, time) }
206
+ end
207
+ end
208
+
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-copy_ex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Naotoshi Seo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-30 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: pry
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: pry-nav
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: Fluentd out_copy extension
70
+ email:
71
+ - sonots@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - CHANGELOG.md
79
+ - Gemfile
80
+ - LICENSE
81
+ - README.md
82
+ - Rakefile
83
+ - example/fluent.conf
84
+ - fluent-plugin-copy_ex.gemspec
85
+ - lib/fluent/plugin/out_copy_ex.rb
86
+ - test/helper.rb
87
+ - test/plugin/test_out_copy_ex.rb
88
+ homepage: https://github.com/sonots/fluent-plugin-copy_ex
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project: fluent-plugin-copy_ex
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Fluentd out_copy extension
112
+ test_files:
113
+ - test/helper.rb
114
+ - test/plugin/test_out_copy_ex.rb