fluent-plugin-kinesis 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -23
- data/CHANGELOG.md +13 -0
- data/Gemfile +9 -9
- data/LICENSE.txt +201 -40
- data/Makefile +24 -31
- data/README.md +179 -308
- data/Rakefile +9 -13
- data/benchmark/task.rake +96 -58
- data/fluent-plugin-kinesis.gemspec +15 -19
- data/gemfiles/Gemfile.fluentd-0.12 +10 -10
- data/lib/fluent/plugin/kinesis.rb +166 -0
- data/lib/fluent/plugin/kinesis_helper/aggregator.rb +99 -0
- data/lib/fluent/plugin/kinesis_helper/api.rb +152 -121
- data/lib/fluent/plugin/kinesis_helper/client.rb +125 -12
- data/lib/fluent/plugin/out_kinesis_firehose.rb +40 -27
- data/lib/fluent/plugin/out_kinesis_streams.rb +51 -30
- data/lib/fluent/plugin/out_kinesis_streams_aggregated.rb +76 -0
- data/lib/fluent_plugin_kinesis/version.rb +10 -10
- metadata +18 -70
- data/README-v0.4.md +0 -348
- data/benchmark/dummy.conf +0 -0
- data/gemfiles/Gemfile.aws-sdk-2.4 +0 -20
- data/gemfiles/Gemfile.fluentd-0.10.58 +0 -20
- data/gemfiles/Gemfile.fluentd-0.14.11 +0 -20
- data/gemfiles/Gemfile.ruby-2.0 +0 -21
- data/gemfiles/Gemfile.ruby-2.1 +0 -21
- data/lib/fluent/plugin/kinesis_helper.rb +0 -36
- data/lib/fluent/plugin/kinesis_helper/class_methods.rb +0 -123
- data/lib/fluent/plugin/kinesis_helper/credentials.rb +0 -51
- data/lib/fluent/plugin/kinesis_helper/error.rb +0 -43
- data/lib/fluent/plugin/kinesis_helper/format.rb +0 -85
- data/lib/fluent/plugin/kinesis_helper/initialize.rb +0 -59
- data/lib/fluent/plugin/kinesis_helper/kpl.rb +0 -82
- data/lib/fluent/plugin/out_kinesis.rb +0 -323
- data/lib/fluent/plugin/out_kinesis_producer.rb +0 -48
- data/lib/fluent/plugin/patched_detach_process_impl.rb +0 -103
- data/lib/kinesis_producer.rb +0 -24
- data/lib/kinesis_producer/binary.rb +0 -10
- data/lib/kinesis_producer/daemon.rb +0 -270
- data/lib/kinesis_producer/library.rb +0 -122
- data/lib/kinesis_producer/protobuf/config.pb.rb +0 -66
- data/lib/kinesis_producer/protobuf/messages.pb.rb +0 -151
- data/lib/kinesis_producer/tasks/binary.rake +0 -73
data/Rakefile
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
#
|
2
|
-
#
|
2
|
+
# Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
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
|
-
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
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
|
-
#
|
2
|
+
# Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
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
|
-
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
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/
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
</source>
|
37
|
+
def run
|
38
|
+
setup
|
39
|
+
benchmark(ENV['SIZE'] || 100, ENV['COUNT'] || 10000)
|
40
|
+
teardown
|
41
|
+
end
|
54
42
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
57
|
+
def teardown
|
58
|
+
return if not @local
|
59
|
+
Process.kill "TERM", @server_pid
|
60
|
+
Process.waitpid @server_pid
|
61
|
+
end
|
64
62
|
|
65
|
-
|
66
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
#
|
3
|
+
# Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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
|
-
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
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 = "
|
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.
|
31
|
+
spec.required_ruby_version = '>= 2.1'
|
34
32
|
|
35
|
-
spec.add_dependency "fluentd", ">= 0.
|
36
|
-
spec.add_dependency "
|
37
|
-
spec.add_dependency "aws-sdk", "~>
|
38
|
-
spec.add_dependency "
|
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
|
-
#
|
2
|
+
# Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
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
|
-
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
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", "
|
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
|