fluent-plugin-kinesis 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,178 +16,180 @@ require 'fluent_plugin_kinesis/version'
16
16
  require 'fluent/configurable'
17
17
 
18
18
  module Fluent
19
- module KinesisHelper
20
- module API
21
- MaxRecordSize = 1024 * 1024 # 1 MB
19
+ module Plugin
20
+ module KinesisHelper
21
+ module API
22
+ MaxRecordSize = 1024 * 1024 # 1 MB
22
23
 
23
- module APIParams
24
- include Fluent::Configurable
25
- config_param :max_record_size, :integer, default: MaxRecordSize
26
- end
27
-
28
- def self.included(mod)
29
- mod.include APIParams
30
- end
31
-
32
- def configure(conf)
33
- super
34
- if @max_record_size > MaxRecordSize
35
- raise ConfigError, "max_record_size can't be grater than #{MaxRecordSize/1024} KB."
36
- end
37
- end
38
-
39
- module BatchRequest
40
- module BatchRequestParams
24
+ module APIParams
41
25
  include Fluent::Configurable
42
- config_param :retries_on_batch_request, :integer, default: 8
43
- config_param :reset_backoff_if_success, :bool, default: true
44
- config_param :batch_request_max_count, :integer, default: nil
45
- config_param :batch_request_max_size, :integer, default: nil
26
+ config_param :max_record_size, :integer, default: MaxRecordSize
46
27
  end
47
28
 
48
29
  def self.included(mod)
49
- mod.include BatchRequestParams
30
+ mod.include APIParams
50
31
  end
51
32
 
52
33
  def configure(conf)
53
34
  super
54
- if @batch_request_max_count.nil?
55
- @batch_request_max_count = self.class::BatchRequestLimitCount
56
- elsif @batch_request_max_count > self.class::BatchRequestLimitCount
57
- raise ConfigError, "batch_request_max_count can't be grater than #{self.class::BatchRequestLimitCount}."
58
- end
59
- if @batch_request_max_size.nil?
60
- @batch_request_max_size = self.class::BatchRequestLimitSize
61
- elsif @batch_request_max_size > self.class::BatchRequestLimitSize
62
- raise ConfigError, "batch_request_max_size can't be grater than #{self.class::BatchRequestLimitSize}."
35
+ if @max_record_size > MaxRecordSize
36
+ raise ConfigError, "max_record_size can't be grater than #{MaxRecordSize/1024} KB."
63
37
  end
64
38
  end
65
39
 
66
- def size_of_values(record)
67
- record.compact.map(&:size).inject(:+) || 0
68
- end
40
+ module BatchRequest
41
+ module BatchRequestParams
42
+ include Fluent::Configurable
43
+ config_param :retries_on_batch_request, :integer, default: 8
44
+ config_param :reset_backoff_if_success, :bool, default: true
45
+ config_param :batch_request_max_count, :integer, default: nil
46
+ config_param :batch_request_max_size, :integer, default: nil
47
+ end
69
48
 
70
- private
71
-
72
- def split_to_batches(records, &block)
73
- batch = []
74
- size = 0
75
- records.each do |record|
76
- record_size = size_of_values(record)
77
- if batch.size+1 > @batch_request_max_count or size+record_size > @batch_request_max_size
78
- yield(batch, size)
79
- batch = []
80
- size = 0
81
- end
82
- batch << record
83
- size += record_size
49
+ def self.included(mod)
50
+ mod.include BatchRequestParams
84
51
  end
85
- yield(batch, size) if batch.size > 0
86
- end
87
52
 
88
- def batch_request_with_retry(batch, retry_count=0, backoff: nil, &block)
89
- backoff ||= Backoff.new
90
- res = yield(batch)
91
- if failed_count(res) > 0
92
- failed_records = collect_failed_records(batch, res)
93
- if retry_count < @retries_on_batch_request
94
- backoff.reset if @reset_backoff_if_success and any_records_shipped?(res)
95
- wait_second = backoff.next
96
- msg = 'Retrying to request batch. Retry count: %3d, Retry records: %3d, Wait seconds %3.2f' % [retry_count+1, failed_records.size, wait_second]
97
- log.warn(truncate msg)
98
- # TODO: sleep() doesn't wait the given seconds sometime.
99
- # The root cause is unknown so far, so I'd like to add debug print only. It should be fixed in the future.
100
- log.debug("#{Thread.current.object_id} sleep start")
101
- sleep(wait_second)
102
- log.debug("#{Thread.current.object_id} sleep finish")
103
- batch_request_with_retry(retry_records(failed_records), retry_count+1, backoff: backoff, &block)
104
- else
105
- give_up_retries(failed_records)
53
+ def configure(conf)
54
+ super
55
+ if @batch_request_max_count.nil?
56
+ @batch_request_max_count = self.class::BatchRequestLimitCount
57
+ elsif @batch_request_max_count > self.class::BatchRequestLimitCount
58
+ raise ConfigError, "batch_request_max_count can't be grater than #{self.class::BatchRequestLimitCount}."
59
+ end
60
+ if @batch_request_max_size.nil?
61
+ @batch_request_max_size = self.class::BatchRequestLimitSize
62
+ elsif @batch_request_max_size > self.class::BatchRequestLimitSize
63
+ raise ConfigError, "batch_request_max_size can't be grater than #{self.class::BatchRequestLimitSize}."
106
64
  end
107
65
  end
108
- end
109
66
 
110
- def any_records_shipped?(res)
111
- results(res).size > failed_count(res)
112
- end
113
-
114
- def collect_failed_records(records, res)
115
- failed_records = []
116
- results(res).each_with_index do |record, index|
117
- next unless record[:error_code]
118
- original = case request_type
119
- when :streams, :firehose; records[index]
120
- when :streams_aggregated; records
121
- end
122
- failed_records.push(
123
- original: original,
124
- error_code: record[:error_code],
125
- error_message: record[:error_message]
126
- )
67
+ def size_of_values(record)
68
+ record.compact.map(&:size).inject(:+) || 0
127
69
  end
128
- failed_records
70
+
71
+ private
72
+
73
+ def split_to_batches(records, &block)
74
+ batch = []
75
+ size = 0
76
+ records.each do |record|
77
+ record_size = size_of_values(record)
78
+ if batch.size+1 > @batch_request_max_count or size+record_size > @batch_request_max_size
79
+ yield(batch, size)
80
+ batch = []
81
+ size = 0
129
82
  end
83
+ batch << record
84
+ size += record_size
85
+ end
86
+ yield(batch, size) if batch.size > 0
87
+ end
130
88
 
131
- def retry_records(failed_records)
132
- case request_type
133
- when :streams, :firehose
134
- failed_records.map{|r| r[:original] }
135
- when :streams_aggregated
136
- failed_records.first[:original]
89
+ def batch_request_with_retry(batch, retry_count=0, backoff: nil, &block)
90
+ backoff ||= Backoff.new
91
+ res = yield(batch)
92
+ if failed_count(res) > 0
93
+ failed_records = collect_failed_records(batch, res)
94
+ if retry_count < @retries_on_batch_request
95
+ backoff.reset if @reset_backoff_if_success and any_records_shipped?(res)
96
+ wait_second = backoff.next
97
+ msg = 'Retrying to request batch. Retry count: %3d, Retry records: %3d, Wait seconds %3.2f' % [retry_count+1, failed_records.size, wait_second]
98
+ log.warn(truncate msg)
99
+ # TODO: sleep() doesn't wait the given seconds sometime.
100
+ # The root cause is unknown so far, so I'd like to add debug print only. It should be fixed in the future.
101
+ log.debug("#{Thread.current.object_id} sleep start")
102
+ sleep(wait_second)
103
+ log.debug("#{Thread.current.object_id} sleep finish")
104
+ batch_request_with_retry(retry_records(failed_records), retry_count+1, backoff: backoff, &block)
105
+ else
106
+ give_up_retries(failed_records)
107
+ end
108
+ end
137
109
  end
138
- end
139
110
 
140
- def failed_count(res)
141
- failed_field = case request_type
142
- when :streams; :failed_record_count
143
- when :streams_aggregated; :failed_record_count
144
- when :firehose; :failed_put_count
145
- end
146
- res[failed_field]
147
- end
111
+ def any_records_shipped?(res)
112
+ results(res).size > failed_count(res)
113
+ end
148
114
 
149
- def results(res)
150
- result_field = case request_type
151
- when :streams; :records
152
- when :streams_aggregated; :records
153
- when :firehose; :request_responses
115
+ def collect_failed_records(records, res)
116
+ failed_records = []
117
+ results(res).each_with_index do |record, index|
118
+ next unless record[:error_code]
119
+ original = case request_type
120
+ when :streams, :firehose; records[index]
121
+ when :streams_aggregated; records
154
122
  end
155
- res[result_field]
156
- end
123
+ failed_records.push(
124
+ original: original,
125
+ error_code: record[:error_code],
126
+ error_message: record[:error_message]
127
+ )
128
+ end
129
+ failed_records
130
+ end
157
131
 
158
- def give_up_retries(failed_records)
159
- failed_records.each {|record|
160
- log.error(truncate 'Could not put record, Error: %s/%s, Record: %s' % [
161
- record[:error_code],
162
- record[:error_message],
163
- record[:original]
164
- ])
165
- }
166
- end
132
+ def retry_records(failed_records)
133
+ case request_type
134
+ when :streams, :firehose
135
+ failed_records.map{|r| r[:original] }
136
+ when :streams_aggregated
137
+ failed_records.first[:original]
138
+ end
139
+ end
167
140
 
168
- class Backoff
169
- def initialize
170
- @count = 0
141
+ def failed_count(res)
142
+ failed_field = case request_type
143
+ when :streams; :failed_record_count
144
+ when :streams_aggregated; :failed_record_count
145
+ when :firehose; :failed_put_count
146
+ end
147
+ res[failed_field]
171
148
  end
172
149
 
173
- def next
174
- value = calc(@count)
175
- @count += 1
176
- value
150
+ def results(res)
151
+ result_field = case request_type
152
+ when :streams; :records
153
+ when :streams_aggregated; :records
154
+ when :firehose; :request_responses
155
+ end
156
+ res[result_field]
177
157
  end
178
158
 
179
- def reset
180
- @count = 0
159
+ def give_up_retries(failed_records)
160
+ failed_records.each {|record|
161
+ log.error(truncate 'Could not put record, Error: %s/%s, Record: %s' % [
162
+ record[:error_code],
163
+ record[:error_message],
164
+ record[:original]
165
+ ])
166
+ }
181
167
  end
182
168
 
183
- private
169
+ class Backoff
170
+ def initialize
171
+ @count = 0
172
+ end
184
173
 
185
- def calc(count)
186
- (2 ** count) * scaling_factor
187
- end
174
+ def next
175
+ value = calc(@count)
176
+ @count += 1
177
+ value
178
+ end
179
+
180
+ def reset
181
+ @count = 0
182
+ end
183
+
184
+ private
188
185
 
189
- def scaling_factor
190
- 0.3 + (0.5-rand) * 0.1
186
+ def calc(count)
187
+ (2 ** count) * scaling_factor
188
+ end
189
+
190
+ def scaling_factor
191
+ 0.3 + (0.5-rand) * 0.1
192
+ end
191
193
  end
192
194
  end
193
195
  end
@@ -16,152 +16,142 @@ require 'fluent/configurable'
16
16
  require 'aws-sdk-core'
17
17
 
18
18
  module Fluent
19
- module KinesisHelper
20
- module Client
21
- module ClientParams
22
- include Fluent::Configurable
23
- config_param :region, :string, default: nil
19
+ module Plugin
20
+ module KinesisHelper
21
+ module Client
22
+ module ClientParams
23
+ include Fluent::Configurable
24
+ config_param :region, :string, default: nil
24
25
 
25
- config_param :http_proxy, :string, default: nil, secret: true
26
- config_param :endpoint, :string, default: nil
27
- config_param :ssl_verify_peer, :bool, default: true
26
+ config_param :http_proxy, :string, default: nil, secret: true
27
+ config_param :endpoint, :string, default: nil
28
+ config_param :ssl_verify_peer, :bool, default: true
28
29
 
29
- config_param :aws_key_id, :string, default: nil, secret: true
30
- config_param :aws_sec_key, :string, default: nil, secret: true
31
- config_section :assume_role_credentials, multi: false do
32
- desc "The Amazon Resource Name (ARN) of the role to assume"
33
- config_param :role_arn, :string, secret: true
34
- desc "An identifier for the assumed role session"
35
- config_param :role_session_name, :string
36
- desc "An IAM policy in JSON format"
37
- config_param :policy, :string, default: nil
38
- desc "The duration, in seconds, of the role session (900-3600)"
39
- config_param :duration_seconds, :integer, default: nil
40
- desc "A unique identifier that is used by third parties when assuming roles in their customers' accounts."
41
- config_param :external_id, :string, default: nil, secret: true
42
- desc "A http proxy url for requests to aws sts service"
43
- config_param :sts_http_proxy, :string, default: nil, secret: true
44
- end
45
- config_section :instance_profile_credentials, multi: false do
46
- desc "Number of times to retry when retrieving credentials"
47
- config_param :retries, :integer, default: nil
48
- desc "IP address (default:169.254.169.254)"
49
- config_param :ip_address, :string, default: nil
50
- desc "Port number (default:80)"
51
- config_param :port, :integer, default: nil
52
- desc "Number of seconds to wait for the connection to open"
53
- config_param :http_open_timeout, :float, default: nil
54
- desc "Number of seconds to wait for one block to be read"
55
- config_param :http_read_timeout, :float, default: nil
56
- # config_param :delay, :integer or :proc, :default => nil
57
- # config_param :http_degub_output, :io, :default => nil
58
- end
59
- config_section :shared_credentials, multi: false do
60
- desc "Path to the shared file. (default: $HOME/.aws/credentials)"
61
- config_param :path, :string, default: nil
62
- desc "Profile name. Default to 'default' or ENV['AWS_PROFILE']"
63
- config_param :profile_name, :string, default: nil
30
+ config_param :aws_key_id, :string, default: nil, secret: true
31
+ config_param :aws_sec_key, :string, default: nil, secret: true
32
+ config_section :assume_role_credentials, multi: false do
33
+ desc "The Amazon Resource Name (ARN) of the role to assume"
34
+ config_param :role_arn, :string, secret: true
35
+ desc "An identifier for the assumed role session"
36
+ config_param :role_session_name, :string
37
+ desc "An IAM policy in JSON format"
38
+ config_param :policy, :string, default: nil
39
+ desc "The duration, in seconds, of the role session (900-3600)"
40
+ config_param :duration_seconds, :integer, default: nil
41
+ desc "A unique identifier that is used by third parties when assuming roles in their customers' accounts."
42
+ config_param :external_id, :string, default: nil, secret: true
43
+ desc "A http proxy url for requests to aws sts service"
44
+ config_param :sts_http_proxy, :string, default: nil, secret: true
45
+ end
46
+ config_section :instance_profile_credentials, multi: false do
47
+ desc "Number of times to retry when retrieving credentials"
48
+ config_param :retries, :integer, default: nil
49
+ desc "IP address (default:169.254.169.254)"
50
+ config_param :ip_address, :string, default: nil
51
+ desc "Port number (default:80)"
52
+ config_param :port, :integer, default: nil
53
+ desc "Number of seconds to wait for the connection to open"
54
+ config_param :http_open_timeout, :float, default: nil
55
+ desc "Number of seconds to wait for one block to be read"
56
+ config_param :http_read_timeout, :float, default: nil
57
+ # config_param :delay, :integer or :proc, :default => nil
58
+ # config_param :http_degub_output, :io, :default => nil
59
+ end
60
+ config_section :shared_credentials, multi: false do
61
+ desc "Path to the shared file. (default: $HOME/.aws/credentials)"
62
+ config_param :path, :string, default: nil
63
+ desc "Profile name. Default to 'default' or ENV['AWS_PROFILE']"
64
+ config_param :profile_name, :string, default: nil
65
+ end
64
66
  end
65
- end
66
67
 
67
- def self.included(mod)
68
- mod.include ClientParams
69
- end
70
-
71
- def configure(conf)
72
- super
73
- @region = client.config.region if @region.nil?
74
- end
68
+ def self.included(mod)
69
+ mod.include ClientParams
70
+ end
75
71
 
76
- def client
77
- @client ||= client_class.new(client_options)
78
- end
72
+ def configure(conf)
73
+ super
74
+ @region = client.config.region if @region.nil?
75
+ end
79
76
 
80
- private
77
+ def client
78
+ @client ||= client_class.new(client_options)
79
+ end
81
80
 
82
- def aws_sdk_v2?
83
- @aws_sdk_v2 ||= Gem.loaded_specs['aws-sdk-core'].version < Gem::Version.create('3')
84
- end
81
+ private
85
82
 
86
- def client_class
87
- case request_type
88
- when :streams, :streams_aggregated
89
- if aws_sdk_v2?
90
- require 'aws-sdk'
91
- else
83
+ def client_class
84
+ case request_type
85
+ when :streams, :streams_aggregated
92
86
  require 'aws-sdk-kinesis'
93
- end
94
- Aws::Kinesis::Client
95
- when :firehose
96
- if aws_sdk_v2?
97
- require 'aws-sdk'
98
- else
87
+ Aws::Kinesis::Client
88
+ when :firehose
99
89
  require 'aws-sdk-firehose'
90
+ Aws::Firehose::Client
100
91
  end
101
- Aws::Firehose::Client
102
92
  end
103
- end
104
93
 
105
- def client_options
106
- options = setup_credentials
107
- options.update(
108
- user_agent_suffix: "fluent-plugin-kinesis/#{request_type}/#{FluentPluginKinesis::VERSION}"
109
- )
110
- options.update(region: @region) unless @region.nil?
111
- options.update(http_proxy: @http_proxy) unless @http_proxy.nil?
112
- options.update(endpoint: @endpoint) unless @endpoint.nil?
113
- options.update(ssl_verify_peer: @ssl_verify_peer) unless @ssl_verify_peer.nil?
114
- if @debug
115
- options.update(logger: Logger.new(log.out))
116
- options.update(log_level: :debug)
94
+ def client_options
95
+ options = setup_credentials
96
+ options.update(
97
+ user_agent_suffix: "fluent-plugin-kinesis/#{request_type}/#{FluentPluginKinesis::VERSION}"
98
+ )
99
+ options.update(region: @region) unless @region.nil?
100
+ options.update(http_proxy: @http_proxy) unless @http_proxy.nil?
101
+ options.update(endpoint: @endpoint) unless @endpoint.nil?
102
+ options.update(ssl_verify_peer: @ssl_verify_peer) unless @ssl_verify_peer.nil?
103
+ if @debug
104
+ options.update(logger: Logger.new(log.out))
105
+ options.update(log_level: :debug)
106
+ end
107
+ options
117
108
  end
118
- options
119
- end
120
109
 
121
- def setup_credentials
122
- options = {}
123
- credentials_options = {}
124
- case
125
- when @aws_key_id && @aws_sec_key
126
- options[:access_key_id] = @aws_key_id
127
- options[:secret_access_key] = @aws_sec_key
128
- when @assume_role_credentials
129
- c = @assume_role_credentials
130
- credentials_options[:role_arn] = c.role_arn
131
- credentials_options[:role_session_name] = c.role_session_name
132
- credentials_options[:policy] = c.policy if c.policy
133
- credentials_options[:duration_seconds] = c.duration_seconds if c.duration_seconds
134
- credentials_options[:external_id] = c.external_id if c.external_id
135
- if c.sts_http_proxy and @region
136
- credentials_options[:client] = Aws::STS::Client.new(region: @region, http_proxy: c.sts_http_proxy)
137
- elsif @region
138
- credentials_options[:client] = Aws::STS::Client.new(region: @region)
139
- elsif c.sts_http_proxy
140
- credentials_options[:client] = Aws::STS::Client.new(http_proxy: c.sts_http_proxy)
141
- end
142
- options[:credentials] = Aws::AssumeRoleCredentials.new(credentials_options)
143
- when @instance_profile_credentials
144
- c = @instance_profile_credentials
145
- credentials_options[:retries] = c.retries if c.retries
146
- credentials_options[:ip_address] = c.ip_address if c.ip_address
147
- credentials_options[:port] = c.port if c.port
148
- credentials_options[:http_open_timeout] = c.http_open_timeout if c.http_open_timeout
149
- credentials_options[:http_read_timeout] = c.http_read_timeout if c.http_read_timeout
150
- if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
151
- options[:credentials] = Aws::ECSCredentials.new(credentials_options)
110
+ def setup_credentials
111
+ options = {}
112
+ credentials_options = {}
113
+ case
114
+ when @aws_key_id && @aws_sec_key
115
+ options[:access_key_id] = @aws_key_id
116
+ options[:secret_access_key] = @aws_sec_key
117
+ when @assume_role_credentials
118
+ c = @assume_role_credentials
119
+ credentials_options[:role_arn] = c.role_arn
120
+ credentials_options[:role_session_name] = c.role_session_name
121
+ credentials_options[:policy] = c.policy if c.policy
122
+ credentials_options[:duration_seconds] = c.duration_seconds if c.duration_seconds
123
+ credentials_options[:external_id] = c.external_id if c.external_id
124
+ if c.sts_http_proxy and @region
125
+ credentials_options[:client] = Aws::STS::Client.new(region: @region, http_proxy: c.sts_http_proxy)
126
+ elsif @region
127
+ credentials_options[:client] = Aws::STS::Client.new(region: @region)
128
+ elsif c.sts_http_proxy
129
+ credentials_options[:client] = Aws::STS::Client.new(http_proxy: c.sts_http_proxy)
130
+ end
131
+ options[:credentials] = Aws::AssumeRoleCredentials.new(credentials_options)
132
+ when @instance_profile_credentials
133
+ c = @instance_profile_credentials
134
+ credentials_options[:retries] = c.retries if c.retries
135
+ credentials_options[:ip_address] = c.ip_address if c.ip_address
136
+ credentials_options[:port] = c.port if c.port
137
+ credentials_options[:http_open_timeout] = c.http_open_timeout if c.http_open_timeout
138
+ credentials_options[:http_read_timeout] = c.http_read_timeout if c.http_read_timeout
139
+ if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
140
+ options[:credentials] = Aws::ECSCredentials.new(credentials_options)
141
+ else
142
+ options[:credentials] = Aws::InstanceProfileCredentials.new(credentials_options)
143
+ end
144
+ when @shared_credentials
145
+ c = @shared_credentials
146
+ credentials_options[:path] = c.path if c.path
147
+ credentials_options[:profile_name] = c.profile_name if c.profile_name
148
+ options[:credentials] = Aws::SharedCredentials.new(credentials_options)
152
149
  else
153
- options[:credentials] = Aws::InstanceProfileCredentials.new(credentials_options)
150
+ # Use default credentials
151
+ # See http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html
154
152
  end
155
- when @shared_credentials
156
- c = @shared_credentials
157
- credentials_options[:path] = c.path if c.path
158
- credentials_options[:profile_name] = c.profile_name if c.profile_name
159
- options[:credentials] = Aws::SharedCredentials.new(credentials_options)
160
- else
161
- # Use default credentials
162
- # See http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html
153
+ options
163
154
  end
164
- options
165
155
  end
166
156
  end
167
157
  end