ruby-kafka 0.7.8 → 0.7.10

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: f85ddf1d516d86a5cedcf4de17f400cc93e8e20846dd657b3acb85ba6aca1bf6
4
- data.tar.gz: d7a55e0fad7767fed575ac2d05b3cba3837402dc97c908e7f47709bd550a484d
3
+ metadata.gz: 5aa84a39ade791c3bce57152d426e95cb7d29575af3e8a9cb29fcded1c6cdad5
4
+ data.tar.gz: 46be738fb1a2b71bbbd5d5d3b2fc95b705aef5740f666095eeaf40c9a6980fc4
5
5
  SHA512:
6
- metadata.gz: 1c4a94639c6c6a889d4be943c4201c60d6d29d872d20fde38b86c54168cb98ea1bfa0b1f151595033841792ee64db73cfdf1138ccd3ad51180a18ad742613230
7
- data.tar.gz: 4bde456d53429e192dc2d7dae7a75e009c15d1b793be658fb7402831376556cf9b2ea44eeaf858229a5d2b5e8fa75c2fa74e1ea1f89777a2b5728838e79422d2
6
+ metadata.gz: 42e8059ab9b49e16a8e9c70e5739c9694d2142d5d440f8e2c18477cc151a24183536ae1548aed66a7e7ee6ea64c96ff2c9aacb63366ed92bd1612af6e52d8300
7
+ data.tar.gz: 5008c803cc61fbea993f7f2a22ca7ac3ebb448f91cbdca40d540b9f4604dab8b4e38fcf4b20006a16641b5239e78d6045ccbec70168171219b716090ea72ba09
@@ -145,21 +145,53 @@ jobs:
145
145
  environment:
146
146
  LOG_LEVEL: DEBUG
147
147
  - image: wurstmeister/zookeeper
148
- - image: wurstmeister/kafka:2.12-2.1.0
148
+ - image: wurstmeister/kafka:2.12-2.1.1
149
149
  environment:
150
150
  KAFKA_ADVERTISED_HOST_NAME: localhost
151
151
  KAFKA_ADVERTISED_PORT: 9092
152
152
  KAFKA_PORT: 9092
153
153
  KAFKA_ZOOKEEPER_CONNECT: localhost:2181
154
154
  KAFKA_DELETE_TOPIC_ENABLE: true
155
- - image: wurstmeister/kafka:2.12-2.1.0
155
+ - image: wurstmeister/kafka:2.12-2.1.1
156
156
  environment:
157
157
  KAFKA_ADVERTISED_HOST_NAME: localhost
158
158
  KAFKA_ADVERTISED_PORT: 9093
159
159
  KAFKA_PORT: 9093
160
160
  KAFKA_ZOOKEEPER_CONNECT: localhost:2181
161
161
  KAFKA_DELETE_TOPIC_ENABLE: true
162
- - image: wurstmeister/kafka:2.12-2.1.0
162
+ - image: wurstmeister/kafka:2.12-2.1.1
163
+ environment:
164
+ KAFKA_ADVERTISED_HOST_NAME: localhost
165
+ KAFKA_ADVERTISED_PORT: 9094
166
+ KAFKA_PORT: 9094
167
+ KAFKA_ZOOKEEPER_CONNECT: localhost:2181
168
+ KAFKA_DELETE_TOPIC_ENABLE: true
169
+ steps:
170
+ - checkout
171
+ - run: bundle install --path vendor/bundle
172
+ - run: bundle exec rspec --profile --tag functional spec/functional
173
+
174
+ kafka-2.2:
175
+ docker:
176
+ - image: circleci/ruby:2.5.1-node
177
+ environment:
178
+ LOG_LEVEL: DEBUG
179
+ - image: wurstmeister/zookeeper
180
+ - image: wurstmeister/kafka:2.12-2.2.1
181
+ environment:
182
+ KAFKA_ADVERTISED_HOST_NAME: localhost
183
+ KAFKA_ADVERTISED_PORT: 9092
184
+ KAFKA_PORT: 9092
185
+ KAFKA_ZOOKEEPER_CONNECT: localhost:2181
186
+ KAFKA_DELETE_TOPIC_ENABLE: true
187
+ - image: wurstmeister/kafka:2.12-2.2.1
188
+ environment:
189
+ KAFKA_ADVERTISED_HOST_NAME: localhost
190
+ KAFKA_ADVERTISED_PORT: 9093
191
+ KAFKA_PORT: 9093
192
+ KAFKA_ZOOKEEPER_CONNECT: localhost:2181
193
+ KAFKA_DELETE_TOPIC_ENABLE: true
194
+ - image: wurstmeister/kafka:2.12-2.2.1
163
195
  environment:
164
196
  KAFKA_ADVERTISED_HOST_NAME: localhost
165
197
  KAFKA_ADVERTISED_PORT: 9094
@@ -181,3 +213,4 @@ workflows:
181
213
  - kafka-1.1
182
214
  - kafka-2.0
183
215
  - kafka-2.1
216
+ - kafka-2.2
@@ -2,7 +2,16 @@
2
2
 
3
3
  Changes and additions to the library will be listed here.
4
4
 
5
- ## Unreleased
5
+ ## 0.7.10
6
+
7
+ - Fix logger again (#762)
8
+
9
+ ## 0.7.9
10
+
11
+ - Fix SSL authentication for ruby < 2.4.0 (#742)
12
+ - Add metrics for prometheus/client (#739)
13
+ - Do not add nil message entries when ignoring old messages (#746)
14
+ - Scram authentication thread save (#743)
6
15
 
7
16
  ## 0.7.8
8
17
  - Optionally verify hostname on SSL certs (#733)
data/README.md CHANGED
@@ -108,6 +108,11 @@ Or install it yourself as:
108
108
  <td>Limited support</td>
109
109
  <td>Limited support</td>
110
110
  </tr>
111
+ <tr>
112
+ <th>Kafka 2.2</th>
113
+ <td>Limited support</td>
114
+ <td>Limited support</td>
115
+ </tr>
111
116
  </table>
112
117
 
113
118
  This library is targeting Kafka 0.9 with the v0.4.x series and Kafka 0.10 with the v0.5.x series. There's limited support for Kafka 0.8, and things should work with Kafka 0.11, although there may be performance issues due to changes in the protocol.
@@ -48,7 +48,7 @@ module Kafka
48
48
  partition: @fetched_partition.partition
49
49
  )
50
50
  end
51
- end
51
+ end.compact
52
52
  end
53
53
  FetchedBatch.new(
54
54
  topic: @topic,
@@ -0,0 +1,317 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Subscriber to ruby_kafka to report metrics to prometheus
5
+ #
6
+ # Usage:
7
+ # require "kafka/prometheus"
8
+ #
9
+ # Once the file has been required, no further configuration is needed, all operational
10
+ # metrics are automatically emitted (Unless PROMETHEUS_NO_AUTO_START is set).
11
+ #
12
+ # By Peter Mustel, T2 Data AB
13
+ #
14
+ begin
15
+ require 'prometheus/client'
16
+ rescue LoadError
17
+ warn 'In order to report Kafka client metrics to Prometheus you need to install the `prometheus-client` gem.'
18
+ raise
19
+ end
20
+
21
+ require 'active_support/subscriber'
22
+
23
+ module Kafka
24
+ module Prometheus
25
+ SIZE_BUCKETS = [1, 10, 100, 1000, 10_000, 100_000, 1_000_000].freeze
26
+ LATENCY_BUCKETS = [0.0001, 0.001, 0.01, 0.1, 1.0, 10, 100, 1000].freeze
27
+ DELAY_BUCKETS = [1, 3, 10, 30, 100, 300, 1000, 3000, 10_000, 30_000].freeze
28
+
29
+ class << self
30
+ attr_accessor :registry
31
+
32
+ def start(registry = ::Prometheus::Client.registry)
33
+ @registry = registry
34
+ ConnectionSubscriber.attach_to 'connection.kafka'
35
+ ConsumerSubscriber.attach_to 'consumer.kafka'
36
+ ProducerSubscriber.attach_to 'producer.kafka'
37
+ AsyncProducerSubscriber.attach_to 'async_producer.kafka'
38
+ FetcherSubscriber.attach_to 'fetcher.kafka'
39
+ end
40
+ end
41
+
42
+ class ConnectionSubscriber < ActiveSupport::Subscriber
43
+ def initialize
44
+ super
45
+ @api_calls = Prometheus.registry.counter(:api_calls, 'Total calls')
46
+ @api_latency = Prometheus.registry.histogram(:api_latency, 'Latency', {}, LATENCY_BUCKETS)
47
+ @api_request_size = Prometheus.registry.histogram(:api_request_size, 'Request size', {}, SIZE_BUCKETS)
48
+ @api_response_size = Prometheus.registry.histogram(:api_response_size, 'Response size', {}, SIZE_BUCKETS)
49
+ @api_errors = Prometheus.registry.counter(:api_errors, 'Errors')
50
+ end
51
+
52
+ def request(event)
53
+ key = {
54
+ client: event.payload.fetch(:client_id),
55
+ api: event.payload.fetch(:api, 'unknown'),
56
+ broker: event.payload.fetch(:broker_host)
57
+ }
58
+ request_size = event.payload.fetch(:request_size, 0)
59
+ response_size = event.payload.fetch(:response_size, 0)
60
+
61
+ @api_calls.increment(key)
62
+ @api_latency.observe(key, event.duration)
63
+ @api_request_size.observe(key, request_size)
64
+ @api_response_size.observe(key, response_size)
65
+ @api_errors.increment(key) if event.payload.key?(:exception)
66
+ end
67
+ end
68
+
69
+ class ConsumerSubscriber < ActiveSupport::Subscriber
70
+ def initialize
71
+ super
72
+ @process_messages = Prometheus.registry.counter(:consumer_process_messages, 'Total messages')
73
+ @process_message_errors = Prometheus.registry.counter(:consumer_process_message_errors, 'Total errors')
74
+ @process_message_latency =
75
+ Prometheus.registry.histogram(:consumer_process_message_latency, 'Latency', {}, LATENCY_BUCKETS)
76
+ @offset_lag = Prometheus.registry.gauge(:consumer_offset_lag, 'Offset lag')
77
+ @time_lag = Prometheus.registry.gauge(:consumer_time_lag, 'Time lag of message')
78
+ @process_batch_errors = Prometheus.registry.counter(:consumer_process_batch_errors, 'Total errors in batch')
79
+ @process_batch_latency =
80
+ Prometheus.registry.histogram(:consumer_process_batch_latency, 'Latency in batch', {}, LATENCY_BUCKETS)
81
+ @batch_size = Prometheus.registry.histogram(:consumer_batch_size, 'Size of batch', {}, SIZE_BUCKETS)
82
+ @join_group = Prometheus.registry.histogram(:consumer_join_group, 'Time to join group', {}, DELAY_BUCKETS)
83
+ @join_group_errors = Prometheus.registry.counter(:consumer_join_group_errors, 'Total error in joining group')
84
+ @sync_group = Prometheus.registry.histogram(:consumer_sync_group, 'Time to sync group', {}, DELAY_BUCKETS)
85
+ @sync_group_errors = Prometheus.registry.counter(:consumer_sync_group_errors, 'Total error in syncing group')
86
+ @leave_group = Prometheus.registry.histogram(:consumer_leave_group, 'Time to leave group', {}, DELAY_BUCKETS)
87
+ @leave_group_errors = Prometheus.registry.counter(:consumer_leave_group_errors, 'Total error in leaving group')
88
+ @pause_duration = Prometheus.registry.gauge(:consumer_pause_duration, 'Pause duration')
89
+ end
90
+
91
+ def process_message(event)
92
+ key = {
93
+ client: event.payload.fetch(:client_id),
94
+ group_id: event.payload.fetch(:group_id),
95
+ topic: event.payload.fetch(:topic),
96
+ partition: event.payload.fetch(:partition)
97
+ }
98
+
99
+ offset_lag = event.payload.fetch(:offset_lag)
100
+ create_time = event.payload.fetch(:create_time)
101
+
102
+ time_lag = create_time && ((Time.now - create_time) * 1000).to_i
103
+
104
+ if event.payload.key?(:exception)
105
+ @process_message_errors.increment(key)
106
+ else
107
+ @process_message_latency.observe(key, event.duration)
108
+ @process_messages.increment(key)
109
+ end
110
+
111
+ @offset_lag.set(key, offset_lag)
112
+
113
+ # Not all messages have timestamps.
114
+ return unless time_lag
115
+
116
+ @time_lag.set(key, time_lag)
117
+ end
118
+
119
+ def process_batch(event)
120
+ key = {
121
+ client: event.payload.fetch(:client_id),
122
+ group_id: event.payload.fetch(:group_id),
123
+ topic: event.payload.fetch(:topic),
124
+ partition: event.payload.fetch(:partition)
125
+ }
126
+ message_count = event.payload.fetch(:message_count)
127
+
128
+ if event.payload.key?(:exception)
129
+ @process_batch_errors.increment(key)
130
+ else
131
+ @process_batch_latency.observe(key, event.duration)
132
+ @process_messages.increment(key, message_count)
133
+ end
134
+ end
135
+
136
+ def fetch_batch(event)
137
+ key = {
138
+ client: event.payload.fetch(:client_id),
139
+ group_id: event.payload.fetch(:group_id),
140
+ topic: event.payload.fetch(:topic),
141
+ partition: event.payload.fetch(:partition)
142
+ }
143
+ offset_lag = event.payload.fetch(:offset_lag)
144
+ batch_size = event.payload.fetch(:message_count)
145
+
146
+ @batch_size.observe(key, batch_size)
147
+ @offset_lag.set(key, offset_lag)
148
+ end
149
+
150
+ def join_group(event)
151
+ key = { client: event.payload.fetch(:client_id), group_id: event.payload.fetch(:group_id) }
152
+ @join_group.observe(key, event.duration)
153
+
154
+ @join_group_errors.increment(key) if event.payload.key?(:exception)
155
+ end
156
+
157
+ def sync_group(event)
158
+ key = { client: event.payload.fetch(:client_id), group_id: event.payload.fetch(:group_id) }
159
+ @sync_group.observe(key, event.duration)
160
+
161
+ @sync_group_errors.increment(key) if event.payload.key?(:exception)
162
+ end
163
+
164
+ def leave_group(event)
165
+ key = { client: event.payload.fetch(:client_id), group_id: event.payload.fetch(:group_id) }
166
+ @leave_group.observe(key, event.duration)
167
+
168
+ @leave_group_errors.increment(key) if event.payload.key?(:exception)
169
+ end
170
+
171
+ def pause_status(event)
172
+ key = {
173
+ client: event.payload.fetch(:client_id),
174
+ group_id: event.payload.fetch(:group_id),
175
+ topic: event.payload.fetch(:topic),
176
+ partition: event.payload.fetch(:partition)
177
+ }
178
+
179
+ duration = event.payload.fetch(:duration)
180
+ @pause_duration.set(key, duration)
181
+ end
182
+ end
183
+
184
+ class ProducerSubscriber < ActiveSupport::Subscriber
185
+ def initialize
186
+ super
187
+ @produce_messages = Prometheus.registry.counter(:producer_produced_messages, 'Produced messages total')
188
+ @produce_message_size =
189
+ Prometheus.registry.histogram(:producer_message_size, 'Message size', {}, SIZE_BUCKETS)
190
+ @buffer_size = Prometheus.registry.histogram(:producer_buffer_size, 'Buffer size', {}, SIZE_BUCKETS)
191
+ @buffer_fill_ratio = Prometheus.registry.histogram(:producer_buffer_fill_ratio, 'Buffer fill ratio')
192
+ @buffer_fill_percentage = Prometheus.registry.histogram(:producer_buffer_fill_percentage, 'Buffer fill percentage')
193
+ @produce_errors = Prometheus.registry.counter(:producer_produce_errors, 'Produce errors')
194
+ @deliver_errors = Prometheus.registry.counter(:producer_deliver_errors, 'Deliver error')
195
+ @deliver_latency =
196
+ Prometheus.registry.histogram(:producer_deliver_latency, 'Delivery latency', {}, LATENCY_BUCKETS)
197
+ @deliver_messages = Prometheus.registry.counter(:producer_deliver_messages, 'Total count of delivered messages')
198
+ @deliver_attempts = Prometheus.registry.histogram(:producer_deliver_attempts, 'Delivery attempts')
199
+ @ack_messages = Prometheus.registry.counter(:producer_ack_messages, 'Ack')
200
+ @ack_delay = Prometheus.registry.histogram(:producer_ack_delay, 'Ack delay', {}, LATENCY_BUCKETS)
201
+ @ack_errors = Prometheus.registry.counter(:producer_ack_errors, 'Ack errors')
202
+ end
203
+
204
+ def produce_message(event)
205
+ client = event.payload.fetch(:client_id)
206
+ key = { client: client, topic: event.payload.fetch(:topic) }
207
+
208
+ message_size = event.payload.fetch(:message_size)
209
+ buffer_size = event.payload.fetch(:buffer_size)
210
+ max_buffer_size = event.payload.fetch(:max_buffer_size)
211
+ buffer_fill_ratio = buffer_size.to_f / max_buffer_size.to_f
212
+ buffer_fill_percentage = buffer_fill_ratio * 100.0
213
+
214
+ # This gets us the write rate.
215
+ @produce_messages.increment(key)
216
+ @produce_message_size.observe(key, message_size)
217
+
218
+ # This gets us the avg/max buffer size per producer.
219
+ @buffer_size.observe({ client: client }, buffer_size)
220
+
221
+ # This gets us the avg/max buffer fill ratio per producer.
222
+ @buffer_fill_ratio.observe({ client: client }, buffer_fill_ratio)
223
+ @buffer_fill_percentage.observe({ client: client }, buffer_fill_percentage)
224
+ end
225
+
226
+ def buffer_overflow(event)
227
+ key = { client: event.payload.fetch(:client_id), topic: event.payload.fetch(:topic) }
228
+ @produce_errors.increment(key)
229
+ end
230
+
231
+ def deliver_messages(event)
232
+ key = { client: event.payload.fetch(:client_id) }
233
+ message_count = event.payload.fetch(:delivered_message_count)
234
+ attempts = event.payload.fetch(:attempts)
235
+
236
+ @deliver_errors.increment(key) if event.payload.key?(:exception)
237
+ @deliver_latency.observe(key, event.duration)
238
+
239
+ # Messages delivered to Kafka:
240
+ @deliver_messages.increment(key, message_count)
241
+
242
+ # Number of attempts to deliver messages:
243
+ @deliver_attempts.observe(key, attempts)
244
+ end
245
+
246
+ def ack_message(event)
247
+ key = { client: event.payload.fetch(:client_id), topic: event.payload.fetch(:topic) }
248
+
249
+ # Number of messages ACK'd for the topic.
250
+ @ack_messages.increment(key)
251
+
252
+ # Histogram of delay between a message being produced and it being ACK'd.
253
+ @ack_delay.observe(key, event.payload.fetch(:delay))
254
+ end
255
+
256
+ def topic_error(event)
257
+ key = { client: event.payload.fetch(:client_id), topic: event.payload.fetch(:topic) }
258
+
259
+ @ack_errors.increment(key)
260
+ end
261
+ end
262
+
263
+ class AsyncProducerSubscriber < ActiveSupport::Subscriber
264
+ def initialize
265
+ super
266
+ @queue_size = Prometheus.registry.histogram(:async_producer_queue_size, 'Queue size', {}, SIZE_BUCKETS)
267
+ @queue_fill_ratio = Prometheus.registry.histogram(:async_producer_queue_fill_ratio, 'Queue fill ratio')
268
+ @produce_errors = Prometheus.registry.counter(:async_producer_produce_errors, 'Producer errors')
269
+ @dropped_messages = Prometheus.registry.counter(:async_producer_dropped_messages, 'Dropped messages')
270
+ end
271
+
272
+ def enqueue_message(event)
273
+ key = { client: event.payload.fetch(:client_id), topic: event.payload.fetch(:topic) }
274
+
275
+ queue_size = event.payload.fetch(:queue_size)
276
+ max_queue_size = event.payload.fetch(:max_queue_size)
277
+ queue_fill_ratio = queue_size.to_f / max_queue_size.to_f
278
+
279
+ # This gets us the avg/max queue size per producer.
280
+ @queue_size.observe(key, queue_size)
281
+
282
+ # This gets us the avg/max queue fill ratio per producer.
283
+ @queue_fill_ratio.observe(key, queue_fill_ratio)
284
+ end
285
+
286
+ def buffer_overflow(event)
287
+ key = { client: event.payload.fetch(:client_id), topic: event.payload.fetch(:topic) }
288
+ @produce_errors.increment(key)
289
+ end
290
+
291
+ def drop_messages(event)
292
+ key = { client: event.payload.fetch(:client_id) }
293
+ message_count = event.payload.fetch(:message_count)
294
+
295
+ @dropped_messages.increment(key, message_count)
296
+ end
297
+ end
298
+
299
+ class FetcherSubscriber < ActiveSupport::Subscriber
300
+ def initialize
301
+ super
302
+ @queue_size = Prometheus.registry.gauge(:fetcher_queue_size, 'Queue size')
303
+ end
304
+
305
+ def loop(event)
306
+ queue_size = event.payload.fetch(:queue_size)
307
+ client = event.payload.fetch(:client_id)
308
+ group_id = event.payload.fetch(:group_id)
309
+
310
+ @queue_size.set({ client: client, group_id: group_id }, queue_size)
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ # To enable testability, it is possible to skip the start until test time
317
+ Kafka::Prometheus.start unless defined?(PROMETHEUS_NO_AUTO_START)
@@ -1,3 +1,4 @@
1
+ require 'bigdecimal'
1
2
  require 'digest/crc32'
2
3
  require 'kafka/protocol/record'
3
4
 
@@ -131,7 +132,7 @@ module Kafka
131
132
 
132
133
  records.each_with_index do |record, index|
133
134
  record.offset_delta = index
134
- record.timestamp_delta = (record.create_time - first_timestamp).to_i
135
+ record.timestamp_delta = ((record.create_time - first_timestamp) * 1000).to_i
135
136
  end
136
137
  @last_offset_delta = records.length - 1
137
138
  end
@@ -167,8 +168,8 @@ module Kafka
167
168
  log_append_time = (attributes & TIMESTAMP_TYPE_MASK) != 0
168
169
 
169
170
  last_offset_delta = record_batch_decoder.int32
170
- first_timestamp = Time.at(record_batch_decoder.int64 / 1000)
171
- max_timestamp = Time.at(record_batch_decoder.int64 / 1000)
171
+ first_timestamp = Time.at(record_batch_decoder.int64 / BigDecimal(1000))
172
+ max_timestamp = Time.at(record_batch_decoder.int64 / BigDecimal(1000))
172
173
 
173
174
  producer_id = record_batch_decoder.int64
174
175
  producer_epoch = record_batch_decoder.int16
@@ -188,7 +189,7 @@ module Kafka
188
189
  until records_array_decoder.eof?
189
190
  record = Record.decode(records_array_decoder)
190
191
  record.offset = first_offset + record.offset_delta
191
- record.create_time = log_append_time && max_timestamp ? max_timestamp : first_timestamp + record.timestamp_delta
192
+ record.create_time = log_append_time && max_timestamp ? max_timestamp : first_timestamp + record.timestamp_delta / BigDecimal(1000)
192
193
  records_array << record
193
194
  end
194
195
 
@@ -12,6 +12,7 @@ module Kafka
12
12
  }.freeze
13
13
 
14
14
  def initialize(username:, password:, mechanism: 'sha256', logger:)
15
+ @semaphore = Mutex.new
15
16
  @username = username
16
17
  @password = password
17
18
  @logger = TaggedLogger.new(logger)
@@ -35,22 +36,24 @@ module Kafka
35
36
  @logger.debug "Authenticating #{@username} with SASL #{@mechanism}"
36
37
 
37
38
  begin
38
- msg = first_message
39
- @logger.debug "Sending first client SASL SCRAM message: #{msg}"
40
- encoder.write_bytes(msg)
39
+ @semaphore.synchronize do
40
+ msg = first_message
41
+ @logger.debug "Sending first client SASL SCRAM message: #{msg}"
42
+ encoder.write_bytes(msg)
41
43
 
42
- @server_first_message = decoder.bytes
43
- @logger.debug "Received first server SASL SCRAM message: #{@server_first_message}"
44
+ @server_first_message = decoder.bytes
45
+ @logger.debug "Received first server SASL SCRAM message: #{@server_first_message}"
44
46
 
45
- msg = final_message
46
- @logger.debug "Sending final client SASL SCRAM message: #{msg}"
47
- encoder.write_bytes(msg)
47
+ msg = final_message
48
+ @logger.debug "Sending final client SASL SCRAM message: #{msg}"
49
+ encoder.write_bytes(msg)
48
50
 
49
- response = parse_response(decoder.bytes)
50
- @logger.debug "Received last server SASL SCRAM message: #{response}"
51
+ response = parse_response(decoder.bytes)
52
+ @logger.debug "Received last server SASL SCRAM message: #{response}"
51
53
 
52
- raise FailedScramAuthentication, response['e'] if response['e']
53
- raise FailedScramAuthentication, "Invalid server signature" if response['v'] != server_signature
54
+ raise FailedScramAuthentication, response['e'] if response['e']
55
+ raise FailedScramAuthentication, "Invalid server signature" if response['v'] != server_signature
56
+ end
54
57
  rescue EOFError => e
55
58
  raise FailedScramAuthentication, e.message
56
59
  end
@@ -55,7 +55,8 @@ module Kafka
55
55
  end
56
56
  ssl_context.cert_store = store
57
57
  ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
58
- ssl_context.verify_hostname = verify_hostname
58
+ # Verify certificate hostname if supported (ruby >= 2.4.0)
59
+ ssl_context.verify_hostname = verify_hostname if ssl_context.respond_to?(:verify_hostname=)
59
60
  end
60
61
 
61
62
  ssl_context
@@ -1,13 +1,19 @@
1
- require 'forwardable'
2
-
3
1
  # Basic implementation of a tagged logger that matches the API of
4
2
  # ActiveSupport::TaggedLogging.
5
3
 
4
+ require 'logger'
5
+
6
6
  module Kafka
7
- module TaggedFormatter
7
+ class TaggedLogger < SimpleDelegator
8
8
 
9
- def call(severity, timestamp, progname, msg)
10
- super(severity, timestamp, progname, "#{tags_text}#{msg}")
9
+ %i(debug info warn error).each do |method|
10
+ define_method method do |msg_or_progname, &block|
11
+ if block_given?
12
+ super(msg_or_progname, &block)
13
+ else
14
+ super("#{tags_text}#{msg_or_progname}")
15
+ end
16
+ end
11
17
  end
12
18
 
13
19
  def tagged(*tags)
@@ -44,23 +50,21 @@ module Kafka
44
50
  end
45
51
  end
46
52
 
47
- end
48
-
49
- module TaggedLogger
50
- extend Forwardable
51
- delegate [:push_tags, :pop_tags, :clear_tags!] => :formatter
52
-
53
- def self.new(logger)
54
- logger ||= Logger.new(nil)
55
- return logger if logger.respond_to?(:push_tags) # already included
56
- # Ensure we set a default formatter so we aren't extending nil!
57
- logger.formatter ||= Logger::Formatter.new
58
- logger.formatter.extend TaggedFormatter
59
- logger.extend(self)
53
+ def self.new(logger_or_stream = nil)
54
+ # don't keep wrapping the same logger over and over again
55
+ return logger_or_stream if logger_or_stream.is_a?(TaggedLogger)
56
+ super
60
57
  end
61
58
 
62
- def tagged(*tags)
63
- formatter.tagged(*tags) { yield self }
59
+ def initialize(logger_or_stream = nil)
60
+ logger = if %w(info debug warn error).all? { |s| logger_or_stream.respond_to?(s) }
61
+ logger_or_stream
62
+ elsif logger_or_stream
63
+ ::Logger.new(logger_or_stream)
64
+ else
65
+ ::Logger.new(nil)
66
+ end
67
+ super(logger)
64
68
  end
65
69
 
66
70
  def flush
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kafka
4
- VERSION = "0.7.8"
4
+ VERSION = "0.7.10"
5
5
  end
@@ -44,6 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_development_dependency "rspec_junit_formatter", "0.2.2"
45
45
  spec.add_development_dependency "dogstatsd-ruby", ">= 3.0.0", "< 5.0.0"
46
46
  spec.add_development_dependency "statsd-ruby"
47
+ spec.add_development_dependency "prometheus-client"
47
48
  spec.add_development_dependency "ruby-prof"
48
49
  spec.add_development_dependency "timecop"
49
50
  spec.add_development_dependency "rubocop", "~> 0.49.1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-kafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.8
4
+ version: 0.7.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-31 00:00:00.000000000 Z
11
+ date: 2019-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digest-crc
@@ -240,6 +240,20 @@ dependencies:
240
240
  - - ">="
241
241
  - !ruby/object:Gem::Version
242
242
  version: '0'
243
+ - !ruby/object:Gem::Dependency
244
+ name: prometheus-client
245
+ requirement: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ type: :development
251
+ prerelease: false
252
+ version_requirements: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
243
257
  - !ruby/object:Gem::Dependency
244
258
  name: ruby-prof
245
259
  requirement: !ruby/object:Gem::Requirement
@@ -374,6 +388,7 @@ files:
374
388
  - lib/kafka/pending_message_queue.rb
375
389
  - lib/kafka/produce_operation.rb
376
390
  - lib/kafka/producer.rb
391
+ - lib/kafka/prometheus.rb
377
392
  - lib/kafka/protocol.rb
378
393
  - lib/kafka/protocol/add_offsets_to_txn_request.rb
379
394
  - lib/kafka/protocol/add_offsets_to_txn_response.rb