logstash-integration-kafka 10.8.2-java → 10.11.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e11499f791fd2bd71102ddb6f8e52fcbd9791feecf4107c7ebd27dc9334cc34
4
- data.tar.gz: 779cd381a6e53155f61457229df4fc827ceda02ef4e069d4eab0240dafa4ab83
3
+ metadata.gz: 2833139d65282055a4e924ccfb50b19341a61af69e0834ef318a62f1459f3a16
4
+ data.tar.gz: fbfd7e6b94e9a74109b44b838df344ed4d7447d56d624f24e642235eb62b00e3
5
5
  SHA512:
6
- metadata.gz: 5577048fe1adee0c28b012c0bf6eb0ff594b7be4760f7b7ebdf9072473fb0a1806e24997dd7b0659c21f205396a4d7eccb10bc4e789541c35fb7e32610562632
7
- data.tar.gz: 7ee0e7428d63957a57e927a3f0408bcdddf94efad944c5cf0acbac3c1031be55b6751ad0290ea134e5201f10f9e26f2804c6d68150e925f651c9db27847bab5e
6
+ metadata.gz: b35d99bf553fbfd3b78f3f7de62b427b18001853573c5160090bebba5dfb78f4d17aa9f879a94a98805f949b1ed76a3fa82e9c1a7b95815f223a5d04104f5bce
7
+ data.tar.gz: 0e8edf4f07b00443c39ac55523fb5663395ba0ae524dfedc5181a56b5160c2c33fe110e24bccbb060b43c6be0aa2211b50422d041fa1dea59561a26efc79d687
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 10.11.0
2
+ - Feat: added connections_max_idle_ms setting for output [#118](https://github.com/logstash-plugins/logstash-integration-kafka/pull/118)
3
+ - Refactor: mixins to follow shared mixin module naming
4
+
5
+ ## 10.10.1
6
+ - Update CHANGELOG.md [#114](https://api.github.com/repos/logstash-plugins/logstash-integration-kafka/pulls/114)
7
+
8
+ ## 10.10.0
9
+ - Added config setting to enable 'zstd' compression in the Kafka output [#112](https://github.com/logstash-plugins/logstash-integration-kafka/pull/112)
10
+
11
+ ## 10.9.0
12
+ - Refactor: leverage codec when using schema registry [#106](https://github.com/logstash-plugins/logstash-integration-kafka/pull/106)
13
+ Previously using `schema_registry_url` parsed the payload as JSON even if `codec => 'plain'` was set, this is no longer the case.
14
+
1
15
  ## 10.8.2
2
16
  - [DOC] Updates description of `enable_auto_commit=false` to clarify that the commit happens after data is fetched AND written to the queue [#90](https://github.com/logstash-plugins/logstash-integration-kafka/pull/90)
3
17
  - Fix: update to Gradle 7 [#104](https://github.com/logstash-plugins/logstash-integration-kafka/pull/104)
@@ -82,7 +96,6 @@
82
96
  - Fix links in changelog pointing to stand-alone plugin changelogs.
83
97
  - Refactor: scope java_import to plugin class
84
98
 
85
-
86
99
  ## 10.0.0
87
100
  - Initial release of the Kafka Integration Plugin, which combines
88
101
  previously-separate Kafka plugins and shared dependencies into a single
data/DEVELOPER.md CHANGED
@@ -62,7 +62,7 @@ See http://kafka.apache.org/documentation.html#producerconfigs for details about
62
62
  kafka {
63
63
  topic_id => ... # string (required), The topic to produce the messages to
64
64
  broker_list => ... # string (optional), default: "localhost:9092", This is for bootstrapping and the producer will only use it for getting metadata
65
- compression_codec => ... # string (optional), one of ["none", "gzip", "snappy"], default: "none"
65
+ compression_codec => ... # string (optional), one of ["none", "gzip", "snappy", "lz4", "zstd"], default: "none"
66
66
  compressed_topics => ... # string (optional), default: "", This parameter allows you to set whether compression should be turned on for particular
67
67
  request_required_acks => ... # number (optional), one of [-1, 0, 1], default: 0, This value controls when a produce request is considered completed
68
68
  serializer_class => ... # string, (optional) default: "kafka.serializer.StringEncoder", The serializer class for messages. The default encoder takes a byte[] and returns the same byte[]
@@ -84,7 +84,8 @@ See the https://kafka.apache.org/{kafka_client_doc}/documentation for more detai
84
84
  | <<plugins-{type}s-{plugin}-buffer_memory>> |<<number,number>>|No
85
85
  | <<plugins-{type}s-{plugin}-client_dns_lookup>> |<<string,string>>|No
86
86
  | <<plugins-{type}s-{plugin}-client_id>> |<<string,string>>|No
87
- | <<plugins-{type}s-{plugin}-compression_type>> |<<string,string>>, one of `["none", "gzip", "snappy", "lz4"]`|No
87
+ | <<plugins-{type}s-{plugin}-compression_type>> |<<string,string>>, one of `["none", "gzip", "snappy", "lz4", "zstd"]`|No
88
+ | <<plugins-{type}s-{plugin}-connections_max_idle_ms>> |<<number,number>>|No
88
89
  | <<plugins-{type}s-{plugin}-jaas_path>> |a valid filesystem path|No
89
90
  | <<plugins-{type}s-{plugin}-kerberos_config>> |a valid filesystem path|No
90
91
  | <<plugins-{type}s-{plugin}-key_serializer>> |<<string,string>>|No
@@ -193,11 +194,19 @@ ip/port by allowing a logical application name to be included with the request
193
194
  [id="plugins-{type}s-{plugin}-compression_type"]
194
195
  ===== `compression_type`
195
196
 
196
- * Value can be any of: `none`, `gzip`, `snappy`, `lz4`
197
+ * Value can be any of: `none`, `gzip`, `snappy`, `lz4`, `zstd`
197
198
  * Default value is `"none"`
198
199
 
199
200
  The compression type for all data generated by the producer.
200
- The default is none (i.e. no compression). Valid values are none, gzip, snappy, or lz4.
201
+ The default is none (meaning no compression). Valid values are none, gzip, snappy, lz4, or zstd.
202
+
203
+ [id="plugins-{type}s-{plugin}-connections_max_idle_ms"]
204
+ ===== `connections_max_idle_ms`
205
+
206
+ * Value type is <<number,number>>
207
+ * Default value is `540000` milliseconds (9 minutes).
208
+
209
+ Close idle connections after the number of milliseconds specified by this config.
201
210
 
202
211
  [id="plugins-{type}s-{plugin}-jaas_path"]
203
212
  ===== `jaas_path`
@@ -2,12 +2,11 @@ require 'logstash/namespace'
2
2
  require 'logstash/inputs/base'
3
3
  require 'stud/interval'
4
4
  require 'java'
5
- require 'logstash-integration-kafka_jars.rb'
6
- require 'logstash/plugin_mixins/kafka_support'
7
- require 'manticore'
8
5
  require "json"
9
6
  require "logstash/json"
10
- require_relative '../plugin_mixins/common'
7
+ require 'logstash-integration-kafka_jars.rb'
8
+ require 'logstash/plugin_mixins/kafka/common'
9
+ require 'logstash/plugin_mixins/kafka/avro_schema_registry'
11
10
  require 'logstash/plugin_mixins/deprecation_logger_support'
12
11
 
13
12
  # This input will read events from a Kafka topic. It uses the 0.10 version of
@@ -57,13 +56,18 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
57
56
 
58
57
  DEFAULT_DESERIALIZER_CLASS = "org.apache.kafka.common.serialization.StringDeserializer"
59
58
 
60
- include LogStash::PluginMixins::KafkaSupport
61
- include ::LogStash::PluginMixins::KafkaAvroSchemaRegistry
59
+ include LogStash::PluginMixins::Kafka::Common
60
+ include LogStash::PluginMixins::Kafka::AvroSchemaRegistry
62
61
  include LogStash::PluginMixins::DeprecationLoggerSupport
63
62
 
64
63
  config_name 'kafka'
65
64
 
66
- default :codec, 'plain'
65
+ # default :codec, 'plain' or 'json' depending whether schema registry is used
66
+ #
67
+ # @override LogStash::Inputs::Base - removing the `:default => :plain`
68
+ config :codec, :validate => :codec
69
+ # NOTE: isn't necessary due the params['codec'] = ... done in #initialize
70
+ # having the `nil` default explicit makes the behavior more noticeable.
67
71
 
68
72
  # The frequency in milliseconds that the consumer offsets are committed to Kafka.
69
73
  config :auto_commit_interval_ms, :validate => :number, :default => 5000 # Kafka default
@@ -93,8 +97,6 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
93
97
  # is to be able to track the source of requests beyond just ip/port by allowing
94
98
  # a logical application name to be included.
95
99
  config :client_id, :validate => :string, :default => "logstash"
96
- # Close idle connections after the number of milliseconds specified by this config.
97
- config :connections_max_idle_ms, :validate => :number, :default => 540_000 # (9m) Kafka default
98
100
  # Ideally you should have as many threads as the number of partitions for a perfect
99
101
  # balance — more threads than partitions means that some threads will be idle
100
102
  config :consumer_threads, :validate => :number, :default => 1
@@ -147,9 +149,6 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
147
149
  config :max_partition_fetch_bytes, :validate => :number, :default => 1_048_576 # (1MB) Kafka default
148
150
  # The maximum number of records returned in a single call to poll().
149
151
  config :max_poll_records, :validate => :number, :default => 500 # Kafka default
150
- # The period of time in milliseconds after which we force a refresh of metadata even if
151
- # we haven't seen any partition leadership changes to proactively discover any new brokers or partitions
152
- config :metadata_max_age_ms, :validate => :number, :default => 300_000 # (5m) Kafka default
153
152
  # The name of the partition assignment strategy that the client uses to distribute
154
153
  # partition ownership amongst consumer instances, supported options are `range`,
155
154
  # `round_robin`, `sticky` and `cooperative_sticky`
@@ -162,10 +161,6 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
162
161
  # This avoids repeatedly connecting to a host in a tight loop.
163
162
  # This backoff applies to all connection attempts by the client to a broker.
164
163
  config :reconnect_backoff_ms, :validate => :number, :default => 50 # Kafka default
165
- # The configuration controls the maximum amount of time the client will wait for the response of a request.
166
- # If the response is not received before the timeout elapses the client will resend the request if necessary
167
- # or fail the request if retries are exhausted.
168
- config :request_timeout_ms, :validate => :number, :default => 40_000 # Kafka default
169
164
  # The amount of time to wait before attempting to retry a failed fetch request
170
165
  # to a given topic partition. This avoids repeated fetching-and-failing in a tight loop.
171
166
  config :retry_backoff_ms, :validate => :number, :default => 100 # Kafka default
@@ -249,6 +244,15 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
249
244
 
250
245
  attr_reader :metadata_mode
251
246
 
247
+ # @overload based on schema registry change the codec default
248
+ def initialize(params = {})
249
+ unless params.key?('codec')
250
+ params['codec'] = params.key?('schema_registry_url') ? 'json' : 'plain'
251
+ end
252
+
253
+ super(params)
254
+ end
255
+
252
256
  public
253
257
  def register
254
258
  @runner_threads = []
@@ -341,22 +345,11 @@ class LogStash::Inputs::Kafka < LogStash::Inputs::Base
341
345
  def handle_record(record, codec_instance, queue)
342
346
  codec_instance.decode(record.value.to_s) do |event|
343
347
  decorate(event)
344
- maybe_apply_schema(event, record)
345
348
  maybe_set_metadata(event, record)
346
349
  queue << event
347
350
  end
348
351
  end
349
352
 
350
- def maybe_apply_schema(event, record)
351
- if schema_registry_url
352
- json = LogStash::Json.load(record.value.to_s)
353
- json.each do |k, v|
354
- event.set(k, v)
355
- end
356
- event.remove("message")
357
- end
358
- end
359
-
360
353
  def maybe_set_metadata(event, record)
361
354
  if @metadata_mode.include?(:record_props)
362
355
  event.set("[@metadata][kafka][topic]", record.topic)
@@ -2,7 +2,7 @@ require 'logstash/namespace'
2
2
  require 'logstash/outputs/base'
3
3
  require 'java'
4
4
  require 'logstash-integration-kafka_jars.rb'
5
- require 'logstash/plugin_mixins/kafka_support'
5
+ require 'logstash/plugin_mixins/kafka/common'
6
6
 
7
7
  # Write events to a Kafka topic. This uses the Kafka Producer API to write messages to a topic on
8
8
  # the broker.
@@ -51,7 +51,7 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
51
51
 
52
52
  java_import org.apache.kafka.clients.producer.ProducerRecord
53
53
 
54
- include LogStash::PluginMixins::KafkaSupport
54
+ include LogStash::PluginMixins::Kafka::Common
55
55
 
56
56
  declare_threadsafe!
57
57
 
@@ -80,8 +80,8 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
80
80
  # The total bytes of memory the producer can use to buffer records waiting to be sent to the server.
81
81
  config :buffer_memory, :validate => :number, :default => 33_554_432 # (32M) Kafka default
82
82
  # The compression type for all data generated by the producer.
83
- # The default is none (i.e. no compression). Valid values are none, gzip, or snappy.
84
- config :compression_type, :validate => ["none", "gzip", "snappy", "lz4"], :default => "none"
83
+ # The default is none (i.e. no compression). Valid values are none, gzip, snappy, lz4 or zstd.
84
+ config :compression_type, :validate => ["none", "gzip", "snappy", "lz4", "zstd"], :default => "none"
85
85
  # How DNS lookups should be done. If set to `use_all_dns_ips`, when the lookup returns multiple
86
86
  # IP addresses for a hostname, they will all be attempted to connect to before failing the
87
87
  # connection. If the value is `resolve_canonical_bootstrap_servers_only` each entry will be
@@ -107,19 +107,12 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
107
107
  config :message_key, :validate => :string
108
108
  # the timeout setting for initial metadata request to fetch topic metadata.
109
109
  config :metadata_fetch_timeout_ms, :validate => :number, :default => 60_000
110
- # the max time in milliseconds before a metadata refresh is forced.
111
- config :metadata_max_age_ms, :validate => :number, :default => 300_000 # (5m) Kafka default
112
110
  # Partitioner to use - can be `default`, `uniform_sticky`, `round_robin` or a fully qualified class name of a custom partitioner.
113
111
  config :partitioner, :validate => :string
114
112
  # The size of the TCP receive buffer to use when reading data
115
113
  config :receive_buffer_bytes, :validate => :number, :default => 32_768 # (32KB) Kafka default
116
114
  # The amount of time to wait before attempting to reconnect to a given host when a connection fails.
117
115
  config :reconnect_backoff_ms, :validate => :number, :default => 50 # Kafka default
118
- # The configuration controls the maximum amount of time the client will wait
119
- # for the response of a request. If the response is not received before the timeout
120
- # elapses the client will resend the request if necessary or fail the request if
121
- # retries are exhausted.
122
- config :request_timeout_ms, :validate => :number, :default => 40_000 # (40s) Kafka default
123
116
  # The default retry behavior is to retry until successful. To prevent data loss,
124
117
  # the use of this setting is discouraged.
125
118
  #
@@ -0,0 +1,108 @@
1
+ require 'manticore'
2
+
3
+ module LogStash module PluginMixins module Kafka
4
+ module AvroSchemaRegistry
5
+
6
+ def self.included(base)
7
+ base.extend(self)
8
+ base.setup_schema_registry_config
9
+ end
10
+
11
+ def setup_schema_registry_config
12
+ # Option to set key to access Schema Registry.
13
+ config :schema_registry_key, :validate => :string
14
+
15
+ # Option to set secret to access Schema Registry.
16
+ config :schema_registry_secret, :validate => :password
17
+
18
+ # Option to set the endpoint of the Schema Registry.
19
+ # This option permit the usage of Avro Kafka deserializer which retrieve the schema of the Avro message from an
20
+ # instance of schema registry. If this option has value `value_deserializer_class` nor `topics_pattern` could be valued
21
+ config :schema_registry_url, :validate => :uri
22
+
23
+ # Option to set the proxy of the Schema Registry.
24
+ # This option permits to define a proxy to be used to reach the schema registry service instance.
25
+ config :schema_registry_proxy, :validate => :uri
26
+
27
+ # Option to skip validating the schema registry during registration. This can be useful when using
28
+ # certificate based auth
29
+ config :schema_registry_validation, :validate => ['auto', 'skip'], :default => 'auto'
30
+ end
31
+
32
+ def check_schema_registry_parameters
33
+ if @schema_registry_url
34
+ check_for_schema_registry_conflicts
35
+ @schema_registry_proxy_host, @schema_registry_proxy_port = split_proxy_into_host_and_port(schema_registry_proxy)
36
+ check_for_key_and_secret
37
+ check_for_schema_registry_connectivity_and_subjects if schema_registry_validation?
38
+ end
39
+ end
40
+
41
+ def schema_registry_validation?
42
+ return false if schema_registry_validation.to_s == 'skip'
43
+ return false if using_kerberos? # pre-validation doesn't support kerberos
44
+
45
+ true
46
+ end
47
+
48
+ def using_kerberos?
49
+ security_protocol == "SASL_PLAINTEXT" || security_protocol == "SASL_SSL"
50
+ end
51
+
52
+ private
53
+ def check_for_schema_registry_conflicts
54
+ if @value_deserializer_class != LogStash::Inputs::Kafka::DEFAULT_DESERIALIZER_CLASS
55
+ raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of value_deserializer_class'
56
+ end
57
+ if @topics_pattern && !@topics_pattern.empty?
58
+ raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of topics_pattern'
59
+ end
60
+ end
61
+
62
+ private
63
+ def check_for_schema_registry_connectivity_and_subjects
64
+ options = {}
65
+ if schema_registry_proxy && !schema_registry_proxy.empty?
66
+ options[:proxy] = schema_registry_proxy.to_s
67
+ end
68
+ if schema_registry_key and !schema_registry_key.empty?
69
+ options[:auth] = {:user => schema_registry_key, :password => schema_registry_secret.value}
70
+ end
71
+ client = Manticore::Client.new(options)
72
+ begin
73
+ response = client.get(@schema_registry_url.uri.to_s + '/subjects').body
74
+ rescue Manticore::ManticoreException => e
75
+ raise LogStash::ConfigurationError.new("Schema registry service doesn't respond, error: #{e.message}")
76
+ end
77
+ registered_subjects = JSON.parse response
78
+ expected_subjects = @topics.map { |t| "#{t}-value"}
79
+ if (expected_subjects & registered_subjects).size != expected_subjects.size
80
+ undefined_topic_subjects = expected_subjects - registered_subjects
81
+ raise LogStash::ConfigurationError, "The schema registry does not contain definitions for required topic subjects: #{undefined_topic_subjects}"
82
+ end
83
+ end
84
+
85
+ def split_proxy_into_host_and_port(proxy_uri)
86
+ return nil unless proxy_uri && !proxy_uri.empty?
87
+
88
+ port = proxy_uri.port
89
+
90
+ host_spec = ""
91
+ host_spec << proxy_uri.scheme || "http"
92
+ host_spec << "://"
93
+ host_spec << "#{proxy_uri.userinfo}@" if proxy_uri.userinfo
94
+ host_spec << proxy_uri.host
95
+
96
+ [host_spec, port]
97
+ end
98
+
99
+ def check_for_key_and_secret
100
+ if schema_registry_key and !schema_registry_key.empty?
101
+ if !schema_registry_secret or schema_registry_secret.value.empty?
102
+ raise LogStash::ConfigurationError, "Setting `schema_registry_secret` is required when `schema_registry_key` is provided."
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end end end
@@ -0,0 +1,47 @@
1
+ module LogStash module PluginMixins module Kafka
2
+ module Common
3
+
4
+ def self.included(base)
5
+ # COMMON CONFIGURATION SUPPORTED BY BOTH PRODUCER/CONSUMER
6
+
7
+ # Close idle connections after the number of milliseconds specified by this config.
8
+ base.config :connections_max_idle_ms, :validate => :number, :default => 540_000 # (9m) Kafka default
9
+
10
+ # The period of time in milliseconds after which we force a refresh of metadata even if
11
+ # we haven't seen any partition leadership changes to proactively discover any new brokers or partitions
12
+ base.config :metadata_max_age_ms, :validate => :number, :default => 300_000 # (5m) Kafka default
13
+
14
+ # The configuration controls the maximum amount of time the client will wait for the response of a request.
15
+ # If the response is not received before the timeout elapses the client will resend the request if necessary
16
+ # or fail the request if retries are exhausted.
17
+ base.config :request_timeout_ms, :validate => :number, :default => 40_000 # Kafka default
18
+ end
19
+
20
+ def set_trustore_keystore_config(props)
21
+ props.put("ssl.truststore.type", ssl_truststore_type) unless ssl_truststore_type.nil?
22
+ props.put("ssl.truststore.location", ssl_truststore_location) unless ssl_truststore_location.nil?
23
+ props.put("ssl.truststore.password", ssl_truststore_password.value) unless ssl_truststore_password.nil?
24
+
25
+ # Client auth stuff
26
+ props.put("ssl.keystore.type", ssl_keystore_type) unless ssl_keystore_type.nil?
27
+ props.put("ssl.key.password", ssl_key_password.value) unless ssl_key_password.nil?
28
+ props.put("ssl.keystore.location", ssl_keystore_location) unless ssl_keystore_location.nil?
29
+ props.put("ssl.keystore.password", ssl_keystore_password.value) unless ssl_keystore_password.nil?
30
+ props.put("ssl.endpoint.identification.algorithm", ssl_endpoint_identification_algorithm) unless ssl_endpoint_identification_algorithm.nil?
31
+ end
32
+
33
+ def set_sasl_config(props)
34
+ java.lang.System.setProperty("java.security.auth.login.config", jaas_path) unless jaas_path.nil?
35
+ java.lang.System.setProperty("java.security.krb5.conf", kerberos_config) unless kerberos_config.nil?
36
+
37
+ props.put("sasl.mechanism", sasl_mechanism)
38
+ if sasl_mechanism == "GSSAPI" && sasl_kerberos_service_name.nil?
39
+ raise LogStash::ConfigurationError, "sasl_kerberos_service_name must be specified when SASL mechanism is GSSAPI"
40
+ end
41
+
42
+ props.put("sasl.kerberos.service.name", sasl_kerberos_service_name) unless sasl_kerberos_service_name.nil?
43
+ props.put("sasl.jaas.config", sasl_jaas_config) unless sasl_jaas_config.nil?
44
+ end
45
+
46
+ end
47
+ end end end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-integration-kafka'
3
- s.version = '10.8.2'
3
+ s.version = '10.11.0'
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 "+
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  s.add_runtime_dependency 'logstash-mixin-deprecation_logger_support', '~>1.0'
51
51
 
52
52
  s.add_development_dependency 'logstash-devutils'
53
+ s.add_development_dependency 'logstash-codec-line'
53
54
  s.add_development_dependency 'rspec-wait'
54
55
  s.add_development_dependency 'digest-crc', '~> 0.5.1' # 0.6.0 started using a C-ext
55
56
  s.add_development_dependency 'ruby-kafka' # depends on digest-crc
@@ -16,38 +16,38 @@ describe "inputs/kafka", :integration => true do
16
16
  let(:group_id_5) {rand(36**8).to_s(36)}
17
17
  let(:group_id_6) {rand(36**8).to_s(36)}
18
18
  let(:plain_config) do
19
- { 'topics' => ['logstash_integration_topic_plain'], 'codec' => 'plain', 'group_id' => group_id_1,
19
+ { 'topics' => ['logstash_integration_topic_plain'], 'group_id' => group_id_1,
20
20
  'auto_offset_reset' => 'earliest' }
21
21
  end
22
22
  let(:multi_consumer_config) do
23
23
  plain_config.merge({"group_id" => group_id_4, "client_id" => "spec", "consumer_threads" => 3})
24
24
  end
25
25
  let(:snappy_config) do
26
- { 'topics' => ['logstash_integration_topic_snappy'], 'codec' => 'plain', 'group_id' => group_id_1,
26
+ { 'topics' => ['logstash_integration_topic_snappy'], 'group_id' => group_id_1,
27
27
  'auto_offset_reset' => 'earliest' }
28
28
  end
29
29
  let(:lz4_config) do
30
- { 'topics' => ['logstash_integration_topic_lz4'], 'codec' => 'plain', 'group_id' => group_id_1,
30
+ { 'topics' => ['logstash_integration_topic_lz4'], 'group_id' => group_id_1,
31
31
  'auto_offset_reset' => 'earliest' }
32
32
  end
33
33
  let(:pattern_config) do
34
- { 'topics_pattern' => 'logstash_integration_topic_.*', 'group_id' => group_id_2, 'codec' => 'plain',
34
+ { 'topics_pattern' => 'logstash_integration_topic_.*', 'group_id' => group_id_2,
35
35
  'auto_offset_reset' => 'earliest' }
36
36
  end
37
37
  let(:decorate_config) do
38
- { 'topics' => ['logstash_integration_topic_plain'], 'codec' => 'plain', 'group_id' => group_id_3,
38
+ { 'topics' => ['logstash_integration_topic_plain'], 'group_id' => group_id_3,
39
39
  'auto_offset_reset' => 'earliest', 'decorate_events' => 'true' }
40
40
  end
41
41
  let(:decorate_headers_config) do
42
- { 'topics' => ['logstash_integration_topic_plain_with_headers'], 'codec' => 'plain', 'group_id' => group_id_3,
42
+ { 'topics' => ['logstash_integration_topic_plain_with_headers'], 'group_id' => group_id_3,
43
43
  'auto_offset_reset' => 'earliest', 'decorate_events' => 'extended' }
44
44
  end
45
45
  let(:decorate_bad_headers_config) do
46
- { 'topics' => ['logstash_integration_topic_plain_with_headers_badly'], 'codec' => 'plain', 'group_id' => group_id_3,
46
+ { 'topics' => ['logstash_integration_topic_plain_with_headers_badly'], 'group_id' => group_id_3,
47
47
  'auto_offset_reset' => 'earliest', 'decorate_events' => 'extended' }
48
48
  end
49
49
  let(:manual_commit_config) do
50
- { 'topics' => ['logstash_integration_topic_plain'], 'codec' => 'plain', 'group_id' => group_id_5,
50
+ { 'topics' => ['logstash_integration_topic_plain'], 'group_id' => group_id_5,
51
51
  'auto_offset_reset' => 'earliest', 'enable_auto_commit' => 'false' }
52
52
  end
53
53
  let(:timeout_seconds) { 30 }
@@ -352,10 +352,7 @@ describe "Deserializing with the schema registry", :integration => true do
352
352
 
353
353
  let(:base_config) do
354
354
  {
355
- 'topics' => [avro_topic_name],
356
- 'codec' => 'plain',
357
- 'group_id' => group_id_1,
358
- 'auto_offset_reset' => 'earliest'
355
+ 'topics' => [avro_topic_name], 'group_id' => group_id_1, 'auto_offset_reset' => 'earliest'
359
356
  }
360
357
  end
361
358
 
@@ -28,7 +28,8 @@ describe "outputs/kafka", :integration => true do
28
28
  let(:num_events) { 3 }
29
29
 
30
30
  before :each do
31
- config = base_config.merge({"topic_id" => test_topic})
31
+ # NOTE: the connections_max_idle_ms is irrelevant just testing that configuration works ...
32
+ config = base_config.merge({"topic_id" => test_topic, "connections_max_idle_ms" => 540_000})
32
33
  load_kafka_data(config)
33
34
  end
34
35
 
@@ -139,6 +140,25 @@ describe "outputs/kafka", :integration => true do
139
140
  # end
140
141
  end
141
142
 
143
+ context 'when using zstd compression' do
144
+ let(:test_topic) { 'logstash_integration_zstd_topic' }
145
+
146
+ before :each do
147
+ config = base_config.merge({"topic_id" => test_topic, "compression_type" => "zstd"})
148
+ load_kafka_data(config)
149
+ end
150
+
151
+ # NOTE: depends on zstd-ruby gem which is using a C-extension
152
+ # it 'should have data integrity' do
153
+ # messages = fetch_messages(test_topic)
154
+ #
155
+ # expect(messages.size).to eq(num_events)
156
+ # messages.each do |m|
157
+ # expect(m.value).to eq(event.to_s)
158
+ # end
159
+ # end
160
+ end
161
+
142
162
  context 'when using multi partition topic' do
143
163
  let(:num_events) { 100 } # ~ more than (batch.size) 16,384 bytes
144
164
  let(:test_topic) { 'logstash_integration_topic3' }
@@ -177,7 +177,23 @@ describe LogStash::Inputs::Kafka do
177
177
  end
178
178
  end
179
179
 
180
- describe "schema registry parameter verification" do
180
+ it 'uses plain codec by default' do
181
+ expect( subject.codec ).to respond_to :decode
182
+ expect( subject.codec.class ).to be LogStash::Codecs::Plain
183
+ end
184
+
185
+ context 'with codec option' do
186
+
187
+ let(:config) { super().merge 'codec' => 'line' }
188
+
189
+ it 'uses specified codec' do
190
+ expect( subject.codec ).to respond_to :decode
191
+ expect( subject.codec.class ).to be LogStash::Codecs::Line
192
+ end
193
+
194
+ end
195
+
196
+ describe "schema registry" do
181
197
  let(:base_config) do {
182
198
  'schema_registry_url' => 'http://localhost:8081',
183
199
  'topics' => ['logstash'],
@@ -186,7 +202,7 @@ describe LogStash::Inputs::Kafka do
186
202
  end
187
203
 
188
204
  context "schema_registry_url" do
189
- let(:config) { base_config }
205
+ let(:config) { base_config }
190
206
 
191
207
  it "conflict with value_deserializer_class should fail" do
192
208
  config['value_deserializer_class'] = 'my.fantasy.Deserializer'
@@ -197,6 +213,11 @@ describe LogStash::Inputs::Kafka do
197
213
  config['topics_pattern'] = 'topic_.*'
198
214
  expect { subject.register }.to raise_error LogStash::ConfigurationError, /Option schema_registry_url prohibit the customization of topics_pattern/
199
215
  end
216
+
217
+ it 'switches default codec to json' do
218
+ expect( subject.codec ).to respond_to :decode
219
+ expect( subject.codec.class ).to be LogStash::Codecs::JSON
220
+ end
200
221
  end
201
222
 
202
223
  context 'when kerberos auth is used' do
@@ -204,9 +225,8 @@ describe LogStash::Inputs::Kafka do
204
225
  context "with #{protocol}" do
205
226
  ['auto', 'skip'].each do |vsr|
206
227
  context "when validata_schema_registry is #{vsr}" do
207
- let(:config) { base_config.merge({'security_protocol' => protocol,
208
- 'schema_registry_validation' => vsr})
209
- }
228
+ let(:config) { base_config.merge({'security_protocol' => protocol, 'schema_registry_validation' => vsr}) }
229
+
210
230
  it 'skips verification' do
211
231
  expect(subject).not_to receive(:check_for_schema_registry_connectivity_and_subjects)
212
232
  expect { subject.register }.not_to raise_error
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.8.2
4
+ version: 10.11.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-04 00:00:00.000000000 Z
11
+ date: 2022-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -154,6 +154,20 @@ dependencies:
154
154
  - - ">="
155
155
  - !ruby/object:Gem::Version
156
156
  version: '0'
157
+ - !ruby/object:Gem::Dependency
158
+ requirement: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ name: logstash-codec-line
164
+ prerelease: false
165
+ type: :development
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
157
171
  - !ruby/object:Gem::Dependency
158
172
  requirement: !ruby/object:Gem::Requirement
159
173
  requirements:
@@ -231,8 +245,8 @@ files:
231
245
  - lib/logstash-integration-kafka_jars.rb
232
246
  - lib/logstash/inputs/kafka.rb
233
247
  - lib/logstash/outputs/kafka.rb
234
- - lib/logstash/plugin_mixins/common.rb
235
- - lib/logstash/plugin_mixins/kafka_support.rb
248
+ - lib/logstash/plugin_mixins/kafka/avro_schema_registry.rb
249
+ - lib/logstash/plugin_mixins/kafka/common.rb
236
250
  - logstash-integration-kafka.gemspec
237
251
  - spec/check_docs_spec.rb
238
252
  - spec/fixtures/jaas.config
@@ -1,107 +0,0 @@
1
- module LogStash
2
- module PluginMixins
3
- module KafkaAvroSchemaRegistry
4
-
5
- def self.included(base)
6
- base.extend(self)
7
- base.setup_schema_registry_config
8
- end
9
-
10
- def setup_schema_registry_config
11
- # Option to set key to access Schema Registry.
12
- config :schema_registry_key, :validate => :string
13
-
14
- # Option to set secret to access Schema Registry.
15
- config :schema_registry_secret, :validate => :password
16
-
17
- # Option to set the endpoint of the Schema Registry.
18
- # This option permit the usage of Avro Kafka deserializer which retrieve the schema of the Avro message from an
19
- # instance of schema registry. If this option has value `value_deserializer_class` nor `topics_pattern` could be valued
20
- config :schema_registry_url, :validate => :uri
21
-
22
- # Option to set the proxy of the Schema Registry.
23
- # This option permits to define a proxy to be used to reach the schema registry service instance.
24
- config :schema_registry_proxy, :validate => :uri
25
-
26
- # Option to skip validating the schema registry during registration. This can be useful when using
27
- # certificate based auth
28
- config :schema_registry_validation, :validate => ['auto', 'skip'], :default => 'auto'
29
- end
30
-
31
- def check_schema_registry_parameters
32
- if @schema_registry_url
33
- check_for_schema_registry_conflicts
34
- @schema_registry_proxy_host, @schema_registry_proxy_port = split_proxy_into_host_and_port(schema_registry_proxy)
35
- check_for_key_and_secret
36
- check_for_schema_registry_connectivity_and_subjects if schema_registry_validation?
37
- end
38
- end
39
-
40
- def schema_registry_validation?
41
- return false if schema_registry_validation.to_s == 'skip'
42
- return false if using_kerberos? # pre-validation doesn't support kerberos
43
-
44
- true
45
- end
46
-
47
- def using_kerberos?
48
- security_protocol == "SASL_PLAINTEXT" || security_protocol == "SASL_SSL"
49
- end
50
-
51
- private
52
- def check_for_schema_registry_conflicts
53
- if @value_deserializer_class != LogStash::Inputs::Kafka::DEFAULT_DESERIALIZER_CLASS
54
- raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of value_deserializer_class'
55
- end
56
- if @topics_pattern && !@topics_pattern.empty?
57
- raise LogStash::ConfigurationError, 'Option schema_registry_url prohibit the customization of topics_pattern'
58
- end
59
- end
60
-
61
- private
62
- def check_for_schema_registry_connectivity_and_subjects
63
- options = {}
64
- if schema_registry_proxy && !schema_registry_proxy.empty?
65
- options[:proxy] = schema_registry_proxy.to_s
66
- end
67
- if schema_registry_key and !schema_registry_key.empty?
68
- options[:auth] = {:user => schema_registry_key, :password => schema_registry_secret.value}
69
- end
70
- client = Manticore::Client.new(options)
71
- begin
72
- response = client.get(@schema_registry_url.uri.to_s + '/subjects').body
73
- rescue Manticore::ManticoreException => e
74
- raise LogStash::ConfigurationError.new("Schema registry service doesn't respond, error: #{e.message}")
75
- end
76
- registered_subjects = JSON.parse response
77
- expected_subjects = @topics.map { |t| "#{t}-value"}
78
- if (expected_subjects & registered_subjects).size != expected_subjects.size
79
- undefined_topic_subjects = expected_subjects - registered_subjects
80
- raise LogStash::ConfigurationError, "The schema registry does not contain definitions for required topic subjects: #{undefined_topic_subjects}"
81
- end
82
- end
83
-
84
- def split_proxy_into_host_and_port(proxy_uri)
85
- return nil unless proxy_uri && !proxy_uri.empty?
86
-
87
- port = proxy_uri.port
88
-
89
- host_spec = ""
90
- host_spec << proxy_uri.scheme || "http"
91
- host_spec << "://"
92
- host_spec << "#{proxy_uri.userinfo}@" if proxy_uri.userinfo
93
- host_spec << proxy_uri.host
94
-
95
- [host_spec, port]
96
- end
97
-
98
- def check_for_key_and_secret
99
- if schema_registry_key and !schema_registry_key.empty?
100
- if !schema_registry_secret or schema_registry_secret.value.empty?
101
- raise LogStash::ConfigurationError, "Setting `schema_registry_secret` is required when `schema_registry_key` is provided."
102
- end
103
- end
104
- end
105
- end
106
- end
107
- end
@@ -1,29 +0,0 @@
1
- module LogStash module PluginMixins module KafkaSupport
2
-
3
- def set_trustore_keystore_config(props)
4
- props.put("ssl.truststore.type", ssl_truststore_type) unless ssl_truststore_type.nil?
5
- props.put("ssl.truststore.location", ssl_truststore_location) unless ssl_truststore_location.nil?
6
- props.put("ssl.truststore.password", ssl_truststore_password.value) unless ssl_truststore_password.nil?
7
-
8
- # Client auth stuff
9
- props.put("ssl.keystore.type", ssl_keystore_type) unless ssl_keystore_type.nil?
10
- props.put("ssl.key.password", ssl_key_password.value) unless ssl_key_password.nil?
11
- props.put("ssl.keystore.location", ssl_keystore_location) unless ssl_keystore_location.nil?
12
- props.put("ssl.keystore.password", ssl_keystore_password.value) unless ssl_keystore_password.nil?
13
- props.put("ssl.endpoint.identification.algorithm", ssl_endpoint_identification_algorithm) unless ssl_endpoint_identification_algorithm.nil?
14
- end
15
-
16
- def set_sasl_config(props)
17
- java.lang.System.setProperty("java.security.auth.login.config", jaas_path) unless jaas_path.nil?
18
- java.lang.System.setProperty("java.security.krb5.conf", kerberos_config) unless kerberos_config.nil?
19
-
20
- props.put("sasl.mechanism", sasl_mechanism)
21
- if sasl_mechanism == "GSSAPI" && sasl_kerberos_service_name.nil?
22
- raise LogStash::ConfigurationError, "sasl_kerberos_service_name must be specified when SASL mechanism is GSSAPI"
23
- end
24
-
25
- props.put("sasl.kerberos.service.name", sasl_kerberos_service_name) unless sasl_kerberos_service_name.nil?
26
- props.put("sasl.jaas.config", sasl_jaas_config) unless sasl_jaas_config.nil?
27
- end
28
-
29
- end end end