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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/LICENSE +199 -10
- data/docs/input-rabbitmq.asciidoc +52 -36
- data/docs/output-rabbitmq.asciidoc +4 -2
- data/lib/logstash/inputs/rabbitmq.rb +70 -12
- data/lib/logstash/outputs/rabbitmq.rb +71 -7
- data/lib/logstash/plugin_mixins/rabbitmq_connection.rb +7 -2
- data/logstash-integration-rabbitmq.gemspec +2 -2
- data/spec/inputs/rabbitmq_spec.rb +194 -5
- data/spec/outputs/rabbitmq_spec.rb +55 -6
- data/spec/plugin_mixins/rabbitmq_connection_spec.rb +40 -19
- metadata +7 -7
|
@@ -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 =>
|
|
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
|
|
190
|
-
:class
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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 =>
|
|
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.
|
|
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
|
-
:
|
|
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.
|
|
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
|
-
|
|
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(:
|
|
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
|