fluent-plugin-kafka 0.17.5 → 0.19.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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +1 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +1 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/linux.yml +8 -3
- data/.github/workflows/stale-actions.yml +5 -3
- data/ChangeLog +14 -0
- data/Gemfile +1 -1
- data/README.md +63 -2
- data/examples/README.md +3 -0
- data/examples/out_kafka2/dynamic_topic_based_on_tag.conf +32 -0
- data/examples/out_kafka2/protobuf-formatter.conf +23 -0
- data/examples/out_kafka2/record_key.conf +31 -0
- data/fluent-plugin-kafka.gemspec +2 -2
- data/lib/fluent/plugin/in_kafka.rb +3 -0
- data/lib/fluent/plugin/in_kafka_group.rb +3 -0
- data/lib/fluent/plugin/kafka_plugin_util.rb +15 -0
- data/lib/fluent/plugin/kafka_producer_ext.rb +14 -12
- data/lib/fluent/plugin/out_kafka2.rb +120 -20
- data/lib/fluent/plugin/out_rdkafka2.rb +39 -3
- data/test/plugin/test_out_kafka2.rb +15 -0
- data/test/plugin/test_out_rdkafka2.rb +15 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4a8c37b041fedc3f95046620413e5f7da437557fc19294439585fa89fd5b244
|
4
|
+
data.tar.gz: fe4c8cc8df6b8b5b105fbf709044e10752d8b64f321b5a4e290cb7e316e10fe1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ff333ee092e0ffd653ab476acf8b2656b4ca59ea32d6dcc846eb8a174f69d98811272e8a735bfa3bdfac3d5b3753ce499adb5c8a215b3197310b1f4d822364e
|
7
|
+
data.tar.gz: ebf6cafbde9635cfc886ee4dce84495353b2d389e447e6188f6a88eb4ca11b19086ce5a12565bac550ef26936f424e4ec5a0fe908fad4b39bea984758ac44720
|
data/.github/workflows/linux.yml
CHANGED
@@ -12,12 +12,15 @@ jobs:
|
|
12
12
|
strategy:
|
13
13
|
fail-fast: false
|
14
14
|
matrix:
|
15
|
-
ruby: [ '3.
|
15
|
+
ruby: [ '3.2', '3.1', '3.0', '2.7' ]
|
16
16
|
os:
|
17
17
|
- ubuntu-latest
|
18
|
-
|
18
|
+
rdkafka_versions:
|
19
|
+
- { min: '>= 0.6.0', max: '< 0.12.0' }
|
20
|
+
- { min: '>= 0.12.0', max: '>= 0.12.0' }
|
21
|
+
name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }} with rdkafka gem version (min ${{ matrix.rdkafka_versions.min }} max ${{ matrix.rdkafka_versions.max }})
|
19
22
|
steps:
|
20
|
-
- uses: actions/checkout@
|
23
|
+
- uses: actions/checkout@v3
|
21
24
|
- uses: ruby/setup-ruby@v1
|
22
25
|
with:
|
23
26
|
ruby-version: ${{ matrix.ruby }}
|
@@ -33,6 +36,8 @@ jobs:
|
|
33
36
|
- name: unit testing
|
34
37
|
env:
|
35
38
|
CI: true
|
39
|
+
RDKAFKA_VERSION_MIN_RANGE: ${{ matrix.rdkafka_versions.min }}
|
40
|
+
RDKAFKA_VERSION_MAX_RANGE: ${{ matrix.rdkafka_versions.max }}
|
36
41
|
run: |
|
37
42
|
sudo ./ci/prepare-kafka-server.sh
|
38
43
|
gem install bundler rake
|
@@ -7,7 +7,7 @@ jobs:
|
|
7
7
|
stale:
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
steps:
|
10
|
-
- uses: actions/stale@
|
10
|
+
- uses: actions/stale@v8
|
11
11
|
with:
|
12
12
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
13
13
|
days-before-stale: 90
|
@@ -18,5 +18,7 @@ jobs:
|
|
18
18
|
close-pr-message: "This PR was automatically closed because of stale in 30 days"
|
19
19
|
stale-pr-label: "stale"
|
20
20
|
stale-issue-label: "stale"
|
21
|
-
exempt-issue-labels: "bug,enhancement,help wanted"
|
22
|
-
exempt-pr-labels: "bug,enhancement,help wanted"
|
21
|
+
exempt-issue-labels: "bug,enhancement,help wanted,waiting-for-triage"
|
22
|
+
exempt-pr-labels: "bug,enhancement,help wanted,waiting-for-triage"
|
23
|
+
exempt-all-assignees: true
|
24
|
+
exempt-all-milestones: true
|
data/ChangeLog
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
Release 0.19.0 - 2023/04/26
|
2
|
+
* out_kafka2: Add support for AWS IAM authentication
|
3
|
+
* in_kafka, in_kafka_group, out_kafka2: Add support for ssl client cert key password
|
4
|
+
* out_rdkafka2: Mask `ssl_client_cert_key_password` on dumping it to log
|
5
|
+
* out_rdkafka2: Support rdkafka-ruby 0.12
|
6
|
+
|
7
|
+
Release 0.18.1 - 2022/08/17
|
8
|
+
* out_kafka2: Fix a bug that it doesn't respect `chunk_limit_records` and `chunk_limit_size`
|
9
|
+
|
10
|
+
Release 0.18.0 - 2022/07/21
|
11
|
+
* out_kafka2: Keep alive Kafka connections between flushes
|
12
|
+
* out_rdkafka2: Enable to set SASL credentials via `username` and `password` parameters
|
13
|
+
* out_kafka2/out_rdkafka2: Add `record_key` parameter
|
14
|
+
|
1
15
|
Release 0.17.5 - 2022/03/18
|
2
16
|
* out_kafka2: Add `resolve_seed_brokers` parameter
|
3
17
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -36,6 +36,7 @@ If you want to use zookeeper related parameters, you also need to install zookee
|
|
36
36
|
- ssl_ca_cert
|
37
37
|
- ssl_client_cert
|
38
38
|
- ssl_client_cert_key
|
39
|
+
- ssl_client_cert_key_password
|
39
40
|
- ssl_ca_certs_from_system
|
40
41
|
|
41
42
|
Set path to SSL related files. See [Encryption and Authentication using SSL](https://github.com/zendesk/ruby-kafka#encryption-and-authentication-using-ssl) for more detail.
|
@@ -187,12 +188,17 @@ If `ruby-kafka` doesn't fit your kafka environment, check `rdkafka2` plugin inst
|
|
187
188
|
@type kafka2
|
188
189
|
|
189
190
|
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,.. # Set brokers directly
|
191
|
+
|
192
|
+
# Kafka topic, placerholders are supported. Chunk keys are required in the Buffer section inorder for placeholders
|
193
|
+
# to work.
|
194
|
+
topic (string) :default => nil
|
190
195
|
topic_key (string) :default => 'topic'
|
191
196
|
partition_key (string) :default => 'partition'
|
192
197
|
partition_key_key (string) :default => 'partition_key'
|
193
198
|
message_key_key (string) :default => 'message_key'
|
194
199
|
default_topic (string) :default => nil
|
195
200
|
default_partition_key (string) :default => nil
|
201
|
+
record_key (string) :default => nil
|
196
202
|
default_message_key (string) :default => nil
|
197
203
|
exclude_topic_key (bool) :default => false
|
198
204
|
exclude_partition_key (bool) :default => false
|
@@ -205,6 +211,17 @@ If `ruby-kafka` doesn't fit your kafka environment, check `rdkafka2` plugin inst
|
|
205
211
|
use_default_for_unknown_topic (bool) :default => false
|
206
212
|
discard_kafka_delivery_failed (bool) :default => false (No discard)
|
207
213
|
partitioner_hash_function (enum) (crc32|murmur2) :default => 'crc32'
|
214
|
+
share_producer (bool) :default => false
|
215
|
+
|
216
|
+
# If you intend to rely on AWS IAM auth to MSK with long lived credentials
|
217
|
+
# https://docs.aws.amazon.com/msk/latest/developerguide/iam-access-control.html
|
218
|
+
#
|
219
|
+
# For AWS STS support, see status in
|
220
|
+
# - https://github.com/zendesk/ruby-kafka/issues/944
|
221
|
+
# - https://github.com/zendesk/ruby-kafka/pull/951
|
222
|
+
sasl_aws_msk_iam_access_key_id (string) :default => nil
|
223
|
+
sasl_aws_msk_iam_secret_key_id (string) :default => nil
|
224
|
+
sasl_aws_msk_iam_aws_region (string) :default => nil
|
208
225
|
|
209
226
|
<format>
|
210
227
|
@type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
|
@@ -241,13 +258,12 @@ ruby-kafka's log is routed to fluentd log so you can see ruby-kafka's log in flu
|
|
241
258
|
|
242
259
|
Supports following ruby-kafka's producer options.
|
243
260
|
|
244
|
-
- max_send_retries - default:
|
261
|
+
- max_send_retries - default: 2 - Number of times to retry sending of messages to a leader.
|
245
262
|
- required_acks - default: -1 - The number of acks required per request. If you need flush performance, set lower value, e.g. 1, 2.
|
246
263
|
- ack_timeout - default: nil - How long the producer waits for acks. The unit is seconds.
|
247
264
|
- compression_codec - default: nil - The codec the producer uses to compress messages.
|
248
265
|
- max_send_limit_bytes - default: nil - Max byte size to send message to avoid MessageSizeTooLarge. For example, if you set 1000000(message.max.bytes in kafka), Message more than 1000000 byes will be dropped.
|
249
266
|
- discard_kafka_delivery_failed - default: false - discard the record where [Kafka::DeliveryFailed](http://www.rubydoc.info/gems/ruby-kafka/Kafka/DeliveryFailed) occurred
|
250
|
-
- monitoring_list - default: [] - library to be used to monitor. statsd and datadog are supported
|
251
267
|
|
252
268
|
If you want to know about detail of monitoring, see also https://github.com/zendesk/ruby-kafka#monitoring
|
253
269
|
|
@@ -335,6 +351,40 @@ For example, `$.source.ip` can be extracted with config `headers_from_record` an
|
|
335
351
|
|
336
352
|
> Using this config to remove unused fields is discouraged. A [filter plugin](https://docs.fluentd.org/v/0.12/filter) can be used for this purpose.
|
337
353
|
|
354
|
+
#### Send only a sub field as a message payload
|
355
|
+
|
356
|
+
If `record_key` is provided, the plugin sends only a sub field given by that key.
|
357
|
+
The configuration format is jsonpath.
|
358
|
+
|
359
|
+
e.g. When the following configuration and the incoming record are given:
|
360
|
+
|
361
|
+
configuration:
|
362
|
+
|
363
|
+
<match **>
|
364
|
+
@type kafka2
|
365
|
+
[...]
|
366
|
+
record_key '$.data'
|
367
|
+
</match>
|
368
|
+
|
369
|
+
record:
|
370
|
+
|
371
|
+
{
|
372
|
+
"specversion" : "1.0",
|
373
|
+
"type" : "com.example.someevent",
|
374
|
+
"id" : "C234-1234-1234",
|
375
|
+
"time" : "2018-04-05T17:31:00Z",
|
376
|
+
"datacontenttype" : "application/json",
|
377
|
+
"data" : {
|
378
|
+
"appinfoA" : "abc",
|
379
|
+
"appinfoB" : 123,
|
380
|
+
"appinfoC" : true
|
381
|
+
},
|
382
|
+
...
|
383
|
+
}
|
384
|
+
|
385
|
+
only the `data` field will be serialized by the formatter and sent to Kafka.
|
386
|
+
The toplevel `data` key will be removed.
|
387
|
+
|
338
388
|
### Buffered output plugin
|
339
389
|
|
340
390
|
This plugin uses ruby-kafka producer for writing data. This plugin is for v0.12. If you use v1, see `kafka2`.
|
@@ -384,6 +434,16 @@ Support of fluentd v0.12 has ended. `kafka_buffered` will be an alias of `kafka2
|
|
384
434
|
monitoring_list (array) :default => []
|
385
435
|
</match>
|
386
436
|
|
437
|
+
`kafka_buffered` supports the following `ruby-kafka` parameters:
|
438
|
+
|
439
|
+
- max_send_retries - default: 2 - Number of times to retry sending of messages to a leader.
|
440
|
+
- required_acks - default: -1 - The number of acks required per request. If you need flush performance, set lower value, e.g. 1, 2.
|
441
|
+
- ack_timeout - default: nil - How long the producer waits for acks. The unit is seconds.
|
442
|
+
- compression_codec - default: nil - The codec the producer uses to compress messages.
|
443
|
+
- max_send_limit_bytes - default: nil - Max byte size to send message to avoid MessageSizeTooLarge. For example, if you set 1000000(message.max.bytes in kafka), Message more than 1000000 byes will be dropped.
|
444
|
+
- discard_kafka_delivery_failed - default: false - discard the record where [Kafka::DeliveryFailed](http://www.rubydoc.info/gems/ruby-kafka/Kafka/DeliveryFailed) occurred
|
445
|
+
- monitoring_list - default: [] - library to be used to monitor. statsd and datadog are supported
|
446
|
+
|
387
447
|
`kafka_buffered` has two additional parameters:
|
388
448
|
|
389
449
|
- kafka_agg_max_bytes - default: 4096 - Maximum value of total message size to be included in one batch transmission.
|
@@ -460,6 +520,7 @@ You need to install rdkafka gem.
|
|
460
520
|
# same with kafka2
|
461
521
|
headers (hash) :default => {}
|
462
522
|
headers_from_record (hash) :default => {}
|
523
|
+
record_key (string) :default => nil
|
463
524
|
|
464
525
|
<format>
|
465
526
|
@type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
|
data/examples/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
<source>
|
2
|
+
@type sample
|
3
|
+
sample {"hello": "world"}
|
4
|
+
rate 7000
|
5
|
+
tag sample.hello.world
|
6
|
+
</source>
|
7
|
+
|
8
|
+
<match sample.**>
|
9
|
+
@type kafka2
|
10
|
+
|
11
|
+
brokers "broker:29092"
|
12
|
+
|
13
|
+
# Writes to topic `events.sample.hello.world`
|
14
|
+
topic "events.${tag}"
|
15
|
+
|
16
|
+
# Writes to topic `hello.world`
|
17
|
+
# topic "${tag[1]}.${tag[2]}"
|
18
|
+
|
19
|
+
<format>
|
20
|
+
@type json
|
21
|
+
</format>
|
22
|
+
|
23
|
+
<buffer tag>
|
24
|
+
flush_at_shutdown true
|
25
|
+
flush_mode interval
|
26
|
+
flush_interval 1s
|
27
|
+
chunk_limit_size 3MB
|
28
|
+
chunk_full_threshold 1
|
29
|
+
total_limit_size 1024MB
|
30
|
+
overflow_action block
|
31
|
+
</buffer>
|
32
|
+
</match>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<source>
|
2
|
+
@type sample
|
3
|
+
sample {"hello": "world", "some_record":{"event":"message"}}
|
4
|
+
rate 7000
|
5
|
+
tag sample.hello.world
|
6
|
+
</source>
|
7
|
+
|
8
|
+
<match sample.**>
|
9
|
+
@type kafka2
|
10
|
+
|
11
|
+
brokers "broker:29092"
|
12
|
+
|
13
|
+
record_key "some_record"
|
14
|
+
default_topic "events"
|
15
|
+
|
16
|
+
<format>
|
17
|
+
# requires the fluent-plugin-formatter-protobuf gem
|
18
|
+
# see its docs for full usage
|
19
|
+
@type protobuf
|
20
|
+
class_name SomeRecord
|
21
|
+
include_paths ["/opt/fluent-plugin-formatter-protobuf/some_record_pb.rb"]
|
22
|
+
</format>
|
23
|
+
</match>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<source>
|
2
|
+
@type sample
|
3
|
+
sample {"hello": "world", "some_record":{"event":"message"}}
|
4
|
+
rate 7000
|
5
|
+
tag sample.hello.world
|
6
|
+
</source>
|
7
|
+
|
8
|
+
<match sample.**>
|
9
|
+
@type kafka2
|
10
|
+
|
11
|
+
brokers "broker:29092"
|
12
|
+
|
13
|
+
# {"event": "message"} will be formatted and sent to Kafka
|
14
|
+
record_key "some_record"
|
15
|
+
|
16
|
+
default_topic "events"
|
17
|
+
|
18
|
+
<format>
|
19
|
+
@type json
|
20
|
+
</format>
|
21
|
+
|
22
|
+
<buffer>
|
23
|
+
flush_at_shutdown true
|
24
|
+
flush_mode interval
|
25
|
+
flush_interval 1s
|
26
|
+
chunk_limit_size 3MB
|
27
|
+
chunk_full_threshold 1
|
28
|
+
total_limit_size 1024MB
|
29
|
+
overflow_action block
|
30
|
+
</buffer>
|
31
|
+
</match>
|
data/fluent-plugin-kafka.gemspec
CHANGED
@@ -13,12 +13,12 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
14
|
gem.name = "fluent-plugin-kafka"
|
15
15
|
gem.require_paths = ["lib"]
|
16
|
-
gem.version = '0.
|
16
|
+
gem.version = '0.19.0'
|
17
17
|
gem.required_ruby_version = ">= 2.1.0"
|
18
18
|
|
19
19
|
gem.add_dependency "fluentd", [">= 0.10.58", "< 2"]
|
20
20
|
gem.add_dependency 'ltsv'
|
21
|
-
gem.add_dependency 'ruby-kafka', '>= 1.
|
21
|
+
gem.add_dependency 'ruby-kafka', '>= 1.5.0', '< 2'
|
22
22
|
gem.add_development_dependency "rake", ">= 0.9.2"
|
23
23
|
gem.add_development_dependency "test-unit", ">= 3.0.8"
|
24
24
|
gem.add_development_dependency "test-unit-rr", "~> 1.0"
|
@@ -200,16 +200,19 @@ class Fluent::KafkaInput < Fluent::Input
|
|
200
200
|
if @scram_mechanism != nil && @username != nil && @password != nil
|
201
201
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, ssl_ca_cert_file_path: @ssl_ca_cert,
|
202
202
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
203
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
203
204
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system, sasl_scram_username: @username, sasl_scram_password: @password,
|
204
205
|
sasl_scram_mechanism: @scram_mechanism, sasl_over_ssl: @sasl_over_ssl, ssl_verify_hostname: @ssl_verify_hostname)
|
205
206
|
elsif @username != nil && @password != nil
|
206
207
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, ssl_ca_cert_file_path: @ssl_ca_cert,
|
207
208
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
209
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
208
210
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system,sasl_plain_username: @username, sasl_plain_password: @password,
|
209
211
|
sasl_over_ssl: @sasl_over_ssl, ssl_verify_hostname: @ssl_verify_hostname)
|
210
212
|
else
|
211
213
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, ssl_ca_cert_file_path: @ssl_ca_cert,
|
212
214
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
215
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
213
216
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system, sasl_gssapi_principal: @principal, sasl_gssapi_keytab: @keytab,
|
214
217
|
ssl_verify_hostname: @ssl_verify_hostname)
|
215
218
|
end
|
@@ -188,16 +188,19 @@ class Fluent::KafkaGroupInput < Fluent::Input
|
|
188
188
|
if @scram_mechanism != nil && @username != nil && @password != nil
|
189
189
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, connect_timeout: @connect_timeout, socket_timeout: @socket_timeout, ssl_ca_cert_file_path: @ssl_ca_cert,
|
190
190
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
191
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
191
192
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system, sasl_scram_username: @username, sasl_scram_password: @password,
|
192
193
|
sasl_scram_mechanism: @scram_mechanism, sasl_over_ssl: @sasl_over_ssl, ssl_verify_hostname: @ssl_verify_hostname)
|
193
194
|
elsif @username != nil && @password != nil
|
194
195
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, connect_timeout: @connect_timeout, socket_timeout: @socket_timeout, ssl_ca_cert_file_path: @ssl_ca_cert,
|
195
196
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
197
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
196
198
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system, sasl_plain_username: @username, sasl_plain_password: @password,
|
197
199
|
sasl_over_ssl: @sasl_over_ssl, ssl_verify_hostname: @ssl_verify_hostname)
|
198
200
|
else
|
199
201
|
@kafka = Kafka.new(seed_brokers: @brokers, client_id: @client_id, logger: logger, connect_timeout: @connect_timeout, socket_timeout: @socket_timeout, ssl_ca_cert_file_path: @ssl_ca_cert,
|
200
202
|
ssl_client_cert: read_ssl_file(@ssl_client_cert), ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
203
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
201
204
|
ssl_ca_certs_from_system: @ssl_ca_certs_from_system, sasl_gssapi_principal: @principal, sasl_gssapi_keytab: @keytab,
|
202
205
|
ssl_verify_hostname: @ssl_verify_hostname)
|
203
206
|
end
|
@@ -1,5 +1,18 @@
|
|
1
1
|
module Fluent
|
2
2
|
module KafkaPluginUtil
|
3
|
+
module AwsIamSettings
|
4
|
+
def self.included(klass)
|
5
|
+
klass.instance_eval do
|
6
|
+
config_param :sasl_aws_msk_iam_access_key_id, :string, :default => nil, secret: true,
|
7
|
+
desc: "AWS access key Id for IAM authentication to MSK."
|
8
|
+
config_param :sasl_aws_msk_iam_secret_key_id, :string, :default => nil, secret: true,
|
9
|
+
desc: "AWS access key secret for IAM authentication to MSK."
|
10
|
+
config_param :sasl_aws_msk_iam_aws_region, :string, :default => nil,
|
11
|
+
desc: "AWS region for IAM authentication to MSK."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
3
16
|
module SSLSettings
|
4
17
|
def self.included(klass)
|
5
18
|
klass.instance_eval {
|
@@ -10,6 +23,8 @@ module Fluent
|
|
10
23
|
:desc => "a PEM encoded client cert to use with and SSL connection. Must be used in combination with ssl_client_cert_key."
|
11
24
|
config_param :ssl_client_cert_key, :string, :default => nil,
|
12
25
|
:desc => "a PEM encoded client cert key to use with and SSL connection. Must be used in combination with ssl_client_cert."
|
26
|
+
config_param :ssl_client_cert_key_password, :string, :default => nil, secret: true,
|
27
|
+
:desc => "a PEM encoded client cert key password to use with SSL connection."
|
13
28
|
config_param :ssl_client_cert_chain, :string, :default => nil,
|
14
29
|
:desc => "an extra PEM encoded cert to use with and SSL connection."
|
15
30
|
config_param :ssl_ca_certs_from_system, :bool, :default => false,
|
@@ -38,9 +38,15 @@ module Kafka
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# for out_kafka2
|
41
|
+
# Majority (if not all) of this code is lifted from https://github.com/zendesk/ruby-kafka/blob/master/lib/kafka/producer.rb
|
42
|
+
# with the main difference where we have removed any checks regarding max_buffer_bytesize and max_buffer_size
|
43
|
+
# The reason for doing this is to provide a better UX for our users where they only need to set those bounds in
|
44
|
+
# the Buffer section using `chunk_limit_size` and `chunk_limit_records`.
|
45
|
+
#
|
46
|
+
# We should reconsider this in the future in case the `ruby-kafka` library drastically changes its internal.
|
41
47
|
module Kafka
|
42
48
|
class Client
|
43
|
-
def
|
49
|
+
def custom_producer(compression_codec: nil, compression_threshold: 1, ack_timeout: 5, required_acks: :all, max_retries: 2, retry_backoff: 1, max_buffer_size: 1000, max_buffer_bytesize: 10_000_000, idempotent: false, transactional: false, transactional_id: nil, transactional_timeout: 60)
|
44
50
|
cluster = initialize_cluster
|
45
51
|
compressor = Compressor.new(
|
46
52
|
codec_name: compression_codec,
|
@@ -57,8 +63,7 @@ module Kafka
|
|
57
63
|
transactional_timeout: transactional_timeout,
|
58
64
|
)
|
59
65
|
|
60
|
-
|
61
|
-
cluster: cluster,
|
66
|
+
CustomProducer.new(cluster: cluster,
|
62
67
|
transaction_manager: transaction_manager,
|
63
68
|
logger: @logger,
|
64
69
|
instrumenter: @instrumenter,
|
@@ -74,8 +79,8 @@ module Kafka
|
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
|
-
class
|
78
|
-
def initialize(
|
82
|
+
class CustomProducer
|
83
|
+
def initialize(cluster:, transaction_manager:, logger:, instrumenter:, compressor:, ack_timeout:, required_acks:, max_retries:, retry_backoff:, max_buffer_size:, max_buffer_bytesize:, partitioner:)
|
79
84
|
@cluster = cluster
|
80
85
|
@transaction_manager = transaction_manager
|
81
86
|
@logger = logger
|
@@ -88,10 +93,6 @@ module Kafka
|
|
88
93
|
@max_buffer_bytesize = max_buffer_bytesize
|
89
94
|
@compressor = compressor
|
90
95
|
@partitioner = partitioner
|
91
|
-
|
92
|
-
@topic = topic
|
93
|
-
@cluster.add_target_topics(Set.new([topic]))
|
94
|
-
|
95
96
|
# A buffer organized by topic/partition.
|
96
97
|
@buffer = MessageBuffer.new
|
97
98
|
|
@@ -99,12 +100,12 @@ module Kafka
|
|
99
100
|
@pending_message_queue = PendingMessageQueue.new
|
100
101
|
end
|
101
102
|
|
102
|
-
def produce(value, key: nil, partition: nil, partition_key: nil, headers: EMPTY_HEADER, create_time: Time.now)
|
103
|
+
def produce(value, key: nil, partition: nil, partition_key: nil, headers: EMPTY_HEADER, create_time: Time.now, topic: nil)
|
103
104
|
message = PendingMessage.new(
|
104
105
|
value: value,
|
105
106
|
key: key,
|
106
107
|
headers: headers,
|
107
|
-
topic:
|
108
|
+
topic: topic,
|
108
109
|
partition: partition,
|
109
110
|
partition_key: partition_key,
|
110
111
|
create_time: create_time
|
@@ -245,12 +246,13 @@ module Kafka
|
|
245
246
|
|
246
247
|
def assign_partitions!
|
247
248
|
failed_messages = []
|
248
|
-
partition_count = @cluster.partitions_for(@topic).count
|
249
249
|
|
250
250
|
@pending_message_queue.each do |message|
|
251
251
|
partition = message.partition
|
252
252
|
|
253
253
|
begin
|
254
|
+
partition_count = @cluster.partitions_for(message.topic).count
|
255
|
+
|
254
256
|
if partition.nil?
|
255
257
|
partition = @partitioner.call(partition_count, message)
|
256
258
|
end
|
@@ -27,6 +27,11 @@ DESC
|
|
27
27
|
config_param :partitioner_hash_function, :enum, list: [:crc32, :murmur2], :default => :crc32,
|
28
28
|
:desc => "Specify kafka patrtitioner hash algorithm"
|
29
29
|
config_param :default_partition, :integer, :default => nil
|
30
|
+
config_param :record_key, :string, :default => nil,
|
31
|
+
:desc => <<-DESC
|
32
|
+
A jsonpath to a record value pointing to the field which will be passed to the formatter and sent as the Kafka message payload.
|
33
|
+
If defined, only this field in the record will be sent to Kafka as the message payload.
|
34
|
+
DESC
|
30
35
|
config_param :use_default_for_unknown_topic, :bool, :default => false, :desc => "If true, default_topic is used when topic not found"
|
31
36
|
config_param :client_id, :string, :default => 'fluentd'
|
32
37
|
config_param :idempotent, :bool, :default => false, :desc => 'Enable idempotent producer'
|
@@ -81,6 +86,7 @@ DESC
|
|
81
86
|
Add a regular expression to capture ActiveSupport notifications from the Kafka client
|
82
87
|
requires activesupport gem - records will be generated under fluent_kafka_stats.**
|
83
88
|
DESC
|
89
|
+
config_param :share_producer, :bool, :default => false, :desc => 'share kafka producer between flush threads'
|
84
90
|
|
85
91
|
config_section :buffer do
|
86
92
|
config_set_default :chunk_keys, ["topic"]
|
@@ -89,6 +95,7 @@ DESC
|
|
89
95
|
config_set_default :@type, 'json'
|
90
96
|
end
|
91
97
|
|
98
|
+
include Fluent::KafkaPluginUtil::AwsIamSettings
|
92
99
|
include Fluent::KafkaPluginUtil::SSLSettings
|
93
100
|
include Fluent::KafkaPluginUtil::SaslSettings
|
94
101
|
|
@@ -96,30 +103,58 @@ DESC
|
|
96
103
|
super
|
97
104
|
|
98
105
|
@kafka = nil
|
106
|
+
@producers = nil
|
107
|
+
@producers_mutex = nil
|
108
|
+
@shared_producer = nil
|
109
|
+
|
110
|
+
@writing_threads_mutex = Mutex.new
|
111
|
+
@writing_threads = Set.new
|
99
112
|
end
|
100
113
|
|
101
114
|
def refresh_client(raise_error = true)
|
102
115
|
begin
|
103
116
|
logger = @get_kafka_client_log ? log : nil
|
117
|
+
use_long_lived_aws_credentials = @sasl_aws_msk_iam_access_key_id != nil && @sasl_aws_msk_iam_secret_key_id != nil
|
104
118
|
if @scram_mechanism != nil && @username != nil && @password != nil
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
119
|
+
sasl_params = {
|
120
|
+
sasl_scram_username: @username,
|
121
|
+
sasl_scram_password: @password,
|
122
|
+
sasl_scram_mechanism: @scram_mechanism,
|
123
|
+
}
|
110
124
|
elsif @username != nil && @password != nil
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
125
|
+
sasl_params = {
|
126
|
+
sasl_plain_username: @username,
|
127
|
+
sasl_plain_password: @password,
|
128
|
+
}
|
129
|
+
elsif use_long_lived_aws_credentials
|
130
|
+
sasl_params = {
|
131
|
+
sasl_aws_msk_iam_access_key_id: @sasl_aws_msk_iam_access_key_id,
|
132
|
+
sasl_aws_msk_iam_secret_key_id: @sasl_aws_msk_iam_secret_key_id,
|
133
|
+
sasl_aws_msk_iam_aws_region: @sasl_aws_msk_iam_aws_region,
|
134
|
+
}
|
116
135
|
else
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
partitioner: Kafka::Partitioner.new(hash_function: @partitioner_hash_function))
|
136
|
+
sasl_params = {
|
137
|
+
sasl_gssapi_principal: @principal,
|
138
|
+
sasl_gssapi_keytab: @keytab,
|
139
|
+
}
|
122
140
|
end
|
141
|
+
@kafka = Kafka.new(
|
142
|
+
seed_brokers: @seed_brokers,
|
143
|
+
client_id: @client_id,
|
144
|
+
logger: logger,
|
145
|
+
connect_timeout: @connect_timeout,
|
146
|
+
socket_timeout: @socket_timeout,
|
147
|
+
ssl_ca_cert_file_path: @ssl_ca_cert,
|
148
|
+
ssl_client_cert: read_ssl_file(@ssl_client_cert),
|
149
|
+
ssl_client_cert_key: read_ssl_file(@ssl_client_cert_key),
|
150
|
+
ssl_client_cert_key_password: @ssl_client_cert_key_password,
|
151
|
+
ssl_client_cert_chain: read_ssl_file(@ssl_client_cert_chain),
|
152
|
+
ssl_ca_certs_from_system: @ssl_ca_certs_from_system,
|
153
|
+
ssl_verify_hostname: @ssl_verify_hostname,
|
154
|
+
resolve_seed_brokers: @resolve_seed_brokers,
|
155
|
+
partitioner: Kafka::Partitioner.new(hash_function: @partitioner_hash_function),
|
156
|
+
sasl_over_ssl: @sasl_over_ssl,
|
157
|
+
**sasl_params)
|
123
158
|
log.info "initialized kafka producer: #{@client_id}"
|
124
159
|
rescue Exception => e
|
125
160
|
if raise_error # During startup, error should be reported to engine and stop its phase for safety.
|
@@ -185,15 +220,29 @@ DESC
|
|
185
220
|
@exclude_field_accessors = @exclude_fields.map do |field|
|
186
221
|
record_accessor_create(field)
|
187
222
|
end
|
223
|
+
|
224
|
+
@record_field_accessor = nil
|
225
|
+
@record_field_accessor = record_accessor_create(@record_key) unless @record_key.nil?
|
188
226
|
end
|
189
227
|
|
190
228
|
def multi_workers_ready?
|
191
229
|
true
|
192
230
|
end
|
193
231
|
|
232
|
+
def create_producer
|
233
|
+
@kafka.custom_producer(**@producer_opts)
|
234
|
+
end
|
235
|
+
|
194
236
|
def start
|
195
237
|
super
|
196
238
|
refresh_client
|
239
|
+
|
240
|
+
if @share_producer
|
241
|
+
@shared_producer = create_producer
|
242
|
+
else
|
243
|
+
@producers = {}
|
244
|
+
@producers_mutex = Mutex.new
|
245
|
+
end
|
197
246
|
end
|
198
247
|
|
199
248
|
def close
|
@@ -206,6 +255,56 @@ DESC
|
|
206
255
|
@kafka = nil
|
207
256
|
end
|
208
257
|
|
258
|
+
def wait_writing_threads
|
259
|
+
done = false
|
260
|
+
until done do
|
261
|
+
@writing_threads_mutex.synchronize do
|
262
|
+
done = true if @writing_threads.empty?
|
263
|
+
end
|
264
|
+
sleep(1) unless done
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def shutdown
|
269
|
+
super
|
270
|
+
wait_writing_threads
|
271
|
+
shutdown_producers
|
272
|
+
end
|
273
|
+
|
274
|
+
def shutdown_producers
|
275
|
+
if @share_producer
|
276
|
+
@shared_producer.shutdown
|
277
|
+
@shared_producer = nil
|
278
|
+
else
|
279
|
+
@producers_mutex.synchronize {
|
280
|
+
shutdown_threads = @producers.map { |key, producer|
|
281
|
+
th = Thread.new {
|
282
|
+
producer.shutdown
|
283
|
+
}
|
284
|
+
th.abort_on_exception = true
|
285
|
+
th
|
286
|
+
}
|
287
|
+
shutdown_threads.each { |th| th.join }
|
288
|
+
@producers = {}
|
289
|
+
}
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def get_producer
|
294
|
+
if @share_producer
|
295
|
+
@shared_producer
|
296
|
+
else
|
297
|
+
@producers_mutex.synchronize {
|
298
|
+
producer = @producers[Thread.current.object_id]
|
299
|
+
unless producer
|
300
|
+
producer = create_producer
|
301
|
+
@producers[Thread.current.object_id] = producer
|
302
|
+
end
|
303
|
+
producer
|
304
|
+
}
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
209
308
|
def setup_formatter(conf)
|
210
309
|
type = conf['@type']
|
211
310
|
case type
|
@@ -229,6 +328,8 @@ DESC
|
|
229
328
|
|
230
329
|
# TODO: optimize write performance
|
231
330
|
def write(chunk)
|
331
|
+
@writing_threads_mutex.synchronize { @writing_threads.add(Thread.current) }
|
332
|
+
|
232
333
|
tag = chunk.metadata.tag
|
233
334
|
topic = if @topic
|
234
335
|
extract_placeholders(@topic, chunk)
|
@@ -237,13 +338,12 @@ DESC
|
|
237
338
|
end
|
238
339
|
|
239
340
|
messages = 0
|
240
|
-
record_buf = nil
|
241
341
|
|
242
342
|
base_headers = @headers
|
243
343
|
mutate_headers = !@headers_from_record_accessors.empty?
|
244
344
|
|
245
345
|
begin
|
246
|
-
producer =
|
346
|
+
producer = get_producer
|
247
347
|
chunk.msgpack_each { |time, record|
|
248
348
|
begin
|
249
349
|
record = inject_values_to_record(tag, time, record)
|
@@ -267,6 +367,7 @@ DESC
|
|
267
367
|
end
|
268
368
|
end
|
269
369
|
|
370
|
+
record = @record_field_accessor.call(record) unless @record_field_accessor.nil?
|
270
371
|
record_buf = @formatter_proc.call(tag, time, record)
|
271
372
|
record_buf_bytes = record_buf.bytesize
|
272
373
|
if @max_send_limit_bytes && record_buf_bytes > @max_send_limit_bytes
|
@@ -283,7 +384,7 @@ DESC
|
|
283
384
|
messages += 1
|
284
385
|
|
285
386
|
producer.produce(record_buf, key: message_key, partition_key: partition_key, partition: partition, headers: headers,
|
286
|
-
create_time: @use_event_time ? Time.at(time) : Time.now)
|
387
|
+
create_time: @use_event_time ? Time.at(time) : Time.now, topic: topic)
|
287
388
|
}
|
288
389
|
|
289
390
|
if messages > 0
|
@@ -301,7 +402,6 @@ DESC
|
|
301
402
|
end
|
302
403
|
rescue Kafka::UnknownTopicOrPartition
|
303
404
|
if @use_default_for_unknown_topic && topic != @default_topic
|
304
|
-
producer.shutdown if producer
|
305
405
|
log.warn "'#{topic}' topic not found. Retry with '#{default_topic}' topic"
|
306
406
|
topic = @default_topic
|
307
407
|
retry
|
@@ -321,7 +421,7 @@ DESC
|
|
321
421
|
# Raise exception to retry sendind messages
|
322
422
|
raise e unless ignore
|
323
423
|
ensure
|
324
|
-
|
424
|
+
@writing_threads_mutex.synchronize { @writing_threads.delete(Thread.current) }
|
325
425
|
end
|
326
426
|
end
|
327
427
|
end
|
@@ -5,9 +5,37 @@ require 'fluent/plugin/kafka_plugin_util'
|
|
5
5
|
|
6
6
|
require 'rdkafka'
|
7
7
|
|
8
|
+
# This is required for `rdkafka` version >= 0.12.0
|
9
|
+
# Overriding the close method in order to provide a time limit for when it should be forcibly closed
|
10
|
+
class Rdkafka::Producer::Client
|
11
|
+
# return false if producer is forcefully closed, otherwise return true
|
12
|
+
def close(timeout=nil)
|
13
|
+
return unless @native
|
14
|
+
|
15
|
+
# Indicate to polling thread that we're closing
|
16
|
+
@polling_thread[:closing] = true
|
17
|
+
# Wait for the polling thread to finish up
|
18
|
+
thread = @polling_thread.join(timeout)
|
19
|
+
|
20
|
+
Rdkafka::Bindings.rd_kafka_destroy(@native)
|
21
|
+
|
22
|
+
@native = nil
|
23
|
+
|
24
|
+
return !thread.nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
8
28
|
class Rdkafka::Producer
|
9
29
|
# return false if producer is forcefully closed, otherwise return true
|
10
30
|
def close(timeout = nil)
|
31
|
+
rdkafka_version = Rdkafka::VERSION || '0.0.0'
|
32
|
+
# Rdkafka version >= 0.12.0 changed its internals
|
33
|
+
if Gem::Version::create(rdkafka_version) >= Gem::Version.create('0.12.0')
|
34
|
+
ObjectSpace.undefine_finalizer(self)
|
35
|
+
|
36
|
+
return @client.close(timeout)
|
37
|
+
end
|
38
|
+
|
11
39
|
@closing = true
|
12
40
|
# Wait for the polling thread to finish up
|
13
41
|
# If the broker isn't alive, the thread doesn't exit
|
@@ -73,6 +101,11 @@ DESC
|
|
73
101
|
:desc => <<-DESC
|
74
102
|
The codec the producer uses to compress messages. Used for compression.codec
|
75
103
|
Supported codecs: (gzip|snappy)
|
104
|
+
DESC
|
105
|
+
config_param :record_key, :string, :default => nil,
|
106
|
+
:desc => <<-DESC
|
107
|
+
A jsonpath to a record value pointing to the field which will be passed to the formatter and sent as the Kafka message payload.
|
108
|
+
If defined, only this field in the record will be sent to Kafka as the message payload.
|
76
109
|
DESC
|
77
110
|
config_param :use_event_time, :bool, :default => false, :desc => 'Use fluentd event time for rdkafka timestamp'
|
78
111
|
config_param :max_send_limit_bytes, :size, :default => nil
|
@@ -90,7 +123,6 @@ DESC
|
|
90
123
|
config_param :max_enqueue_bytes_per_second, :size, :default => nil, :desc => 'The maximum number of enqueueing bytes per second'
|
91
124
|
|
92
125
|
config_param :service_name, :string, :default => nil, :desc => 'Used for sasl.kerberos.service.name'
|
93
|
-
config_param :ssl_client_cert_key_password, :string, :default => nil, :desc => 'Used for ssl.key.password'
|
94
126
|
|
95
127
|
config_section :buffer do
|
96
128
|
config_set_default :chunk_keys, ["topic"]
|
@@ -230,6 +262,9 @@ DESC
|
|
230
262
|
end
|
231
263
|
|
232
264
|
@enqueue_rate = EnqueueRate.new(@max_enqueue_bytes_per_second) unless @max_enqueue_bytes_per_second.nil?
|
265
|
+
|
266
|
+
@record_field_accessor = nil
|
267
|
+
@record_field_accessor = record_accessor_create(@record_key) unless @record_key.nil?
|
233
268
|
end
|
234
269
|
|
235
270
|
def build_config
|
@@ -270,6 +305,8 @@ DESC
|
|
270
305
|
config[:"queue.buffering.max.messages"] = @rdkafka_buffering_max_messages if @rdkafka_buffering_max_messages
|
271
306
|
config[:"message.max.bytes"] = @rdkafka_message_max_bytes if @rdkafka_message_max_bytes
|
272
307
|
config[:"batch.num.messages"] = @rdkafka_message_max_num if @rdkafka_message_max_num
|
308
|
+
config[:"sasl.username"] = @username if @username
|
309
|
+
config[:"sasl.password"] = @password if @password
|
273
310
|
|
274
311
|
@rdkafka_options.each { |k, v|
|
275
312
|
config[k.to_sym] = v
|
@@ -371,8 +408,6 @@ DESC
|
|
371
408
|
end
|
372
409
|
|
373
410
|
handlers = []
|
374
|
-
record_buf = nil
|
375
|
-
record_buf_bytes = nil
|
376
411
|
|
377
412
|
headers = @headers.clone
|
378
413
|
|
@@ -395,6 +430,7 @@ DESC
|
|
395
430
|
end
|
396
431
|
end
|
397
432
|
|
433
|
+
record = @record_field_accessor.call(record) unless @record_field_accessor.nil?
|
398
434
|
record_buf = @formatter_proc.call(tag, time, record)
|
399
435
|
record_buf_bytes = record_buf.bytesize
|
400
436
|
if @max_send_limit_bytes && record_buf_bytes > @max_send_limit_bytes
|
@@ -105,6 +105,21 @@ class Kafka2OutputTest < Test::Unit::TestCase
|
|
105
105
|
assert_equal([expected_message], actual_messages)
|
106
106
|
end
|
107
107
|
|
108
|
+
def test_record_key
|
109
|
+
conf = config(default_topic: TOPIC_NAME) +
|
110
|
+
config_element('ROOT', '', {"record_key" => "$.data"}, [])
|
111
|
+
target_driver = create_target_driver
|
112
|
+
target_driver.run(expect_records: 1, timeout: 5) do
|
113
|
+
sleep 2
|
114
|
+
d = create_driver(conf)
|
115
|
+
d.run do
|
116
|
+
d.feed('test', event_time, {'data' => {'a' => 'b', 'foo' => 'bar', 'message' => 'test'}, 'message_key' => '123456'})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
actual_messages = target_driver.events.collect { |event| event[2] }
|
120
|
+
assert_equal([{'a' => 'b', 'foo' => 'bar', 'message' => 'test'}], actual_messages)
|
121
|
+
end
|
122
|
+
|
108
123
|
def test_exclude_fields
|
109
124
|
conf = config(default_topic: TOPIC_NAME) +
|
110
125
|
config_element('ROOT', '', {"exclude_fields" => "$.foo"}, [])
|
@@ -163,5 +163,20 @@ class Rdkafka2OutputTest < Test::Unit::TestCase
|
|
163
163
|
actual_messages = target_driver.events.collect { |event| event[2] }
|
164
164
|
assert_equal(expected_messages, actual_messages)
|
165
165
|
end
|
166
|
+
|
167
|
+
def test_record_key
|
168
|
+
conf = config(default_topic: TOPIC_NAME) +
|
169
|
+
config_element('ROOT', '', {"record_key" => "$.data"}, [])
|
170
|
+
target_driver = create_target_driver
|
171
|
+
target_driver.run(expect_records: 1, timeout: 5) do
|
172
|
+
sleep 2
|
173
|
+
d = create_driver(conf)
|
174
|
+
d.run do
|
175
|
+
d.feed('test', event_time, {'data' => {'a' => 'b', 'foo' => 'bar', 'message' => 'test'}, 'message_key' => '123456'})
|
176
|
+
end
|
177
|
+
end
|
178
|
+
actual_messages = target_driver.events.collect { |event| event[2] }
|
179
|
+
assert_equal([{'a' => 'b', 'foo' => 'bar', 'message' => 'test'}], actual_messages)
|
180
|
+
end
|
166
181
|
end
|
167
182
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-kafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hidemasa Togashi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-04-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -51,7 +51,7 @@ dependencies:
|
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.
|
54
|
+
version: 1.5.0
|
55
55
|
- - "<"
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '2'
|
@@ -61,7 +61,7 @@ dependencies:
|
|
61
61
|
requirements:
|
62
62
|
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 1.
|
64
|
+
version: 1.5.0
|
65
65
|
- - "<"
|
66
66
|
- !ruby/object:Gem::Version
|
67
67
|
version: '2'
|
@@ -146,6 +146,7 @@ files:
|
|
146
146
|
- ".github/ISSUE_TEMPLATE/bug_report.yaml"
|
147
147
|
- ".github/ISSUE_TEMPLATE/config.yml"
|
148
148
|
- ".github/ISSUE_TEMPLATE/feature_request.yaml"
|
149
|
+
- ".github/dependabot.yml"
|
149
150
|
- ".github/workflows/linux.yml"
|
150
151
|
- ".github/workflows/stale-actions.yml"
|
151
152
|
- ".gitignore"
|
@@ -155,6 +156,10 @@ files:
|
|
155
156
|
- README.md
|
156
157
|
- Rakefile
|
157
158
|
- ci/prepare-kafka-server.sh
|
159
|
+
- examples/README.md
|
160
|
+
- examples/out_kafka2/dynamic_topic_based_on_tag.conf
|
161
|
+
- examples/out_kafka2/protobuf-formatter.conf
|
162
|
+
- examples/out_kafka2/record_key.conf
|
158
163
|
- fluent-plugin-kafka.gemspec
|
159
164
|
- lib/fluent/plugin/in_kafka.rb
|
160
165
|
- lib/fluent/plugin/in_kafka_group.rb
|
@@ -193,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
198
|
- !ruby/object:Gem::Version
|
194
199
|
version: '0'
|
195
200
|
requirements: []
|
196
|
-
rubygems_version: 3.
|
201
|
+
rubygems_version: 3.3.5
|
197
202
|
signing_key:
|
198
203
|
specification_version: 4
|
199
204
|
summary: Fluentd plugin for Apache Kafka > 0.8
|