logstash-integration-kafka 10.7.2-java → 10.7.3-java
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/CHANGELOG.md +4 -1
- data/docs/input-kafka.asciidoc +12 -6
- data/lib/logstash/inputs/kafka.rb +42 -4
- data/logstash-integration-kafka.gemspec +2 -1
- data/spec/integration/inputs/kafka_spec.rb +65 -2
- data/spec/unit/inputs/kafka_spec.rb +26 -9
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1049dfcad573e64aed24bebc6114b0345ce6513e43c2104c54ac8e3ed6602e57
|
4
|
+
data.tar.gz: 41260002d0a2765b4beeac73bdd8d8f100e0b3e058c1e5dbac4f2a460a29a3d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 744b4621e51c32ef882c7f5521be467c75805c2ba6ee8eaf225567412fe9e6bade35e60ae7fa85b87de50f68a191f5408b0504025e28071e11eb227ab5f428c8
|
7
|
+
data.tar.gz: feb75d5f0da3523e891253213cf52b49460881c125adf2fc82710f96c0feaa3eb4630468bbec7f1182c6a52e44b060362b5dd946b6194c066821a3de4c6e1314
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
## 10.7.3
|
2
|
+
- Changed `decorate_events` to add also Kafka headers [#78](https://github.com/logstash-plugins/logstash-integration-kafka/pull/78)
|
3
|
+
|
1
4
|
## 10.7.2
|
2
5
|
- Update Jersey dependency to version 2.33 [#75](https://github.com/logstash-plugins/logstash-integration-kafka/pull/75)
|
3
6
|
|
4
7
|
## 10.7.1
|
5
|
-
- Fix: dropped usage of SHUTDOWN event deprecated since Logstash 5.0 [#71](https://github.com/logstash-plugins/logstash-integration-kafka/
|
8
|
+
- Fix: dropped usage of SHUTDOWN event deprecated since Logstash 5.0 [#71](https://github.com/logstash-plugins/logstash-integration-kafka/pull/71)
|
6
9
|
|
7
10
|
## 10.7.0
|
8
11
|
- Switched use from Faraday to Manticore as HTTP client library to access Schema Registry service
|
data/docs/input-kafka.asciidoc
CHANGED
@@ -73,7 +73,7 @@ either when the record was created (default) or when it was received by the
|
|
73
73
|
broker. See more about property log.message.timestamp.type at
|
74
74
|
https://kafka.apache.org/{kafka_client_doc}/documentation.html#brokerconfigs
|
75
75
|
|
76
|
-
Metadata is only added to the event if the `decorate_events` option is set to
|
76
|
+
Metadata is only added to the event if the `decorate_events` option is set to `basic` or `extended` (it defaults to `none`).
|
77
77
|
|
78
78
|
Please note that `@metadata` fields are not part of any of your events at output time. If you need these information to be
|
79
79
|
inserted into your original event, you'll have to use the `mutate` filter to manually copy the required fields into your `event`.
|
@@ -99,7 +99,7 @@ See the https://kafka.apache.org/{kafka_client_doc}/documentation for more detai
|
|
99
99
|
| <<plugins-{type}s-{plugin}-client_rack>> |<<string,string>>|No
|
100
100
|
| <<plugins-{type}s-{plugin}-connections_max_idle_ms>> |<<number,number>>|No
|
101
101
|
| <<plugins-{type}s-{plugin}-consumer_threads>> |<<number,number>>|No
|
102
|
-
| <<plugins-{type}s-{plugin}-decorate_events>> |<<
|
102
|
+
| <<plugins-{type}s-{plugin}-decorate_events>> |<<string,string>>|No
|
103
103
|
| <<plugins-{type}s-{plugin}-enable_auto_commit>> |<<boolean,boolean>>|No
|
104
104
|
| <<plugins-{type}s-{plugin}-exclude_internal_topics>> |<<string,string>>|No
|
105
105
|
| <<plugins-{type}s-{plugin}-fetch_max_bytes>> |<<number,number>>|No
|
@@ -246,10 +246,16 @@ balance — more threads than partitions means that some threads will be idl
|
|
246
246
|
[id="plugins-{type}s-{plugin}-decorate_events"]
|
247
247
|
===== `decorate_events`
|
248
248
|
|
249
|
-
* Value type is <<
|
250
|
-
*
|
251
|
-
|
252
|
-
|
249
|
+
* Value type is <<string,string>>
|
250
|
+
* Accepted values are:
|
251
|
+
- `none`: no metadata is added
|
252
|
+
- `basic`: record's attributes are added
|
253
|
+
- `extended`: record's attributes, headers are added
|
254
|
+
- `false`: deprecated alias for `none`
|
255
|
+
- `true`: deprecated alias for `basic`
|
256
|
+
* Default value is `none`
|
257
|
+
|
258
|
+
Option to add Kafka metadata like topic, message size and header key values to the event.
|
253
259
|
This will add a field named `kafka` to the logstash event containing the following attributes:
|
254
260
|
|
255
261
|
* `topic`: The topic this message is associated with
|
@@ -8,6 +8,7 @@ require 'manticore'
|
|
8
8
|
require "json"
|
9
9
|
require "logstash/json"
|
10
10
|
require_relative '../plugin_mixins/common'
|
11
|
+
require 'logstash/plugin_mixins/deprecation_logger_support'
|
11
12
|
|
12
13
|
# This input will read events from a Kafka topic. It uses the 0.10 version of
|
13
14
|
# the consumer API provided by Kafka to read messages from the broker.
|
@@ -58,6 +59,7 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
58
59
|
|
59
60
|
include LogStash::PluginMixins::KafkaSupport
|
60
61
|
include ::LogStash::PluginMixins::KafkaAvroSchemaRegistry
|
62
|
+
include LogStash::PluginMixins::DeprecationLoggerSupport
|
61
63
|
|
62
64
|
config_name 'kafka'
|
63
65
|
|
@@ -233,22 +235,49 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
233
235
|
config :sasl_jaas_config, :validate => :string
|
234
236
|
# Optional path to kerberos config file. This is krb5.conf style as detailed in https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html
|
235
237
|
config :kerberos_config, :validate => :path
|
236
|
-
# Option to add Kafka metadata like topic, message size to the event.
|
237
|
-
#
|
238
|
+
# Option to add Kafka metadata like topic, message size and header key values to the event.
|
239
|
+
# With `basic` this will add a field named `kafka` to the logstash event containing the following attributes:
|
238
240
|
# `topic`: The topic this message is associated with
|
239
241
|
# `consumer_group`: The consumer group used to read in this event
|
240
242
|
# `partition`: The partition this message is associated with
|
241
243
|
# `offset`: The offset from the partition this message is associated with
|
242
244
|
# `key`: A ByteBuffer containing the message key
|
243
245
|
# `timestamp`: The timestamp of this message
|
244
|
-
|
246
|
+
# While with `extended` it adds also all the key values present in the Kafka header if the key is valid UTF-8 else
|
247
|
+
# silently skip it.
|
248
|
+
config :decorate_events, :validate => %w(none basic extended false true), :default => "none"
|
249
|
+
|
250
|
+
attr_reader :metadata_mode
|
245
251
|
|
246
252
|
public
|
247
253
|
def register
|
248
254
|
@runner_threads = []
|
255
|
+
@metadata_mode = extract_metadata_level(@decorate_events)
|
249
256
|
check_schema_registry_parameters
|
250
257
|
end
|
251
258
|
|
259
|
+
METADATA_NONE = Set[].freeze
|
260
|
+
METADATA_BASIC = Set[:record_props].freeze
|
261
|
+
METADATA_EXTENDED = Set[:record_props, :headers].freeze
|
262
|
+
METADATA_DEPRECATION_MAP = { 'true' => 'basic', 'false' => 'none' }
|
263
|
+
|
264
|
+
private
|
265
|
+
def extract_metadata_level(decorate_events_setting)
|
266
|
+
metadata_enabled = decorate_events_setting
|
267
|
+
|
268
|
+
if METADATA_DEPRECATION_MAP.include?(metadata_enabled)
|
269
|
+
canonical_value = METADATA_DEPRECATION_MAP[metadata_enabled]
|
270
|
+
deprecation_logger.deprecated("Deprecated value `#{decorate_events_setting}` for `decorate_events` option; use `#{canonical_value}` instead.")
|
271
|
+
metadata_enabled = canonical_value
|
272
|
+
end
|
273
|
+
|
274
|
+
case metadata_enabled
|
275
|
+
when 'none' then METADATA_NONE
|
276
|
+
when 'basic' then METADATA_BASIC
|
277
|
+
when 'extended' then METADATA_EXTENDED
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
252
281
|
public
|
253
282
|
def run(logstash_queue)
|
254
283
|
@runner_consumers = consumer_threads.times.map { |i| create_consumer("#{client_id}-#{i}") }
|
@@ -292,7 +321,7 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
292
321
|
end
|
293
322
|
event.remove("message")
|
294
323
|
end
|
295
|
-
if @
|
324
|
+
if @metadata_mode.include?(:record_props)
|
296
325
|
event.set("[@metadata][kafka][topic]", record.topic)
|
297
326
|
event.set("[@metadata][kafka][consumer_group]", @group_id)
|
298
327
|
event.set("[@metadata][kafka][partition]", record.partition)
|
@@ -300,6 +329,15 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
|
|
300
329
|
event.set("[@metadata][kafka][key]", record.key)
|
301
330
|
event.set("[@metadata][kafka][timestamp]", record.timestamp)
|
302
331
|
end
|
332
|
+
if @metadata_mode.include?(:headers)
|
333
|
+
record.headers.each do |header|
|
334
|
+
s = String.from_java_bytes(header.value)
|
335
|
+
s.force_encoding(Encoding::UTF_8)
|
336
|
+
if s.valid_encoding?
|
337
|
+
event.set("[@metadata][kafka][headers]["+header.key+"]", s)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
303
341
|
logstash_queue << event
|
304
342
|
end
|
305
343
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-integration-kafka'
|
3
|
-
s.version = '10.7.
|
3
|
+
s.version = '10.7.3'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = "Integration with Kafka - input and output plugins"
|
6
6
|
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline "+
|
@@ -47,6 +47,7 @@ Gem::Specification.new do |s|
|
|
47
47
|
s.add_runtime_dependency 'logstash-codec-plain'
|
48
48
|
s.add_runtime_dependency 'stud', '>= 0.0.22', '< 0.1.0'
|
49
49
|
s.add_runtime_dependency "manticore", '>= 0.5.4', '< 1.0.0'
|
50
|
+
s.add_runtime_dependency 'logstash-mixin-deprecation_logger_support', '~>1.0'
|
50
51
|
|
51
52
|
s.add_development_dependency 'logstash-devutils'
|
52
53
|
s.add_development_dependency 'rspec-wait'
|
@@ -36,7 +36,15 @@ describe "inputs/kafka", :integration => true do
|
|
36
36
|
end
|
37
37
|
let(:decorate_config) do
|
38
38
|
{ 'topics' => ['logstash_integration_topic_plain'], 'codec' => 'plain', 'group_id' => group_id_3,
|
39
|
-
'auto_offset_reset' => 'earliest', 'decorate_events' => true }
|
39
|
+
'auto_offset_reset' => 'earliest', 'decorate_events' => 'true' }
|
40
|
+
end
|
41
|
+
let(:decorate_headers_config) do
|
42
|
+
{ 'topics' => ['logstash_integration_topic_plain_with_headers'], 'codec' => 'plain', 'group_id' => group_id_3,
|
43
|
+
'auto_offset_reset' => 'earliest', 'decorate_events' => 'extended' }
|
44
|
+
end
|
45
|
+
let(:decorate_bad_headers_config) do
|
46
|
+
{ 'topics' => ['logstash_integration_topic_plain_with_headers_badly'], 'codec' => 'plain', 'group_id' => group_id_3,
|
47
|
+
'auto_offset_reset' => 'earliest', 'decorate_events' => 'extended' }
|
40
48
|
end
|
41
49
|
let(:manual_commit_config) do
|
42
50
|
{ 'topics' => ['logstash_integration_topic_plain'], 'codec' => 'plain', 'group_id' => group_id_5,
|
@@ -45,6 +53,35 @@ describe "inputs/kafka", :integration => true do
|
|
45
53
|
let(:timeout_seconds) { 30 }
|
46
54
|
let(:num_events) { 103 }
|
47
55
|
|
56
|
+
before(:all) do
|
57
|
+
# Prepare message with headers with valid UTF-8 chars
|
58
|
+
header = org.apache.kafka.common.header.internals.RecordHeader.new("name", "John ανδρεα €".to_java_bytes)
|
59
|
+
record = org.apache.kafka.clients.producer.ProducerRecord.new(
|
60
|
+
"logstash_integration_topic_plain_with_headers", 0, "key", "value", [header])
|
61
|
+
send_message(record)
|
62
|
+
|
63
|
+
# Prepare message with headers with invalid UTF-8 chars
|
64
|
+
invalid = "日本".encode('Shift_JIS').force_encoding(Encoding::UTF_8).to_java_bytes
|
65
|
+
header = org.apache.kafka.common.header.internals.RecordHeader.new("name", invalid)
|
66
|
+
record = org.apache.kafka.clients.producer.ProducerRecord.new(
|
67
|
+
"logstash_integration_topic_plain_with_headers_badly", 0, "key", "value", [header])
|
68
|
+
|
69
|
+
send_message(record)
|
70
|
+
end
|
71
|
+
|
72
|
+
def send_message(record)
|
73
|
+
props = java.util.Properties.new
|
74
|
+
kafka = org.apache.kafka.clients.producer.ProducerConfig
|
75
|
+
props.put(kafka::BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
|
76
|
+
props.put(kafka::KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer")
|
77
|
+
props.put(kafka::VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer")
|
78
|
+
|
79
|
+
producer = org.apache.kafka.clients.producer.KafkaProducer.new(props)
|
80
|
+
|
81
|
+
producer.send(record)
|
82
|
+
producer.close
|
83
|
+
end
|
84
|
+
|
48
85
|
describe "#kafka-topics" do
|
49
86
|
|
50
87
|
it "should consume all messages from plain 3-partition topic" do
|
@@ -74,7 +111,7 @@ describe "inputs/kafka", :integration => true do
|
|
74
111
|
|
75
112
|
context "#kafka-topics-pattern" do
|
76
113
|
it "should consume all messages from all 3 topics" do
|
77
|
-
total_events = num_events * 3
|
114
|
+
total_events = num_events * 3 + 2
|
78
115
|
queue = consume_messages(pattern_config, timeout: timeout_seconds, event_count: total_events)
|
79
116
|
expect(queue.length).to eq(total_events)
|
80
117
|
end
|
@@ -91,6 +128,31 @@ describe "inputs/kafka", :integration => true do
|
|
91
128
|
expect(event.get("[@metadata][kafka][timestamp]")).to be >= start
|
92
129
|
end
|
93
130
|
end
|
131
|
+
|
132
|
+
it "should show the right topic and group name in and kafka headers decorated kafka section" do
|
133
|
+
start = LogStash::Timestamp.now.time.to_i
|
134
|
+
consume_messages(decorate_headers_config, timeout: timeout_seconds, event_count: 1) do |queue, _|
|
135
|
+
expect(queue.length).to eq(1)
|
136
|
+
event = queue.shift
|
137
|
+
expect(event.get("[@metadata][kafka][topic]")).to eq("logstash_integration_topic_plain_with_headers")
|
138
|
+
expect(event.get("[@metadata][kafka][consumer_group]")).to eq(group_id_3)
|
139
|
+
expect(event.get("[@metadata][kafka][timestamp]")).to be >= start
|
140
|
+
expect(event.get("[@metadata][kafka][headers][name]")).to eq("John ανδρεα €")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should skip headers not encoded in UTF-8" do
|
145
|
+
start = LogStash::Timestamp.now.time.to_i
|
146
|
+
consume_messages(decorate_bad_headers_config, timeout: timeout_seconds, event_count: 1) do |queue, _|
|
147
|
+
expect(queue.length).to eq(1)
|
148
|
+
event = queue.shift
|
149
|
+
expect(event.get("[@metadata][kafka][topic]")).to eq("logstash_integration_topic_plain_with_headers_badly")
|
150
|
+
expect(event.get("[@metadata][kafka][consumer_group]")).to eq(group_id_3)
|
151
|
+
expect(event.get("[@metadata][kafka][timestamp]")).to be >= start
|
152
|
+
|
153
|
+
expect(event.include?("[@metadata][kafka][headers][name]")).to eq(false)
|
154
|
+
end
|
155
|
+
end
|
94
156
|
end
|
95
157
|
|
96
158
|
context "#kafka-offset-commit" do
|
@@ -129,6 +191,7 @@ private
|
|
129
191
|
|
130
192
|
def consume_messages(config, queue: Queue.new, timeout:, event_count:)
|
131
193
|
kafka_input = LogStash::Inputs::Kafka.new(config)
|
194
|
+
kafka_input.register
|
132
195
|
t = Thread.new { kafka_input.run(queue) }
|
133
196
|
begin
|
134
197
|
t.run
|
@@ -38,18 +38,35 @@ describe LogStash::Inputs::Kafka do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
context "register parameter verification" do
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
context "schema_registry_url" do
|
42
|
+
let(:config) do
|
43
|
+
{ 'schema_registry_url' => 'http://localhost:8081', 'topics' => ['logstash'], 'consumer_threads' => 4 }
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
it "conflict with value_deserializer_class should fail" do
|
47
|
+
config['value_deserializer_class'] = 'my.fantasy.Deserializer'
|
48
|
+
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Option schema_registry_url prohibit the customization of value_deserializer_class/
|
49
|
+
end
|
50
|
+
|
51
|
+
it "conflict with topics_pattern should fail" do
|
52
|
+
config['topics_pattern'] = 'topic_.*'
|
53
|
+
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Option schema_registry_url prohibit the customization of topics_pattern/
|
54
|
+
end
|
48
55
|
end
|
49
56
|
|
50
|
-
|
51
|
-
config
|
52
|
-
|
57
|
+
context "decorate_events" do
|
58
|
+
let(:config) { { 'decorate_events' => 'extended'} }
|
59
|
+
|
60
|
+
it "should raise error for invalid value" do
|
61
|
+
config['decorate_events'] = 'avoid'
|
62
|
+
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Something is wrong with your configuration./
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should map old true boolean value to :record_props mode" do
|
66
|
+
config['decorate_events'] = "true"
|
67
|
+
subject.register
|
68
|
+
expect(subject.metadata_mode).to include(:record_props)
|
69
|
+
end
|
53
70
|
end
|
54
71
|
end
|
55
72
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-integration-kafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.7.
|
4
|
+
version: 10.7.3
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,6 +126,20 @@ dependencies:
|
|
126
126
|
- - "<"
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: 1.0.0
|
129
|
+
- !ruby/object:Gem::Dependency
|
130
|
+
requirement: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - "~>"
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '1.0'
|
135
|
+
name: logstash-mixin-deprecation_logger_support
|
136
|
+
prerelease: false
|
137
|
+
type: :runtime
|
138
|
+
version_requirements: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - "~>"
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '1.0'
|
129
143
|
- !ruby/object:Gem::Dependency
|
130
144
|
requirement: !ruby/object:Gem::Requirement
|
131
145
|
requirements:
|