logstash-integration-rabbitmq 7.0.0-java → 7.1.1-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.
@@ -1,3 +1,4 @@
1
+ :integration: rabbitmq
1
2
  :plugin: rabbitmq
2
3
  :type: output
3
4
  :default_codec: json
@@ -17,7 +18,7 @@ END - GENERATED VARIABLES, DO NOT EDIT!
17
18
 
18
19
  === Rabbitmq output plugin
19
20
 
20
- include::{include_path}/plugin_header.asciidoc[]
21
+ include::{include_path}/plugin_header-integration.asciidoc[]
21
22
 
22
23
  ==== Description
23
24
 
@@ -168,7 +169,8 @@ Key to route to by default. Defaults to 'logstash'
168
169
  * Value type is <<hash,hash>>
169
170
  * Default value is `{}`
170
171
 
171
- Add properties to be set per-message here, such as 'content_type', 'priority'
172
+ Add properties to be set per-message here, such as 'content_type', 'priority'.
173
+ Values can be {logstash-ref}/event-dependent-configuration.html#sprintf[`sprintf` templates], whose value for each message will be populated from the event.
172
174
 
173
175
  Example:
174
176
  [source,ruby]
@@ -2,8 +2,6 @@
2
2
  require_relative '../plugin_mixins/rabbitmq_connection'
3
3
  require 'logstash/inputs/threadable'
4
4
  require 'logstash/event'
5
- java_import java.util.concurrent.ArrayBlockingQueue
6
- java_import java.util.concurrent.TimeUnit
7
5
 
8
6
  module LogStash
9
7
  module Inputs
@@ -59,6 +57,9 @@ module LogStash
59
57
  # Additionally, any message headers will be saved in the
60
58
  # `[@metadata][rabbitmq_headers]` field.
61
59
  class RabbitMQ < LogStash::Inputs::Threadable
60
+
61
+ java_import java.util.concurrent.TimeUnit
62
+
62
63
  include ::LogStash::PluginMixins::RabbitMQConnection
63
64
 
64
65
  # The properties to extract from each message and store in a
@@ -121,8 +122,6 @@ module LogStash
121
122
  # restart).
122
123
  config :exclusive, :validate => :boolean, :default => false
123
124
 
124
- # Extra queue arguments as an array.
125
- # To make a RabbitMQ queue mirrored, use: `{"x-ha-policy" => "all"}`
126
125
  config :arguments, :validate => :array, :default => {}
127
126
 
128
127
  # Prefetch count. If acknowledgements are enabled with the `ack`
@@ -167,16 +166,26 @@ module LogStash
167
166
  config :subscription_retry_interval_seconds, :validate => :number, :required => true, :default => 5
168
167
 
169
168
  # Enable the storage of message headers and properties in `@metadata`. This may impact performance
170
- config :metadata_enabled, :validate => :boolean, :default => false
169
+ config :metadata_enabled, :validate => %w(none basic extended false true), :default => "none"
171
170
 
172
171
  def register
173
172
  @internal_queue = java.util.concurrent.ArrayBlockingQueue.new(@prefetch_count*2)
173
+ @metadata_level = extract_metadata_level(@metadata_enabled)
174
174
  end
175
175
 
176
+ attr_reader :metadata_level
177
+
176
178
  def run(output_queue)
177
179
  setup!
178
180
  @output_queue = output_queue
179
181
  consume!
182
+ rescue => e
183
+ raise unless stop?
184
+
185
+ logger.warn("Ignoring exception thrown during plugin shutdown",
186
+ :message => e.message,
187
+ :class => e.class.name,
188
+ :location => e.backtrace.first)
180
189
  end
181
190
 
182
191
  def setup!
@@ -185,14 +194,32 @@ module LogStash
185
194
  bind_exchange!
186
195
  @hare_info.channel.prefetch = @prefetch_count
187
196
  rescue => e
197
+ # when encountering an exception during shut-down,
198
+ # re-raise the exception instead of retrying
199
+ raise if stop?
200
+
201
+ reset!
202
+
188
203
  @logger.warn("Error while setting up connection for rabbitmq input! Will retry.",
189
- :message => e.message,
190
- :class => e.class.name,
204
+ :message => e.message,
205
+ :class => e.class.name,
191
206
  :location => e.backtrace.first)
192
207
  sleep_for_retry
193
208
  retry
194
209
  end
195
210
 
211
+ # reset a partially-established connection, enabling subsequent
212
+ # call to `RabbitMQ#setup!` to succeed.
213
+ #
214
+ # @api private
215
+ def reset!
216
+ @hare_info.connection && @hare_info.connection.close
217
+ rescue => e
218
+ @logger.debug("Exception while resetting connection", :exception => e.message, :backtrace => e.backtrace)
219
+ ensure
220
+ @hare_info = nil
221
+ end
222
+
196
223
  def bind_exchange!
197
224
  if @exchange
198
225
  if @exchange_type # Only declare the exchange if @exchange_type is set!
@@ -251,12 +278,11 @@ module LogStash
251
278
 
252
279
  metadata, data = payload
253
280
  @codec.decode(data) do |event|
254
- decorate(event)
255
- if @metadata_enabled
256
- event.set("[@metadata][rabbitmq_headers]", get_headers(metadata))
257
- event.set("[@metadata][rabbitmq_properties]", get_properties(metadata))
281
+ if event
282
+ decorate(event, metadata, data)
283
+
284
+ @output_queue << event
258
285
  end
259
- @output_queue << event if event
260
286
  end
261
287
 
262
288
  i += 1
@@ -271,6 +297,16 @@ module LogStash
271
297
  end
272
298
  end
273
299
 
300
+ def decorate(event, metadata, data)
301
+ super(event)
302
+
303
+ event.set("[@metadata][rabbitmq_headers]", get_headers(metadata)) if metadata_level.include?(:headers)
304
+ event.set("[@metadata][rabbitmq_properties]", get_properties(metadata)) if metadata_level.include?(:properties)
305
+ event.set("[@metadata][rabbitmq_payload]", data) if metadata_level.include?(:payload) && !data.nil?
306
+
307
+ nil
308
+ end
309
+
274
310
  def stop
275
311
  @internal_queue.put(INTERNAL_QUEUE_POISON)
276
312
  shutdown_consumer
@@ -312,6 +348,28 @@ module LogStash
312
348
  acc
313
349
  end
314
350
  end
351
+
352
+ METADATA_NONE = Set[].freeze
353
+ METADATA_BASIC = Set[:headers,:properties].freeze
354
+ METADATA_EXTENDED = Set[:headers,:properties,:payload].freeze
355
+ METADATA_DEPRECATION_MAP = { 'true' => 'basic', 'false' => 'none' }
356
+
357
+ private
358
+ def extract_metadata_level(metadata_enabled_setting)
359
+ metadata_enabled = metadata_enabled_setting
360
+
361
+ if METADATA_DEPRECATION_MAP.include?(metadata_enabled)
362
+ canonical_value = METADATA_DEPRECATION_MAP[metadata_enabled]
363
+ logger.warn("Deprecated value `#{metadata_enabled_setting}` for `metadata_enabled` option; use `#{canonical_value}` instead.")
364
+ metadata_enabled = canonical_value
365
+ end
366
+
367
+ case metadata_enabled
368
+ when 'none' then METADATA_NONE
369
+ when 'basic' then METADATA_BASIC
370
+ when 'extended' then METADATA_EXTENDED
371
+ end
372
+ end
315
373
  end
316
374
  end
317
375
  end
@@ -1,14 +1,12 @@
1
1
  # encoding: UTF-8
2
2
  require "logstash/pipeline"
3
3
  require_relative '../plugin_mixins/rabbitmq_connection'
4
- java_import java.util.concurrent.TimeoutException
5
- java_import com.rabbitmq.client.AlreadyClosedException
6
4
 
7
5
  require 'back_pressure'
8
6
 
9
7
  # Push events to a RabbitMQ exchange. Requires RabbitMQ 2.x
10
8
  # or later version (3.x is recommended).
11
- #
9
+ #
12
10
  # Relevant links:
13
11
  #
14
12
  # * http://www.rabbitmq.com/[RabbitMQ]
@@ -16,10 +14,14 @@ require 'back_pressure'
16
14
  module LogStash
17
15
  module Outputs
18
16
  class RabbitMQ < LogStash::Outputs::Base
17
+
18
+ java_import java.util.concurrent.TimeoutException
19
+ java_import com.rabbitmq.client.AlreadyClosedException
20
+
19
21
  include LogStash::PluginMixins::RabbitMQConnection
20
22
 
21
23
  config_name "rabbitmq"
22
-
24
+
23
25
  concurrency :shared
24
26
 
25
27
  # The default codec for this plugin is JSON. You can override this to suit your particular needs however.
@@ -46,6 +48,8 @@ module LogStash
46
48
  config :message_properties, :validate => :hash, :default => {}
47
49
 
48
50
  def register
51
+ @message_properties_template = MessagePropertiesTemplate.new(symbolize(@message_properties).merge(:persistent => @persistent))
52
+
49
53
  connect!
50
54
  @hare_info.exchange = declare_exchange!(@hare_info.channel, @exchange, @exchange_type, @durable)
51
55
  # The connection close should close all channels, so it is safe to store thread locals here without closing them
@@ -67,8 +71,10 @@ module LogStash
67
71
 
68
72
  def publish(event, message)
69
73
  raise ArgumentError, "No exchange set in HareInfo!!!" unless @hare_info.exchange
74
+ routing_key = event.sprintf(@key)
75
+ message_properties = @message_properties_template.build(event)
70
76
  @gated_executor.execute do
71
- local_exchange.publish(message, :routing_key => event.sprintf(@key), :properties => symbolize(@message_properties.merge(:persistent => @persistent)))
77
+ local_exchange.publish(message, :routing_key => routing_key, :properties => message_properties)
72
78
  end
73
79
  rescue MarchHare::Exception, IOError, AlreadyClosedException, TimeoutException => e
74
80
  @logger.error("Error while publishing. Will retry.",
@@ -118,7 +124,7 @@ module LogStash
118
124
  march_hare_connection.on_unblocked do
119
125
  executor.remove_back_pressure('connection flagged as unblocked')
120
126
  end
121
- march_hare_connection.on_recovery_started do
127
+ march_hare_connection.on_recovery_start do
122
128
  executor.engage_back_pressure("connection is being recovered")
123
129
  end
124
130
  march_hare_connection.on_recovery do
@@ -126,6 +132,64 @@ module LogStash
126
132
  end
127
133
  end
128
134
  end
135
+
136
+ ##
137
+ # A `MessagePropertiesTemplate` efficiently produces per-event message properties from the
138
+ # provided template Hash.
139
+ #
140
+ # In order to efficiently reuse constant-value objects, returned values may be frozen.
141
+ class MessagePropertiesTemplate
142
+ ##
143
+ # Creates a new `MessagePropertiesTemplate` from the provided `template`
144
+ # @param template [Hash{Symbol=>Object}]
145
+ def initialize(template)
146
+ constant_properties = template.reject { |_,v| templated?(v) }
147
+ variable_properties = template.select { |_,v| templated?(v) }
148
+
149
+ @constant_properties = normalize(constant_properties).freeze
150
+ @variable_properties = variable_properties
151
+ end
152
+
153
+ ##
154
+ # Builds a property mapping for the given `event`, including templated values.
155
+ #
156
+ # @param event [LogStash::Event]: the event with which to populated templated values, if any.
157
+ # @return [Hash{Symbol=>Object}] a possibly-frozen properties hash for the provided `event`.
158
+ def build(event)
159
+ return @constant_properties if @variable_properties.empty?
160
+
161
+ properties = @variable_properties.each_with_object(@constant_properties.dup) do |(k,v), memo|
162
+ memo.store(k, event.sprintf(v))
163
+ end
164
+
165
+ return normalize(properties)
166
+ end
167
+
168
+ private
169
+
170
+ ##
171
+ # Normalize the provided property mapping with respect to the value types the underlying
172
+ # client expects.
173
+ #
174
+ # @api private
175
+ # @param properties [Hash{Symbol=>Object}]: a possibly-frozen Hash whose values may need type-coercion.
176
+ # @return [Hash{Symbol=>Object}]
177
+ def normalize(properties)
178
+ if properties[:priority] && properties[:priority].kind_of?(String)
179
+ properties = properties.merge(:priority => properties[:priority].to_i)
180
+ end
181
+
182
+ properties
183
+ end
184
+
185
+ ##
186
+ # @api private
187
+ # @param [Object]: an object, which may or may not be a template `String`
188
+ # @return [Boolean]: returns `true` IFF `value` is a template `String`
189
+ def templated?(value)
190
+ value.kind_of?(String) && value.include?('%{')
191
+ end
192
+ end
129
193
  end
130
194
  end
131
- end
195
+ end
@@ -104,10 +104,10 @@ module LogStash
104
104
  def rabbitmq_settings
105
105
  return @rabbitmq_settings if @rabbitmq_settings
106
106
 
107
+
107
108
  s = {
108
109
  :vhost => @vhost,
109
- :hosts => @host,
110
- :port => @port,
110
+ :addresses => addresses_from_hosts_and_port(@host, @port),
111
111
  :user => @user,
112
112
  :automatic_recovery => @automatic_recovery,
113
113
  :pass => @password ? @password.value : "guest",
@@ -133,6 +133,11 @@ module LogStash
133
133
  @rabbitmq_settings = s
134
134
  end
135
135
 
136
+ def addresses_from_hosts_and_port(hosts, port)
137
+ hosts.map {|host| host.include?(':') ? host : "#{host}:#{port}"}
138
+ end
139
+
140
+
136
141
  def connect!
137
142
  @hare_info = connect() unless @hare_info # Don't duplicate the conn!
138
143
  rescue MarchHare::Exception, java.io.IOException => e
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-integration-rabbitmq'
3
- s.version = '7.0.0'
3
+ s.version = '7.1.1'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Integration with RabbitMQ - 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,7 +47,7 @@ Gem::Specification.new do |s|
47
47
  s.add_runtime_dependency 'stud', '~> 0.0.22'
48
48
  s.add_runtime_dependency 'back_pressure', '~> 1.0'
49
49
 
50
- s.add_development_dependency 'logstash-devutils'
50
+ s.add_development_dependency 'logstash-devutils', '~>2.0'
51
51
  s.add_development_dependency 'logstash-input-generator'
52
52
  s.add_development_dependency 'logstash-codec-plain'
53
53
  end
@@ -21,8 +21,13 @@ describe LogStash::Inputs::RabbitMQ do
21
21
  "prefetch_count" => 123
22
22
  }
23
23
  }
24
- let(:instance) { klass.new(rabbitmq_settings) }
24
+ subject(:instance) { klass.new(rabbitmq_settings) }
25
25
  let(:hare_info) { instance.instance_variable_get(:@hare_info) }
26
+ let(:instance_logger) { double("Logger").as_null_object }
27
+
28
+ before do
29
+ allow_any_instance_of(klass).to receive(:logger).and_return(instance_logger)
30
+ end
26
31
 
27
32
  context "when connected" do
28
33
  let(:connection) { double("MarchHare Connection") }
@@ -39,6 +44,7 @@ describe LogStash::Inputs::RabbitMQ do
39
44
  allow(connection).to receive(:on_shutdown)
40
45
  allow(connection).to receive(:on_blocked)
41
46
  allow(connection).to receive(:on_unblocked)
47
+ allow(connection).to receive(:close)
42
48
  allow(channel).to receive(:exchange).and_return(exchange)
43
49
  allow(channel).to receive(:queue).and_return(queue)
44
50
  allow(channel).to receive(:prefetch=)
@@ -127,11 +133,193 @@ describe LogStash::Inputs::RabbitMQ do
127
133
  end
128
134
  end
129
135
  end
136
+
137
+ context '#register' do
138
+ let(:rabbitmq_settings) { super().merge(metadata_enabled_override) }
139
+ let(:metadata_enabled_override) { { "metadata_enabled" => metadata_enabled } }
140
+ before do
141
+ instance.register
142
+ end
143
+
144
+ shared_examples('`metadata_enabled => none`') do
145
+ context 'metadata_level' do
146
+ subject(:metadata_level) { instance.metadata_level }
147
+ it { is_expected.to be_empty }
148
+ it { is_expected.to be_frozen }
149
+ end
150
+ end
151
+
152
+ shared_examples('`metadata_enabled => basic`') do
153
+ context 'metadata_level' do
154
+ subject(:metadata_level) { instance.metadata_level }
155
+ it { is_expected.to include :headers }
156
+ it { is_expected.to include :properties }
157
+ it { is_expected.to_not include :payload }
158
+ it { is_expected.to be_frozen }
159
+ end
160
+ end
161
+
162
+ shared_examples("deprecated `metadata_enabled` setting") do |deprecated_value|
163
+ context 'the logger' do
164
+ subject(:logger) { instance_logger }
165
+ it 'receives a useful deprecation warning' do
166
+ expect(logger).to have_received(:warn).with(/Deprecated value `#{Regexp.escape(deprecated_value)}`/)
167
+ end
168
+ end
169
+ end
170
+
171
+ context 'when `metadata_enabled` is `true`' do
172
+ let(:metadata_enabled) { "true" }
173
+ it_behaves_like '`metadata_enabled => basic`'
174
+ include_examples "deprecated `metadata_enabled` setting", "true"
175
+ end
176
+
177
+ context 'when `metadata_enabled` is `false`' do
178
+ let(:metadata_enabled) { "false" }
179
+ it_behaves_like '`metadata_enabled => none`'
180
+ include_examples "deprecated `metadata_enabled` setting", "false"
181
+ end
182
+
183
+ context 'when `metadata_enabled` is not provided' do
184
+ let(:metadata_enabled_override) { Hash.new }
185
+ it_behaves_like '`metadata_enabled => none`'
186
+ end
187
+
188
+ context 'when `metadata_enabled` is `basic`' do
189
+ let(:metadata_enabled) { "basic" }
190
+ include_examples '`metadata_enabled => basic`'
191
+ end
192
+
193
+ context 'when `metadata_enabled` is `none`' do
194
+ let(:metadata_enabled) { "none" }
195
+ include_examples '`metadata_enabled => none`'
196
+ end
197
+
198
+ context 'when `metadata_enabled` is `extended`' do
199
+ let(:metadata_enabled) { "extended" }
200
+ context 'metadata_level' do
201
+ subject(:metadata_level) { instance.metadata_level }
202
+ it { is_expected.to include :headers }
203
+ it { is_expected.to include :properties }
204
+ it { is_expected.to include :payload }
205
+ it { is_expected.to be_frozen }
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "#decorate(event, metadata, data)" do
211
+ let(:rabbitmq_settings) do
212
+ super().merge("metadata_enabled" => metadata_enabled)
213
+ end
214
+ before(:each) { instance.register }
215
+
216
+ let(:metadata) { double("METADATA") }
217
+ let(:headers) { Hash("header_key"=>"header_value") }
218
+ let(:properties) { Hash("property_key"=>"property_value") }
219
+
220
+ let(:data) { %Q({"message"=>"fubar"}\n) }
221
+
222
+ before do
223
+ allow(instance).to receive(:get_headers).with(metadata).and_return(headers)
224
+ allow(instance).to receive(:get_properties).with(metadata).and_return(properties)
225
+ end
226
+
227
+ describe 'the decorated event' do
228
+ subject(:decorated_event) do
229
+ LogStash::Event.new("message"=>"fubar").tap do |e|
230
+ instance.decorate(e, metadata, data)
231
+ end
232
+ end
233
+
234
+ matcher :include_field do |fieldref|
235
+ match do |event|
236
+ # setting `@actual` makes failure messages clearer
237
+ @actual = event.to_hash_with_metadata
238
+
239
+ break false unless event.include?(fieldref)
240
+ break true unless @specific_value
241
+
242
+ values_match?(@expected_value, event.get(fieldref))
243
+ end
244
+ chain :with_value do |expected_value|
245
+ @specific_value = true
246
+ @expected_value = expected_value
247
+ end
248
+ description do
249
+ desc = "include field `#{fieldref}`"
250
+ desc += " with value matching `#{@expected_value.inspect}`" if @specific_value
251
+ desc
252
+ end
253
+ end
254
+
255
+ shared_examples('core decoration features') do
256
+ let(:rabbitmq_settings) do
257
+ super().merge("type" => "decorated_type",
258
+ "add_field" => {"added_field" => "field_value"})
259
+ end
260
+ it 'has been decorated with core decoration features' do
261
+ expect(decorated_event).to include_field("added_field").with_value("field_value")
262
+ expect(decorated_event).to include_field("type").with_value("decorated_type")
263
+ end
264
+ end
265
+
266
+ let(:headers_fieldref) { "[@metadata][rabbitmq_headers]" }
267
+ let(:properties_fieldref) { "[@metadata][rabbitmq_properties]" }
268
+ let(:payload_fieldref) { "[@metadata][rabbitmq_payload]" }
269
+
270
+ shared_examples('`metadata_enabled => none`') do
271
+ it { is_expected.to_not include_field(headers_fieldref) }
272
+ it { is_expected.to_not include_field(properties_fieldref) }
273
+ it { is_expected.to_not include_field(payload_fieldref) }
274
+
275
+ include_examples 'core decoration features'
276
+ end
277
+
278
+ shared_examples('`metadata_enabled => basic`') do
279
+ it { is_expected.to include_field(headers_fieldref).with_value(headers) }
280
+ it { is_expected.to include_field(properties_fieldref).with_value(properties) }
281
+ it { is_expected.to_not include_field(payload_fieldref) }
282
+
283
+ include_examples 'core decoration features'
284
+ end
285
+
286
+ context "with `metadata_enabled => none`" do
287
+ let(:metadata_enabled) { "none" }
288
+ include_examples '`metadata_enabled => none`'
289
+ end
290
+
291
+ context "with `metadata_enabled => basic`" do
292
+ let(:metadata_enabled) { "basic" }
293
+ include_examples '`metadata_enabled => basic`'
294
+ end
295
+
296
+ context 'with `metadata_enabled => extended`' do
297
+ let(:metadata_enabled) { "extended" }
298
+ it { is_expected.to include_field(headers_fieldref).with_value(headers) }
299
+ it { is_expected.to include_field(properties_fieldref).with_value(properties) }
300
+ it { is_expected.to include_field(payload_fieldref).with_value(data) }
301
+ include_examples 'core decoration features'
302
+ end
303
+
304
+ # Deprecated alias: false -> none
305
+ context "with `metadata_enabled => false`" do
306
+ let(:metadata_enabled) { "false" }
307
+ it_behaves_like '`metadata_enabled => none`'
308
+ end
309
+
310
+ # Deprecated alias: true -> basic
311
+ context "with `metadata_enabled => true`" do
312
+ let(:metadata_enabled) { "true" }
313
+ it_behaves_like '`metadata_enabled => basic`'
314
+ end
315
+ end
316
+ end
130
317
  end
131
318
 
132
- describe "with a live server", :integration => true do
319
+ describe "LogStash::Inputs::RabbitMQ with a live server", :integration => true do
133
320
  let(:klass) { LogStash::Inputs::RabbitMQ }
134
- let(:config) { {"host" => "127.0.0.1", "auto_delete" => true, "codec" => "plain", "add_field" => {"[@metadata][foo]" => "bar"} } }
321
+ let(:rabbitmq_host) { ENV["RABBITMQ_HOST"] || "127.0.0.1" }
322
+ let(:config) { {"host" => rabbitmq_host, "auto_delete" => true, "codec" => "plain", "add_field" => {"[@metadata][foo]" => "bar"} } }
135
323
  let(:instance) { klass.new(config) }
136
324
  let(:hare_info) { instance.instance_variable_get(:@hare_info) }
137
325
  let(:output_queue) { Queue.new }
@@ -185,7 +373,7 @@ describe "with a live server", :integration => true do
185
373
  end
186
374
 
187
375
  describe "receiving a message with a queue + exchange specified" do
188
- let(:config) { super.merge("queue" => queue_name, "exchange" => exchange_name, "exchange_type" => "fanout", "metadata_enabled" => true) }
376
+ let(:config) { super.merge("queue" => queue_name, "exchange" => exchange_name, "exchange_type" => "fanout", "metadata_enabled" => "true") }
189
377
  let(:event) { output_queue.pop }
190
378
  let(:exchange) { test_channel.exchange(exchange_name, :type => "fanout") }
191
379
  let(:exchange_name) { "logstash-input-rabbitmq-#{rand(0xFFFFFFFF)}" }
@@ -237,7 +425,7 @@ describe "with a live server", :integration => true do
237
425
  expect(event).to include("@metadata")
238
426
  expect(event.get("@metadata")).to include("rabbitmq_properties")
239
427
 
240
- props = event.get("[@metadata][rabbitmq_properties")
428
+ props = event.get("[@metadata][rabbitmq_properties]")
241
429
  expect(props["app-id"]).to eq(app_id)
242
430
  expect(props["delivery-mode"]).to eq(1)
243
431
  expect(props["exchange"]).to eq(exchange_name)
@@ -274,6 +462,7 @@ describe "with a live server", :integration => true do
274
462
  end
275
463
 
276
464
  describe LogStash::Inputs::RabbitMQ do
465
+ require "logstash/devutils/rspec/shared_examples"
277
466
  it_behaves_like "an interruptible input plugin"
278
467
  end
279
468
  end