fluent-plugin-kinesis 1.3.0 → 2.0.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -23
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +9 -9
  5. data/LICENSE.txt +201 -40
  6. data/Makefile +24 -31
  7. data/README.md +179 -308
  8. data/Rakefile +9 -13
  9. data/benchmark/task.rake +96 -58
  10. data/fluent-plugin-kinesis.gemspec +15 -19
  11. data/gemfiles/Gemfile.fluentd-0.12 +10 -10
  12. data/lib/fluent/plugin/kinesis.rb +166 -0
  13. data/lib/fluent/plugin/kinesis_helper/aggregator.rb +99 -0
  14. data/lib/fluent/plugin/kinesis_helper/api.rb +152 -121
  15. data/lib/fluent/plugin/kinesis_helper/client.rb +125 -12
  16. data/lib/fluent/plugin/out_kinesis_firehose.rb +40 -27
  17. data/lib/fluent/plugin/out_kinesis_streams.rb +51 -30
  18. data/lib/fluent/plugin/out_kinesis_streams_aggregated.rb +76 -0
  19. data/lib/fluent_plugin_kinesis/version.rb +10 -10
  20. metadata +18 -70
  21. data/README-v0.4.md +0 -348
  22. data/benchmark/dummy.conf +0 -0
  23. data/gemfiles/Gemfile.aws-sdk-2.4 +0 -20
  24. data/gemfiles/Gemfile.fluentd-0.10.58 +0 -20
  25. data/gemfiles/Gemfile.fluentd-0.14.11 +0 -20
  26. data/gemfiles/Gemfile.ruby-2.0 +0 -21
  27. data/gemfiles/Gemfile.ruby-2.1 +0 -21
  28. data/lib/fluent/plugin/kinesis_helper.rb +0 -36
  29. data/lib/fluent/plugin/kinesis_helper/class_methods.rb +0 -123
  30. data/lib/fluent/plugin/kinesis_helper/credentials.rb +0 -51
  31. data/lib/fluent/plugin/kinesis_helper/error.rb +0 -43
  32. data/lib/fluent/plugin/kinesis_helper/format.rb +0 -85
  33. data/lib/fluent/plugin/kinesis_helper/initialize.rb +0 -59
  34. data/lib/fluent/plugin/kinesis_helper/kpl.rb +0 -82
  35. data/lib/fluent/plugin/out_kinesis.rb +0 -323
  36. data/lib/fluent/plugin/out_kinesis_producer.rb +0 -48
  37. data/lib/fluent/plugin/patched_detach_process_impl.rb +0 -103
  38. data/lib/kinesis_producer.rb +0 -24
  39. data/lib/kinesis_producer/binary.rb +0 -10
  40. data/lib/kinesis_producer/daemon.rb +0 -270
  41. data/lib/kinesis_producer/library.rb +0 -122
  42. data/lib/kinesis_producer/protobuf/config.pb.rb +0 -66
  43. data/lib/kinesis_producer/protobuf/messages.pb.rb +0 -151
  44. data/lib/kinesis_producer/tasks/binary.rake +0 -73
data/Rakefile CHANGED
@@ -1,16 +1,16 @@
1
1
  #
2
- # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  #
4
- # Licensed under the Amazon Software License (the "License").
5
- # You may not use this file except in compliance with the License.
6
- # A copy of the License is located at
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # may not use this file except in compliance with the License. A copy of
6
+ # the License is located at
7
7
  #
8
- # http://aws.amazon.com/asl/
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
9
  #
10
- # or in the "license" file accompanying this file. This file is distributed
11
- # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12
- # express or implied. See the License for the specific language governing
13
- # permissions and limitations under the License.
10
+ # or in the "license" file accompanying this file. This file is
11
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # ANY KIND, either express or implied. See the License for the specific
13
+ # language governing permissions and limitations under the License.
14
14
 
15
15
  require "bundler/gem_tasks"
16
16
 
@@ -23,8 +23,4 @@ Rake::TestTask.new do |test|
23
23
  test.options = '-v'
24
24
  end
25
25
 
26
- load 'kinesis_producer/tasks/binary.rake'
27
- Rake::Task[:build].enhance [:binaries]
28
- Rake::Task[:test].enhance [:binaries]
29
-
30
26
  load 'benchmark/task.rake'
data/benchmark/task.rake CHANGED
@@ -1,72 +1,110 @@
1
1
  #
2
- # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  #
4
- # Licensed under the Amazon Software License (the "License").
5
- # You may not use this file except in compliance with the License.
6
- # A copy of the License is located at
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # may not use this file except in compliance with the License. A copy of
6
+ # the License is located at
7
7
  #
8
- # http://aws.amazon.com/asl/
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
9
  #
10
- # or in the "license" file accompanying this file. This file is distributed
11
- # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12
- # express or implied. See the License for the specific language governing
13
- # permissions and limitations under the License.
10
+ # or in the "license" file accompanying this file. This file is
11
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # ANY KIND, either express or implied. See the License for the specific
13
+ # language governing permissions and limitations under the License.
14
14
 
15
- require_relative '../test/dummy_server'
15
+ require_relative '../test/helper'
16
+ require 'fluent/plugin/out_kinesis_streams'
17
+ require 'fluent/plugin/out_kinesis_streams_aggregated'
18
+ require 'fluent/plugin/out_kinesis_firehose'
19
+ require 'benchmark'
20
+ require 'net/empty_port'
16
21
 
17
- task :benchmark do
18
- server = DummyServer.start
19
- conf = profile_conf(ENV["TYPE"] || 'streams', ENV["RATE"] || 1000, server)
20
- pid = spawn("bundle exec fluentd -i '#{conf}' -c benchmark/dummy.conf")
21
- sleep 10
22
- Process.kill("TERM", pid)
23
- Process.wait
24
- puts "Results: requets: #{server.requests.size}, raw_records: #{server.raw_records.size}, records: #{server.records.size}"
25
- server.shutdown
22
+ namespace :benchmark do
23
+ task :local do
24
+ KinesisBenchmark.new.run
25
+ end
26
+ task :remote do
27
+ KinesisBenchmark.new(false).run
28
+ end
26
29
  end
27
30
 
28
- def profile_conf(type, rate, server)
29
- additional_conf = case type
30
- when 'streams', 'firehose'
31
- <<-EOS
32
- endpoint https://localhost:#{server.port}
33
- ssl_verify_peer false
34
- EOS
35
- when 'producer'
36
- <<-EOS
37
- debug true
38
- <kinesis_producer>
39
- custom_endpoint localhost
40
- port #{server.port}
41
- verify_certificate false
42
- record_max_buffered_time 1000
43
- log_level error
44
- </kinesis_producer>
45
- EOS
46
- end
31
+ class KinesisBenchmark
32
+ def initialize(local = true)
33
+ @local = local
34
+ Fluent::Test.setup
35
+ end
47
36
 
48
- conf = <<-EOS
49
- <source>
50
- @type dummy
51
- tag dummy
52
- rate #{rate}
53
- </source>
37
+ def run
38
+ setup
39
+ benchmark(ENV['SIZE'] || 100, ENV['COUNT'] || 10000)
40
+ teardown
41
+ end
54
42
 
55
- <match dummy>
56
- @type kinesis_#{type}
57
- flush_interval 1
58
- buffer_chunk_limit 1m
59
- try_flush_interval 0.1
60
- queued_chunk_flush_interval 0.01
61
- @log_level debug
43
+ def setup
44
+ return if not @local
45
+ @port = Net::EmptyPort.empty_port
46
+ @server_pid = fork do
47
+ Process.setsid
48
+ server = DummyServer.start(port: @port)
49
+ Signal.trap("TERM") do
50
+ server.shutdown
51
+ end
52
+ server.thread.join
53
+ end
54
+ Net::EmptyPort.wait(@port, 3)
55
+ end
62
56
 
63
- num_threads 100
57
+ def teardown
58
+ return if not @local
59
+ Process.kill "TERM", @server_pid
60
+ Process.waitpid @server_pid
61
+ end
64
62
 
65
- region ap-northeast-1
66
- stream_name fluent-plugin-test
63
+ def default_config
64
+ conf = %[
65
+ log_level error
66
+ region ap-northeast-1
67
+ data_key a
68
+ ]
69
+ if @local
70
+ conf += %[
71
+ endpoint https://localhost:#{@port}
72
+ ssl_verify_peer false
73
+ ]
74
+ end
75
+ conf
76
+ end
67
77
 
68
- #{additional_conf}
69
- </match>
70
- EOS
71
- conf
78
+ def create_driver(type, conf = default_config)
79
+ klass = case type
80
+ when :streams
81
+ Fluent::KinesisStreamsOutput
82
+ when :streams_aggregated
83
+ Fluent::KinesisStreamsAggregatedOutput
84
+ when :firehose
85
+ Fluent::KinesisFirehoseOutput
86
+ end
87
+ conf += case type
88
+ when :streams, :streams_aggregated
89
+ "stream_name fluent-plugin-test"
90
+ when :firehose
91
+ "delivery_stream_name fluent-plugin-test"
92
+ end
93
+ if fluentd_v0_12?
94
+ Fluent::Test::BufferedOutputTestDriver.new(klass) do
95
+ end.configure(conf)
96
+ else
97
+ Fluent::Test::Driver::Output.new(klass) do
98
+ end.configure(conf)
99
+ end
100
+ end
101
+
102
+ def benchmark(size, count)
103
+ record = {"a"=>"a"*size}
104
+ Benchmark.bmbm(20) do |x|
105
+ [:streams_aggregated, :streams, :firehose].each do |type|
106
+ x.report(type) { driver_run(create_driver(type), count.times.map{|i|record}) }
107
+ end
108
+ end
109
+ end
72
110
  end
@@ -1,22 +1,21 @@
1
1
  # coding: utf-8
2
2
  #
3
- # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
4
  #
5
- # Licensed under the Amazon Software License (the "License").
6
- # You may not use this file except in compliance with the License.
7
- # A copy of the License is located at
5
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
6
+ # may not use this file except in compliance with the License. A copy of
7
+ # the License is located at
8
8
  #
9
- # http://aws.amazon.com/asl/
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
10
  #
11
- # or in the "license" file accompanying this file. This file is distributed
12
- # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13
- # express or implied. See the License for the specific language governing
14
- # permissions and limitations under the License.
11
+ # or in the "license" file accompanying this file. This file is
12
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
13
+ # ANY KIND, either express or implied. See the License for the specific
14
+ # language governing permissions and limitations under the License.
15
15
 
16
16
  lib = File.expand_path('../lib', __FILE__)
17
17
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
18
18
  require 'fluent_plugin_kinesis/version'
19
- require 'kinesis_producer/binary'
20
19
 
21
20
  Gem::Specification.new do |spec|
22
21
  spec.name = "fluent-plugin-kinesis"
@@ -24,19 +23,17 @@ Gem::Specification.new do |spec|
24
23
  spec.author = 'Amazon Web Services'
25
24
  spec.summary = %q{Fluentd output plugin that sends events to Amazon Kinesis.}
26
25
  spec.homepage = "https://github.com/awslabs/aws-fluent-plugin-kinesis"
27
- spec.license = "Amazon Software License"
26
+ spec.license = "Apache-2.0"
28
27
 
29
28
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
- spec.files += KinesisProducer::Binary::Files.values
31
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
30
  spec.require_paths = ["lib"]
33
- spec.required_ruby_version = '>= 2.0.0'
31
+ spec.required_ruby_version = '>= 2.1'
34
32
 
35
- spec.add_dependency "fluentd", ">= 0.10.58", "< 2"
36
- spec.add_dependency "protobuf", ">= 3.5.5"
37
- spec.add_dependency "aws-sdk", "~> 2"
38
- spec.add_dependency "concurrent-ruby", "~> 1"
39
- spec.add_dependency "os", ">= 0.9.6"
33
+ spec.add_dependency "fluentd", ">= 0.12.35", "< 2"
34
+ spec.add_dependency "aws-sdk-kinesis", "~> 1"
35
+ spec.add_dependency "aws-sdk-firehose", "~> 1"
36
+ spec.add_dependency "google-protobuf", "~> 3"
40
37
 
41
38
  spec.add_development_dependency "bundler", "~> 1.10"
42
39
  spec.add_development_dependency "rake", "~> 10.0"
@@ -46,7 +43,6 @@ Gem::Specification.new do |spec|
46
43
  spec.add_development_dependency "pry-byebug", ">= 3.3.0"
47
44
  spec.add_development_dependency "pry-stack_explorer", ">= 0.4.9.2"
48
45
  spec.add_development_dependency "net-empty_port", ">= 0.0.2"
49
- spec.add_development_dependency "rubyzip", ">= 1.0.0"
50
46
  spec.add_development_dependency "mocha", ">= 1.1.0"
51
47
  spec.add_development_dependency "webmock", ">= 1.24.2"
52
48
  spec.add_development_dependency "fakefs", ">= 0.8.1"
@@ -1,20 +1,20 @@
1
1
  #
2
- # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  #
4
- # Licensed under the Amazon Software License (the "License").
5
- # You may not use this file except in compliance with the License.
6
- # A copy of the License is located at
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # may not use this file except in compliance with the License. A copy of
6
+ # the License is located at
7
7
  #
8
- # http://aws.amazon.com/asl/
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
9
  #
10
- # or in the "license" file accompanying this file. This file is distributed
11
- # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12
- # express or implied. See the License for the specific language governing
13
- # permissions and limitations under the License.
10
+ # or in the "license" file accompanying this file. This file is
11
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # ANY KIND, either express or implied. See the License for the specific
13
+ # language governing permissions and limitations under the License.
14
14
 
15
15
  source 'https://rubygems.org'
16
16
 
17
17
  # Specify your gem's dependencies in fluent-plugin-kinesis.gemspec
18
18
  gemspec path: ".."
19
19
 
20
- gem "fluentd", "~> 0.12.26"
20
+ gem "fluentd", ">= 0.12.35", "< 0.14"
@@ -0,0 +1,166 @@
1
+ #
2
+ # Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # may not use this file except in compliance with the License. A copy of
6
+ # the License is located at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # or in the "license" file accompanying this file. This file is
11
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # ANY KIND, either express or implied. See the License for the specific
13
+ # language governing permissions and limitations under the License.
14
+
15
+ require 'fluent/plugin/kinesis_helper/client'
16
+ require 'fluent/plugin/kinesis_helper/api'
17
+ require 'zlib'
18
+
19
+ module Fluent
20
+ class KinesisOutput < BufferedOutput
21
+ def self.fluentd_v0_12?
22
+ @fluentd_v0_12 ||= Gem.loaded_specs['fluentd'].version < Gem::Version.create('0.14')
23
+ end
24
+
25
+ include Fluent::SetTimeKeyMixin
26
+ include Fluent::SetTagKeyMixin
27
+
28
+ include KinesisHelper::Client
29
+ include KinesisHelper::API
30
+
31
+ class SkipRecordError < ::StandardError
32
+ def initialize(message, record)
33
+ super message
34
+ @record_message = if record.is_a? Array
35
+ record.reverse.map(&:to_s).join(', ')
36
+ else
37
+ record.to_s
38
+ end
39
+ end
40
+
41
+ def to_s
42
+ super + ": " + @record_message
43
+ end
44
+ end
45
+ class KeyNotFoundError < SkipRecordError
46
+ def initialize(key, record)
47
+ super "Key '#{key}' doesn't exist", record
48
+ end
49
+ end
50
+ class ExceedMaxRecordSizeError < SkipRecordError
51
+ def initialize(size, record)
52
+ super "Record size limit exceeded in #{size/1024} KB", record
53
+ end
54
+ end
55
+ class InvalidRecordError < SkipRecordError
56
+ def initialize(record)
57
+ super "Invalid type of record", record
58
+ end
59
+ end
60
+
61
+ config_param :data_key, :string, default: nil
62
+ config_param :log_truncate_max_size, :integer, default: 1024
63
+ config_param :compression, :string, default: nil
64
+ config_section :format do
65
+ config_set_default :@type, 'json'
66
+ end
67
+ config_section :inject do
68
+ config_set_default :time_type, 'string'
69
+ config_set_default :time_format, '%Y-%m-%dT%H:%M:%S.%N%z'
70
+ end
71
+
72
+ config_param :debug, :bool, default: false
73
+
74
+ if fluentd_v0_12?
75
+ config_param :format, :string, default: 'json'
76
+ else
77
+ helpers :formatter, :inject
78
+ end
79
+
80
+ def configure(conf)
81
+ super
82
+ @data_formatter = data_formatter_create(conf)
83
+ end
84
+
85
+ def multi_workers_ready?
86
+ true
87
+ end
88
+
89
+ private
90
+
91
+ def fluentd_v0_12?
92
+ self.class.fluentd_v0_12?
93
+ end
94
+
95
+ def data_formatter_create(conf)
96
+ if fluentd_v0_12?
97
+ formatter = Fluent::Plugin.new_formatter(@format)
98
+ formatter.configure(conf)
99
+ else
100
+ formatter = formatter_create
101
+ end
102
+ compressor = compressor_create
103
+ if @data_key.nil?
104
+ ->(tag, time, record) {
105
+ unless fluentd_v0_12?
106
+ record = inject_values_to_record(tag, time, record)
107
+ end
108
+ compressor.call(formatter.format(tag, time, record).chomp.b)
109
+ }
110
+ else
111
+ ->(tag, time, record) {
112
+ raise InvalidRecordError, record unless record.is_a? Hash
113
+ raise KeyNotFoundError.new(@data_key, record) if record[@data_key].nil?
114
+ compressor.call(record[@data_key].to_s.b)
115
+ }
116
+ end
117
+ end
118
+
119
+ def compressor_create
120
+ case @compression
121
+ when "zlib"
122
+ ->(data) { Zlib::Deflate.deflate(data) }
123
+ else
124
+ ->(data) { data }
125
+ end
126
+ end
127
+
128
+ def format_for_api(&block)
129
+ converted = block.call
130
+ size = size_of_values(converted)
131
+ if size > @max_record_size
132
+ raise ExceedMaxRecordSizeError.new(size, converted)
133
+ end
134
+ converted.to_msgpack
135
+ rescue SkipRecordError => e
136
+ log.error(truncate e)
137
+ ''
138
+ end
139
+
140
+ def write_records_batch(chunk, &block)
141
+ if fluentd_v0_12?
142
+ unique_id = chunk.unique_id.unpack('H*').first
143
+ else
144
+ unique_id = chunk.dump_unique_id_hex(chunk.unique_id)
145
+ end
146
+ records = chunk.to_enum(:msgpack_each)
147
+ split_to_batches(records) do |batch, size|
148
+ log.debug(sprintf "Write chunk %s / %3d records / %4d KB", unique_id, batch.size, size/1024)
149
+ batch_request_with_retry(batch, &block)
150
+ log.debug("Finish writing chunk")
151
+ end
152
+ end
153
+
154
+ def request_type
155
+ self.class::RequestType
156
+ end
157
+
158
+ def truncate(msg)
159
+ if @log_truncate_max_size == 0 or (msg.to_s.size <= @log_truncate_max_size)
160
+ msg.to_s
161
+ else
162
+ msg.to_s[0...@log_truncate_max_size]
163
+ end
164
+ end
165
+ end
166
+ end