fluentd-plugin-kinesis-intuit 2.1.1

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,170 @@
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/configurable'
16
+ require 'aws-sdk-core'
17
+
18
+ module Fluent
19
+ module Plugin
20
+ module KinesisHelper
21
+ module Client
22
+ module ClientParams
23
+ include Fluent::Configurable
24
+ config_param :region, :string, default: nil
25
+
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
29
+
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
66
+ end
67
+
68
+ def self.included(mod)
69
+ mod.include ClientParams
70
+ end
71
+
72
+ def configure(conf)
73
+ super
74
+ @region = client.config.region if @region.nil?
75
+ end
76
+
77
+ def client
78
+ @client ||= client_class.new(client_options)
79
+ end
80
+
81
+ private
82
+
83
+ def aws_sdk_v2?
84
+ @aws_sdk_v2 ||= Gem.loaded_specs['aws-sdk-core'].version < Gem::Version.create('3')
85
+ end
86
+
87
+ def client_class
88
+ case request_type
89
+ when :streams, :streams_aggregated
90
+ if aws_sdk_v2?
91
+ require 'aws-sdk'
92
+ else
93
+ require 'aws-sdk-kinesis'
94
+ end
95
+ Aws::Kinesis::Client
96
+ when :firehose
97
+ if aws_sdk_v2?
98
+ require 'aws-sdk'
99
+ else
100
+ require 'aws-sdk-firehose'
101
+ end
102
+ Aws::Firehose::Client
103
+ end
104
+ end
105
+
106
+ def client_options
107
+ options = setup_credentials
108
+ options.update(
109
+ user_agent_suffix: "fluent-plugin-kinesis/#{request_type}/#{FluentPluginKinesis::VERSION}"
110
+ )
111
+ options.update(region: @region) unless @region.nil?
112
+ options.update(http_proxy: @http_proxy) unless @http_proxy.nil?
113
+ options.update(endpoint: @endpoint) unless @endpoint.nil?
114
+ options.update(ssl_verify_peer: @ssl_verify_peer) unless @ssl_verify_peer.nil?
115
+ if @debug
116
+ options.update(logger: Logger.new(log.out))
117
+ options.update(log_level: :debug)
118
+ end
119
+ options
120
+ end
121
+
122
+ def setup_credentials
123
+ options = {}
124
+ credentials_options = {}
125
+ case
126
+ when @aws_key_id && @aws_sec_key
127
+ options[:access_key_id] = @aws_key_id
128
+ options[:secret_access_key] = @aws_sec_key
129
+ when @assume_role_credentials
130
+ c = @assume_role_credentials
131
+ credentials_options[:role_arn] = c.role_arn
132
+ credentials_options[:role_session_name] = c.role_session_name
133
+ credentials_options[:policy] = c.policy if c.policy
134
+ credentials_options[:duration_seconds] = c.duration_seconds if c.duration_seconds
135
+ credentials_options[:external_id] = c.external_id if c.external_id
136
+ if c.sts_http_proxy and @region
137
+ credentials_options[:client] = Aws::STS::Client.new(region: @region, http_proxy: c.sts_http_proxy)
138
+ elsif @region
139
+ credentials_options[:client] = Aws::STS::Client.new(region: @region)
140
+ elsif c.sts_http_proxy
141
+ credentials_options[:client] = Aws::STS::Client.new(http_proxy: c.sts_http_proxy)
142
+ end
143
+ options[:credentials] = Aws::AssumeRoleCredentials.new(credentials_options)
144
+ when @instance_profile_credentials
145
+ c = @instance_profile_credentials
146
+ credentials_options[:retries] = c.retries if c.retries
147
+ credentials_options[:ip_address] = c.ip_address if c.ip_address
148
+ credentials_options[:port] = c.port if c.port
149
+ credentials_options[:http_open_timeout] = c.http_open_timeout if c.http_open_timeout
150
+ credentials_options[:http_read_timeout] = c.http_read_timeout if c.http_read_timeout
151
+ if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
152
+ options[:credentials] = Aws::ECSCredentials.new(credentials_options)
153
+ else
154
+ options[:credentials] = Aws::InstanceProfileCredentials.new(credentials_options)
155
+ end
156
+ when @shared_credentials
157
+ c = @shared_credentials
158
+ credentials_options[:path] = c.path if c.path
159
+ credentials_options[:profile_name] = c.profile_name if c.profile_name
160
+ options[:credentials] = Aws::SharedCredentials.new(credentials_options)
161
+ else
162
+ # Use default credentials
163
+ # See http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html
164
+ end
165
+ options
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,59 @@
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'
16
+
17
+ module Fluent
18
+ module Plugin
19
+ class KinesisFirehoseOutput < KinesisOutput
20
+ Fluent::Plugin.register_output('kinesis_firehose', self)
21
+
22
+ RequestType = :firehose
23
+ BatchRequestLimitCount = 500
24
+ BatchRequestLimitSize = 4 * 1024 * 1024
25
+ include KinesisHelper::API::BatchRequest
26
+
27
+ config_param :delivery_stream_name, :string
28
+ config_param :append_new_line, :bool, default: true
29
+
30
+ def configure(conf)
31
+ super
32
+ if @append_new_line
33
+ org_data_formatter = @data_formatter
34
+ @data_formatter = ->(tag, time, record) {
35
+ org_data_formatter.call(tag, time, record) + "\n"
36
+ }
37
+ end
38
+ end
39
+
40
+ def format(tag, time, record)
41
+ format_for_api do
42
+ [@data_formatter.call(tag, time, record)]
43
+ end
44
+ end
45
+
46
+ def write(chunk)
47
+ write_records_batch(chunk) do |batch|
48
+ records = batch.map{|(data)|
49
+ { data: data }
50
+ }
51
+ client.put_record_batch(
52
+ delivery_stream_name: @delivery_stream_name,
53
+ records: records,
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,160 @@
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'
16
+
17
+ module Fluent
18
+ module Plugin
19
+ class KinesisStreamsOutput < KinesisOutput
20
+ Fluent::Plugin.register_output('kinesis_streams', self)
21
+
22
+ RequestType = :streams
23
+ BatchRequestLimitCount = 500
24
+ BatchRequestLimitSize = 5 * 1024 * 1024
25
+ include KinesisHelper::API::BatchRequest
26
+
27
+ config_param :stream_name, :string
28
+ config_param :partition_key, :string, default: nil
29
+
30
+ desc 'The Splunk index to index events. When not set, will be decided by HEC'
31
+ config_param :index, :string, default: nil
32
+
33
+ desc 'The host field for events, by default it uses the hostname of the machine that runnning fluentd. '
34
+ config_param :host, :string, default: nil
35
+
36
+ desc 'The source field for events, when not set, will be decided by HEC.'
37
+ config_param :source, :string, default: nil
38
+
39
+ desc 'The sourcetype field for events, when not set, will be decided by HEC.'
40
+ config_param :sourcetype, :string, default: nil
41
+
42
+ desc 'All items in the record will be sent if true, otherwise only message'
43
+ config_param :all_items, :bool, :default => false
44
+
45
+ def initialize
46
+ super
47
+ @default_host = Socket.gethostname
48
+ end
49
+
50
+ # Thanks to
51
+ # https://github.com/kazegusuri/fluent-plugin-prometheus/blob/348c112d/lib/fluent/plugin/prometheus.rb
52
+ def self.placeholder_expander(log)
53
+ # Use internal class in order to expand placeholder
54
+ if defined?(Fluent::Filter) # for v0.12, built-in PlaceholderExpander
55
+ begin
56
+ require 'fluent/plugin/filter_record_transformer'
57
+ if defined?(Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander)
58
+ # for v0.14
59
+ return Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander.new(log: log)
60
+ else
61
+ # for v0.12
62
+ return Fluent::RecordTransformerFilter::PlaceholderExpander.new(log: log)
63
+ end
64
+ rescue LoadError => e
65
+ raise ConfigError, "cannot find filter_record_transformer plugin: #{e.message}"
66
+ end
67
+ else # for v0.10, use PlaceholderExapander in fluent-plugin-record-reformer plugin
68
+ begin
69
+ require 'fluent/plugin/out_record_reformer.rb'
70
+ return Fluent::RecordReformerOutput::PlaceholderExpander.new(log: log)
71
+ rescue LoadError => e
72
+ raise ConfigError, "cannot find fluent-plugin-record-reformer: #{e.message}"
73
+ end
74
+ end
75
+ end
76
+
77
+ def configure(conf)
78
+ super
79
+ # check_conflict
80
+ # prepare_key_fields
81
+ @placeholder_expander = Fluent::Plugin::KinesisStreamsOutput.placeholder_expander(log)
82
+ @hostname = Socket.gethostname
83
+ @key_formatter = key_formatter_create
84
+ end
85
+
86
+
87
+ def format(tag, time, record)
88
+
89
+ placeholder_values = {
90
+ 'tag' => tag,
91
+ 'tag_parts' => tag.split('.'),
92
+ 'hostname' => @default_host,
93
+ 'record' => record
94
+ }
95
+
96
+ placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
97
+
98
+ payload = {
99
+ # for v0.14 millisecs time precision
100
+ time: time.is_a?(Integer) ? time.to_i : time.to_f,
101
+ source: @source.nil? ? tag.to_s : @placeholder_expander.expand(@source, placeholders),
102
+ sourcetype: @placeholder_expander.expand(@sourcetype.to_s, placeholders),
103
+ host: @host.nil? ? @default_host : @placeholder_expander.expand(@host.to_s, placeholders),
104
+ index: @placeholder_expander.expand(@index.to_s, placeholders)
105
+ }
106
+ #payload[:index] = @index if @index
107
+ #payload[:source] = @source if @source
108
+ #payload[:sourcetype] = @sourcetype if @sourcetype
109
+
110
+ # delete nil fields otherwise will get formet error from HEC
111
+ %i[host index source sourcetype].each { |f| payload.delete f if payload[f].nil? }
112
+
113
+ if !record[@data_key].nil?
114
+ payload[@data_key] = record[@data_key]
115
+ end
116
+
117
+ if @all_items
118
+ payload[:event] = record
119
+ else
120
+ payload[:event] = record["message"]
121
+ end
122
+
123
+ format_for_api do
124
+ data = @data_formatter.call(tag, time, payload)
125
+ key = @key_formatter.call(payload)
126
+ [data, key]
127
+ end
128
+ end
129
+
130
+ def write(chunk)
131
+ write_records_batch(chunk) do |batch|
132
+ records = batch.map{|(data, partition_key)|
133
+ { data: data, partition_key: partition_key }
134
+ }
135
+ client.put_records(
136
+ stream_name: @stream_name,
137
+ records: records,
138
+ )
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+ def key_formatter_create
145
+ if @partition_key.nil?
146
+ ->(record) { SecureRandom.hex(16) }
147
+ else
148
+ ->(record) {
149
+ if !record.key?(@partition_key)
150
+ raise KeyNotFoundError.new(@partition_key, record)
151
+ end
152
+ record[@partition_key]
153
+ }
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+
@@ -0,0 +1,78 @@
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'
16
+ require 'fluent/plugin/kinesis_helper/aggregator'
17
+
18
+ module Fluent
19
+ module Plugin
20
+ class KinesisStreamsAggregatedOutput < KinesisOutput
21
+ Fluent::Plugin.register_output('kinesis_streams_aggregated', self)
22
+ include KinesisHelper::Aggregator::Mixin
23
+
24
+ RequestType = :streams_aggregated
25
+ BatchRequestLimitCount = 100_000
26
+ BatchRequestLimitSize = 1024 * 1024
27
+ include KinesisHelper::API::BatchRequest
28
+
29
+ config_param :stream_name, :string
30
+ config_param :fixed_partition_key, :string, default: nil
31
+
32
+ def configure(conf)
33
+ super
34
+ @partition_key_generator = create_partition_key_generator
35
+ @batch_request_max_size -= offset
36
+ @max_record_size -= offset
37
+ end
38
+
39
+ def format(tag, time, record)
40
+ format_for_api do
41
+ [@data_formatter.call(tag, time, record)]
42
+ end
43
+ end
44
+
45
+ def write(chunk)
46
+ write_records_batch(chunk) do |batch|
47
+ key = @partition_key_generator.call
48
+ records = batch.map{|(data)|data}
49
+ client.put_records(
50
+ stream_name: @stream_name,
51
+ records: [{
52
+ partition_key: key,
53
+ data: aggregator.aggregate(records, key),
54
+ }],
55
+ )
56
+ end
57
+ end
58
+
59
+ def offset
60
+ @offset ||= AggregateOffset + @partition_key_generator.call.size*2
61
+ end
62
+
63
+ private
64
+
65
+ def size_of_values(record)
66
+ super(record) + RecordOffset
67
+ end
68
+
69
+ def create_partition_key_generator
70
+ if @fixed_partition_key.nil?
71
+ ->() { SecureRandom.hex(16) }
72
+ else
73
+ ->() { @fixed_partition_key }
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end