fluent-plugin-kinesis 2.2.0 → 3.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.
@@ -0,0 +1,31 @@
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
+ source 'https://rubygems.org'
16
+
17
+ # Specify your gem's dependencies in fluent-plugin-kinesis.gemspec
18
+ gemspec path: ".."
19
+
20
+ # Specify related gems for td-agent v3.2.0
21
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.2.0/config/projects/td-agent3.rb#L27
22
+ gem "fluentd", "1.2.2"
23
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.2.0/plugin_gems.rb#L16-L23
24
+ gem "jmespath", "1.4.0"
25
+ gem "aws-partitions", "1.87.0"
26
+ gem "aws-sigv4", "1.0.2"
27
+ gem "aws-sdk-core", "3.21.2"
28
+ gem "aws-sdk-kms", "1.5.0"
29
+ gem "aws-sdk-sqs", "1.3.0"
30
+ gem "aws-sdk-s3", "1.13.0"
31
+ gem "fluent-plugin-s3", "1.1.3"
@@ -0,0 +1,31 @@
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
+ source 'https://rubygems.org'
16
+
17
+ # Specify your gem's dependencies in fluent-plugin-kinesis.gemspec
18
+ gemspec path: ".."
19
+
20
+ # Specify related gems for td-agent v3.2.1
21
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.2.1/config/projects/td-agent3.rb#L27
22
+ gem "fluentd", "1.2.6"
23
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.2.1/plugin_gems.rb#L16-L23
24
+ gem "jmespath", "1.4.0"
25
+ gem "aws-partitions", "1.105.0"
26
+ gem "aws-sigv4", "1.0.3"
27
+ gem "aws-sdk-core", "3.30.0"
28
+ gem "aws-sdk-kms", "1.9.0"
29
+ gem "aws-sdk-sqs", "1.7.0"
30
+ gem "aws-sdk-s3", "1.21.0"
31
+ gem "fluent-plugin-s3", "1.1.6"
@@ -0,0 +1,31 @@
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
+ source 'https://rubygems.org'
16
+
17
+ # Specify your gem's dependencies in fluent-plugin-kinesis.gemspec
18
+ gemspec path: ".."
19
+
20
+ # Specify related gems for td-agent v3.3.0
21
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.3.0/config/projects/td-agent3.rb#L27
22
+ gem "fluentd", "1.3.3"
23
+ # https://github.com/treasure-data/omnibus-td-agent/blob/v3.3.0/plugin_gems.rb#L16-L23
24
+ gem "jmespath", "1.4.0"
25
+ gem "aws-partitions", "1.127.0"
26
+ gem "aws-sigv4", "1.0.3"
27
+ gem "aws-sdk-core", "3.44.2"
28
+ gem "aws-sdk-kms", "1.13.0"
29
+ gem "aws-sdk-sqs", "1.10.0"
30
+ gem "aws-sdk-s3", "1.30.0"
31
+ gem "fluent-plugin-s3", "1.1.7"
@@ -12,154 +12,149 @@
12
12
  # ANY KIND, either express or implied. See the License for the specific
13
13
  # language governing permissions and limitations under the License.
14
14
 
15
+ require 'fluent/plugin/output'
15
16
  require 'fluent/plugin/kinesis_helper/client'
16
17
  require 'fluent/plugin/kinesis_helper/api'
17
18
  require 'zlib'
18
19
 
19
20
  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
21
+ module Plugin
22
+ class KinesisOutput < Fluent::Plugin::Output
23
+ include Fluent::MessagePackFactory::Mixin
24
+ include KinesisHelper::Client
25
+ include KinesisHelper::API
26
+
27
+ class SkipRecordError < ::StandardError
28
+ def initialize(message, record)
29
+ super message
30
+ @record_message = if record.is_a? Array
31
+ record.reverse.map(&:to_s).join(', ')
32
+ else
33
+ record.to_s
34
+ end
38
35
  end
39
- end
40
36
 
41
- def to_s
42
- super + ": " + @record_message
37
+ def to_s
38
+ super + ": " + @record_message
39
+ end
43
40
  end
44
- end
45
- class KeyNotFoundError < SkipRecordError
46
- def initialize(key, record)
47
- super "Key '#{key}' doesn't exist", record
41
+ class KeyNotFoundError < SkipRecordError
42
+ def initialize(key, record)
43
+ super "Key '#{key}' doesn't exist", record
44
+ end
48
45
  end
49
- end
50
- class ExceedMaxRecordSizeError < SkipRecordError
51
- def initialize(size, record)
52
- super "Record size limit exceeded in #{size/1024} KB", record
46
+ class ExceedMaxRecordSizeError < SkipRecordError
47
+ def initialize(size, record)
48
+ super "Record size limit exceeded in #{size/1024} KB", record
49
+ end
53
50
  end
54
- end
55
- class InvalidRecordError < SkipRecordError
56
- def initialize(record)
57
- super "Invalid type of record", record
51
+ class InvalidRecordError < SkipRecordError
52
+ def initialize(record)
53
+ super "Invalid type of record", record
54
+ end
58
55
  end
59
- end
60
56
 
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
57
+ config_param :data_key, :string, default: nil
58
+ config_param :log_truncate_max_size, :integer, default: 1024
59
+ config_param :compression, :string, default: nil
71
60
 
72
- config_param :debug, :bool, default: false
61
+ desc "Formatter calls chomp and removes separator from the end of each record. This option is for compatible format with plugin v2. (default: false)"
62
+ # https://github.com/awslabs/aws-fluent-plugin-kinesis/issues/142
63
+ config_param :chomp_record, :bool, default: false
73
64
 
74
- if fluentd_v0_12?
75
- config_param :format, :string, default: 'json'
76
- else
77
- helpers :formatter, :inject
78
- end
65
+ config_section :format do
66
+ config_set_default :@type, 'json'
67
+ end
68
+ config_section :inject do
69
+ config_set_default :time_type, 'string'
70
+ config_set_default :time_format, '%Y-%m-%dT%H:%M:%S.%N%z'
71
+ end
79
72
 
80
- def configure(conf)
81
- super
82
- @data_formatter = data_formatter_create(conf)
83
- end
73
+ config_param :debug, :bool, default: false
84
74
 
85
- def multi_workers_ready?
86
- true
87
- end
75
+ helpers :formatter, :inject
88
76
 
89
- private
77
+ def configure(conf)
78
+ super
79
+ @data_formatter = data_formatter_create(conf)
80
+ end
90
81
 
91
- def fluentd_v0_12?
92
- self.class.fluentd_v0_12?
93
- end
82
+ def multi_workers_ready?
83
+ true
84
+ end
85
+
86
+ private
94
87
 
95
- def data_formatter_create(conf)
96
- if fluentd_v0_12?
97
- formatter = Fluent::Plugin.new_formatter(@format)
98
- formatter.configure(conf)
99
- else
88
+ def data_formatter_create(conf)
100
89
  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)
90
+ compressor = compressor_create
91
+ if @data_key.nil?
92
+ if @chomp_record
93
+ ->(tag, time, record) {
94
+ record = inject_values_to_record(tag, time, record)
95
+ # Formatter calls chomp and removes separator from the end of each record.
96
+ # This option is for compatible format with plugin v2.
97
+ # https://github.com/awslabs/aws-fluent-plugin-kinesis/issues/142
98
+ compressor.call(formatter.format(tag, time, record).chomp.b)
99
+ }
100
+ else
101
+ ->(tag, time, record) {
102
+ record = inject_values_to_record(tag, time, record)
103
+ compressor.call(formatter.format(tag, time, record).b)
104
+ }
107
105
  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
- }
106
+ else
107
+ ->(tag, time, record) {
108
+ raise InvalidRecordError, record unless record.is_a? Hash
109
+ raise KeyNotFoundError.new(@data_key, record) if record[@data_key].nil?
110
+ compressor.call(record[@data_key].to_s.b)
111
+ }
112
+ end
116
113
  end
117
- end
118
114
 
119
- def compressor_create
120
- case @compression
121
- when "zlib"
122
- ->(data) { Zlib::Deflate.deflate(data) }
123
- else
124
- ->(data) { data }
115
+ def compressor_create
116
+ case @compression
117
+ when "zlib"
118
+ ->(data) { Zlib::Deflate.deflate(data) }
119
+ else
120
+ ->(data) { data }
121
+ end
125
122
  end
126
- end
127
123
 
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)
124
+ def format_for_api(&block)
125
+ converted = block.call
126
+ size = size_of_values(converted)
127
+ if size > @max_record_size
128
+ raise ExceedMaxRecordSizeError.new(size, converted)
129
+ end
130
+ converted.to_msgpack
131
+ rescue SkipRecordError => e
132
+ log.error(truncate e)
133
+ ''
133
134
  end
134
- converted.to_msgpack
135
- rescue SkipRecordError => e
136
- log.error(truncate e)
137
- ''
138
- end
139
135
 
140
- def write_records_batch(chunk, &block)
141
- if fluentd_v0_12?
142
- unique_id = chunk.unique_id.unpack('H*').first
143
- else
136
+ def write_records_batch(chunk, &block)
144
137
  unique_id = chunk.dump_unique_id_hex(chunk.unique_id)
138
+ chunk.open do |io|
139
+ records = msgpack_unpacker(io).to_enum
140
+ split_to_batches(records) do |batch, size|
141
+ log.debug(sprintf "Write chunk %s / %3d records / %4d KB", unique_id, batch.size, size/1024)
142
+ batch_request_with_retry(batch, &block)
143
+ log.debug("Finish writing chunk")
144
+ end
145
+ end
145
146
  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
147
 
154
- def request_type
155
- self.class::RequestType
156
- end
148
+ def request_type
149
+ self.class::RequestType
150
+ end
157
151
 
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]
152
+ def truncate(msg)
153
+ if @log_truncate_max_size == 0 or (msg.to_s.size <= @log_truncate_max_size)
154
+ msg.to_s
155
+ else
156
+ msg.to_s[0...@log_truncate_max_size]
157
+ end
163
158
  end
164
159
  end
165
160
  end
@@ -34,64 +34,66 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
34
34
  end
35
35
 
36
36
  module Fluent
37
- module KinesisHelper
38
- class Aggregator
39
- AggregatedRecord = Google::Protobuf::DescriptorPool.generated_pool.lookup("AggregatedRecord").msgclass
40
- Tag = Google::Protobuf::DescriptorPool.generated_pool.lookup("Tag").msgclass
41
- Record = Google::Protobuf::DescriptorPool.generated_pool.lookup("Record").msgclass
37
+ module Plugin
38
+ module KinesisHelper
39
+ class Aggregator
40
+ AggregatedRecord = Google::Protobuf::DescriptorPool.generated_pool.lookup("AggregatedRecord").msgclass
41
+ Tag = Google::Protobuf::DescriptorPool.generated_pool.lookup("Tag").msgclass
42
+ Record = Google::Protobuf::DescriptorPool.generated_pool.lookup("Record").msgclass
42
43
 
43
- class InvalidEncodingError < ::StandardError; end
44
+ class InvalidEncodingError < ::StandardError; end
44
45
 
45
- MagicNumber = ['F3899AC2'].pack('H*')
46
+ MagicNumber = ['F3899AC2'].pack('H*')
46
47
 
47
- def aggregate(records, partition_key)
48
- message = AggregatedRecord.encode(AggregatedRecord.new(
49
- partition_key_table: ['a', partition_key],
50
- records: records.map{|data|
51
- Record.new(partition_key_index: 1, data: data)
52
- },
53
- ))
54
- [MagicNumber, message, Digest::MD5.digest(message)].pack("A4A*A16")
55
- end
56
-
57
- def deaggregate(encoded)
58
- unless aggregated?(encoded)
59
- raise InvalidEncodingError, "Invalid MagicNumber #{encoded[0..3]}}"
48
+ def aggregate(records, partition_key)
49
+ message = AggregatedRecord.encode(AggregatedRecord.new(
50
+ partition_key_table: ['a', partition_key],
51
+ records: records.map{|data|
52
+ Record.new(partition_key_index: 1, data: data)
53
+ },
54
+ ))
55
+ [MagicNumber, message, Digest::MD5.digest(message)].pack("A4A*A16")
60
56
  end
61
- message, digest = encoded[4..encoded.length-17], encoded[encoded.length-16..-1]
62
- if Digest::MD5.digest(message) != digest
63
- raise InvalidEncodingError, "Digest mismatch #{digest}"
57
+
58
+ def deaggregate(encoded)
59
+ unless aggregated?(encoded)
60
+ raise InvalidEncodingError, "Invalid MagicNumber #{encoded[0..3]}}"
61
+ end
62
+ message, digest = encoded[4..encoded.length-17], encoded[encoded.length-16..-1]
63
+ if Digest::MD5.digest(message) != digest
64
+ raise InvalidEncodingError, "Digest mismatch #{digest}"
65
+ end
66
+ decoded = AggregatedRecord.decode(message)
67
+ records = decoded.records.map(&:data)
68
+ partition_key = decoded.partition_key_table[1]
69
+ [records, partition_key]
64
70
  end
65
- decoded = AggregatedRecord.decode(message)
66
- records = decoded.records.map(&:data)
67
- partition_key = decoded.partition_key_table[1]
68
- [records, partition_key]
69
- end
70
71
 
71
- def aggregated?(encoded)
72
- encoded[0..3] == MagicNumber
73
- end
72
+ def aggregated?(encoded)
73
+ encoded[0..3] == MagicNumber
74
+ end
74
75
 
75
- def aggregated_size_offset(partition_key)
76
- data = 'd'
77
- encoded = aggregate([record(data)], partition_key)
78
- finalize(encoded).size - data.size
79
- end
76
+ def aggregated_size_offset(partition_key)
77
+ data = 'd'
78
+ encoded = aggregate([record(data)], partition_key)
79
+ finalize(encoded).size - data.size
80
+ end
80
81
 
81
- module Mixin
82
- AggregateOffset = 25
83
- RecordOffset = 10
82
+ module Mixin
83
+ AggregateOffset = 25
84
+ RecordOffset = 10
84
85
 
85
- module Params
86
- include Fluent::Configurable
87
- end
86
+ module Params
87
+ include Fluent::Configurable
88
+ end
88
89
 
89
- def self.included(mod)
90
- mod.include Params
91
- end
90
+ def self.included(mod)
91
+ mod.include Params
92
+ end
92
93
 
93
- def aggregator
94
- @aggregator ||= Aggregator.new
94
+ def aggregator
95
+ @aggregator ||= Aggregator.new
96
+ end
95
97
  end
96
98
  end
97
99
  end