logstash-output-rabbitmq 1.0.1-java → 1.1.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
  SHA1:
3
- metadata.gz: 196e13c70544a6e6b7429647f627d2909ca4b5df
4
- data.tar.gz: 3e6871d57fdcb9afde9a531058728e0f57b252f8
3
+ metadata.gz: 89989010433ce0b5c2eb56006cefbb38eb71e465
4
+ data.tar.gz: 004f589a86bbbcb901167a38976c411c2b1d7dab
5
5
  SHA512:
6
- metadata.gz: 28810116ec622545494f279bb88107edf73e74d8f9886f533a8cf51c2e42dd096255ebcffbbefd8ae97b64031a024c6279128923280a53f5ad31e0b6c3fec87b
7
- data.tar.gz: 4088c7f9ebdf63d9458effc176127df3c4fa3a8cd9acb6299d3e60ac47c4efb71f58935be1d49db8a341673bba6e29c5768f284e3a69871551b8938cd9ed4d62
6
+ metadata.gz: 9cce7f5bd69bd54c440b21f0cb1c89879fec275b58c63c17cc30536e9d2c61646e74e33f968f247e7d44dcd99606704168251aa4f54a31cafc4a08c62483d06d
7
+ data.tar.gz: de07d8b894eb6c93bbeb2ed82d70587a5ffd764a2dc924021134e6dae629718c085b496ecfe58f31fce16fd9892e58bfa057c7f9d6c2714b8dbc3e650b0b3138
data/CHANGELOG.md CHANGED
@@ -1,2 +1,5 @@
1
+ * 1.1.0
2
+ - Many internal refactors
3
+ - Bump march hare version to 2.11.0
1
4
  * 1.0.1
2
5
  - Fix connection leakage/failure to reconnect on disconnect
data/CONTRIBUTORS CHANGED
@@ -13,6 +13,7 @@ Contributors:
13
13
  * Pier-Hugues Pellerin (ph)
14
14
  * Richard Pijnenburg (electrical)
15
15
  * avleen
16
+ * ssc-
16
17
 
17
18
  Note: If you've sent us patches, bug reports, or otherwise contributed to
18
19
  Logstash, and you aren't on the list above and want to be, please let us know
@@ -0,0 +1,11 @@
1
+ input {
2
+ stdin {}
3
+ }
4
+
5
+ output {
6
+ rabbitmq {
7
+ host => "127.0.0.1"
8
+ exchange => "foo"
9
+ exchange_type => "topic"
10
+ }
11
+ }
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/outputs/base"
3
3
  require "logstash/namespace"
4
+ require "march_hare"
5
+ require "java"
4
6
 
5
7
  # Push events to a RabbitMQ exchange. Requires RabbitMQ 2.x
6
8
  # or later version (3.x is recommended).
@@ -9,16 +11,12 @@ require "logstash/namespace"
9
11
  #
10
12
  # * http://www.rabbitmq.com/[RabbitMQ]
11
13
  # * http://rubymarchhare.info[March Hare]
12
- # * http://rubybunny.info[Bunny]
13
14
  class LogStash::Outputs::RabbitMQ < LogStash::Outputs::Base
14
15
  EXCHANGE_TYPES = ["fanout", "direct", "topic"]
15
16
 
16
- config_name "rabbitmq"
17
-
17
+ HareInfo = Struct.new(:connection, :channel, :exchange)
18
18
 
19
- #
20
- # Connection
21
- #
19
+ config_name "rabbitmq"
22
20
 
23
21
  # RabbitMQ server address
24
22
  config :host, :validate => :string, :required => true
@@ -44,12 +42,8 @@ class LogStash::Outputs::RabbitMQ < LogStash::Outputs::Base
44
42
  # Enable or disable logging
45
43
  config :debug, :validate => :boolean, :default => false, :deprecated => "Use the logstash --debug flag for this instead."
46
44
 
47
-
48
-
49
- #
50
- # Exchange
51
- #
52
-
45
+ # Try to automatically recovery from broken connections. You almost certainly don't want to override this!!!
46
+ config :automatic_recovery, :validate => :boolean, :default => true
53
47
 
54
48
  # The exchange type (fanout, topic, direct)
55
49
  config :exchange_type, :validate => EXCHANGE_TYPES, :required => true
@@ -68,7 +62,8 @@ class LogStash::Outputs::RabbitMQ < LogStash::Outputs::Base
68
62
  # Should RabbitMQ persist messages to disk?
69
63
  config :persistent, :validate => :boolean, :default => true
70
64
 
71
-
65
+ # Time in seconds to wait before retrying a connection
66
+ config :connect_retry_interval, :validate => :number, :default => 1
72
67
 
73
68
  def initialize(params)
74
69
  params["codec"] = "json" if !params["codec"]
@@ -76,20 +71,108 @@ class LogStash::Outputs::RabbitMQ < LogStash::Outputs::Base
76
71
  super
77
72
  end
78
73
 
79
- # Use MarchHare on JRuby to avoid IO#select CPU spikes
80
- # (see github.com/ruby-amqp/bunny/issues/95).
81
- #
82
- # On MRI, use Bunny.
83
- #
84
- # See http://rubybunny.info and http://rubymarchhare.info
85
- # for the docs.
86
- if RUBY_ENGINE == "jruby"
87
- require "logstash/outputs/rabbitmq/march_hare"
74
+ public
75
+ def register
76
+ connect!
77
+ @codec.on_event(&method(:publish))
78
+ end
79
+
80
+ public
81
+ def receive(event)
82
+ return unless output?(event)
83
+
84
+ @codec.encode(event)
85
+ rescue StandardError => e
86
+ @logger.warn("Error encoding event", :exception => e, :event => event)
87
+ end
88
+
89
+ private
90
+ def publish(event, message)
91
+ @hare_info.exchange.publish(message, :routing_key => event.sprintf(@key), :properties => { :persistent => @persistent })
92
+ rescue MarchHare::Exception, IOError, com.rabbitmq.client.AlreadyClosedException => e
93
+ return if terminating?
94
+
95
+ @logger.error("Error while publishing. Will retry.",
96
+ :message => e.message,
97
+ :exception => e.class,
98
+ :backtrace => e.backtrace)
99
+
100
+ sleep_for_retry
101
+ connect!
102
+ retry
103
+ end
88
104
 
89
- include MarchHareImpl
90
- else
91
- require "logstash/outputs/rabbitmq/bunny"
105
+ public
106
+ def to_s
107
+ return "<LogStash::RabbitMQ::Output: amqp://#{@user}@#{@host}:#{@port}#{@vhost}/#{@exchange_type}/#{@exchange}\##{@key}>"
108
+ end
109
+
110
+ public
111
+ def teardown
112
+ @hare_info.connection.close if connection_open?
113
+
114
+ finished
115
+ end
116
+
117
+ private
118
+ def settings
119
+ return @settings if @settings
120
+
121
+ s = {
122
+ :vhost => @vhost,
123
+ :host => @host,
124
+ :port => @port,
125
+ :user => @user,
126
+ :automatic_recovery => @automatic_recovery,
127
+ :pass => @password ? @password.value : "guest",
128
+ }
129
+ s[:tls] = @ssl if @ssl
130
+ @settings = s
131
+ end
132
+
133
+ private
134
+ def connect
135
+ @logger.debug("Connecting to RabbitMQ. Settings: #{settings.inspect}, queue: #{@queue.inspect}")
136
+
137
+
138
+ connection = MarchHare.connect(settings)
139
+ connection.on_blocked { @logger.warn("RabbitMQ output blocked! Check your RabbitMQ instance!") }
140
+ connection.on_unblocked { @logger.warn("RabbitMQ output unblocked!") }
141
+
142
+ channel = connection.create_channel
143
+ @logger.info("Connected to RabbitMQ at #{settings[:host]}")
144
+
145
+ @logger.debug("Declaring an exchange", :name => @exchange,
146
+ :type => @exchange_type, :durable => @durable)
147
+
148
+ exchange = channel.exchange(@exchange, :type => @exchange_type.to_sym, :durable => @durable)
149
+ @logger.debug("Exchange declared")
150
+
151
+ HareInfo.new(connection, channel, exchange)
152
+ end
153
+
154
+ private
155
+ def connect!
156
+ @hare_info = connect() unless connection_open?
157
+ rescue MarchHare::Exception => e
158
+ return if terminating?
159
+
160
+ @logger.error("RabbitMQ connection error, will retry.",
161
+ :message => e.message,
162
+ :exception => e.class.name,
163
+ :backtrace => e.backtrace)
164
+
165
+ sleep_for_retry
166
+ retry
167
+ end
168
+
169
+ private
170
+ def connection_open?
171
+ @hare_info && @hare_info.connection && @hare_info.connection.open?
172
+ end
92
173
 
93
- include BunnyImpl
174
+ private
175
+ def sleep_for_retry
176
+ sleep @connect_retry_interval
94
177
  end
95
- end # class LogStash::Outputs::RabbitMQ
178
+ end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-output-rabbitmq'
4
- s.version = '1.0.1'
4
+ s.version = '1.1.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Push events to a RabbitMQ exchange"
7
7
  s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
@@ -22,12 +22,8 @@ Gem::Specification.new do |s|
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core", '>= 1.4.0', '< 2.0.0'
24
24
 
25
- if RUBY_PLATFORM == 'java'
26
- s.platform = RUBY_PLATFORM
27
- s.add_runtime_dependency 'march_hare', ['~> 2.5.1'] #(MIT license)
28
- else
29
- s.add_runtime_dependency 'bunny', ['>= 1.6.0'] #(MIT license)
30
- end
25
+ s.platform = RUBY_PLATFORM
26
+ s.add_runtime_dependency 'march_hare', ['~> 2.11.0'] #(MIT license)
31
27
 
32
28
  s.add_development_dependency 'logstash-devutils'
33
29
  s.add_development_dependency 'logstash-input-generator'
@@ -4,129 +4,160 @@ require "logstash/pipeline"
4
4
  require "logstash/outputs/rabbitmq"
5
5
 
6
6
  describe LogStash::Outputs::RabbitMQ do
7
+ let(:klass) { LogStash::Outputs::RabbitMQ }
8
+ let(:host) { "localhost" }
9
+ let(:port) { 5672 }
10
+ let(:exchange_type) { "topic" }
11
+ let(:exchange) { "myexchange" }
12
+ let(:key) { "mykey" }
13
+ let(:persistent) { true }
14
+ let(:settings) {
15
+ {
16
+ "host" => host,
17
+ "port" => port,
18
+ "exchange_type" => exchange_type,
19
+ "exchange" => exchange,
20
+ "key" => key,
21
+ "persistent" => persistent
22
+ }
23
+ }
24
+ let(:instance) { klass.new(settings) }
25
+ let(:hare_info) { instance.instance_variable_get(:@hare_info) }
7
26
 
8
- describe "rabbitmq static key" do
9
- config <<-END
10
- input {
11
- generator {
12
- count => 1
13
- }
14
- }
15
- output {
16
- rabbitmq {
17
- host => "localhost"
18
- exchange_type => "topic"
19
- exchange => "foo"
20
- key => "bar"
21
- }
22
- }
23
- END
24
-
25
- it "should use defined key" do
26
- exchange = double("exchange")
27
- expect_any_instance_of(LogStash::Outputs::RabbitMQ).to receive(:connect).and_return(nil)
28
- expect_any_instance_of(LogStash::Outputs::RabbitMQ).to receive(:declare_exchange).and_return(exchange)
29
-
30
- expect(exchange).to receive(:publish).with(an_instance_of(String), {:routing_key => "bar", :properties => {:persistent => true}})
31
-
32
- # we need to set expectations before running the pipeline, this is why we cannot use the
33
- # "agent" spec construct here so we do it manually
34
- pipeline = LogStash::Pipeline.new(config)
35
- pipeline.run
36
- end
37
-
38
- end
27
+ context "when connected" do
28
+ let(:connection) { double("MarchHare Connection") }
29
+ let(:channel) { double("Channel") }
30
+ let(:exchange) { double("Exchange") }
39
31
 
40
- describe "rabbitmq key with dynamic field" do
41
- config <<-END
42
- input {
43
- generator {
44
- count => 1
45
- add_field => ["foo", "bar"]
46
- }
47
- }
48
- output {
49
- rabbitmq {
50
- host => "localhost"
51
- exchange_type => "topic"
52
- exchange => "foo"
53
- key => "%{foo}"
54
- }
55
- }
56
- END
57
-
58
- it "should populate the key with the content of the event foo field" do
59
- exchange = double("exchange")
60
- expect_any_instance_of(LogStash::Outputs::RabbitMQ).to receive(:connect).and_return(nil)
61
- expect_any_instance_of(LogStash::Outputs::RabbitMQ).to receive(:declare_exchange).and_return(exchange)
62
-
63
- expect(exchange).to receive(:publish).with(an_instance_of(String), {:routing_key => "bar", :properties => {:persistent => true}})
64
-
65
- # we need to set expectations before running the pipeline, this is why we cannot use the
66
- # "agent" spec construct here so we do it manually
67
- pipeline = LogStash::Pipeline.new(config)
68
- pipeline.run
32
+ before do
33
+ allow(instance).to receive(:connect!).and_call_original
34
+ allow(::MarchHare).to receive(:connect).and_return(connection)
35
+ allow(connection).to receive(:create_channel).and_return(channel)
36
+ allow(connection).to receive(:on_blocked)
37
+ allow(connection).to receive(:on_unblocked)
38
+ allow(channel).to receive(:exchange).and_return(exchange)
39
+
40
+ instance.register
69
41
  end
70
42
 
71
- end
43
+ describe "#register" do
44
+ subject { instance }
72
45
 
73
- # TODO: Redo all this
74
- # This is a crazy test to fix an urgent bug. It tests that we actually to change the
75
- # store exchange value when an exception happens
76
- # This should be a small number of lines, but until we refactor we must jump through hoops
77
- # to put the plugin in the proper state and extract the proper state to test
78
- describe "retrying a publish" do
79
- let(:settings) {
80
- {
81
- "host" => "localhost",
82
- "exchange_type" => "topic",
83
- "exchange" => "foo",
84
- "key" => "%{foo}"
85
- }
86
- }
87
- let(:event) { LogStash::Event.new("foo" => "bar")}
46
+ it "should create cleanly" do
47
+ expect(subject).to be_a(klass)
48
+ end
88
49
 
89
- subject { LogStash::Outputs::RabbitMQ.new(settings) }
50
+ it "should connect" do
51
+ expect(subject).to have_received(:connect!).once
52
+ end
53
+ end
90
54
 
91
- before do
92
- allow(subject).to receive(:connect) {
93
- subject.instance_variable_get(:@connected).set(true)
94
- }
55
+ describe "#connect!" do
56
+ subject { hare_info }
95
57
 
96
- exchange_invocation = 0
58
+ it "should set @hare_info correctly" do
59
+ expect(subject).to be_a(LogStash::Outputs::RabbitMQ::HareInfo)
60
+ end
97
61
 
98
- @most_recent_exchange = nil
62
+ it "should set @connection correctly" do
63
+ expect(subject.connection).to eql(connection)
64
+ end
99
65
 
100
- allow(subject).to receive(:declare_exchange) do
101
- exchange_invocation += 1
102
- @most_recent_exchange = double("exchange #{exchange_invocation}")
66
+ it "should set the channel correctly" do
67
+ expect(subject.channel).to eql(channel)
103
68
  end
104
69
 
105
- subject.register
70
+ it "should set the exchange correctly" do
71
+ expect(subject.exchange).to eql(exchange)
72
+ end
106
73
  end
107
74
 
108
- context "when the connection aborts once" do
109
- before do
110
- i = 0
111
- allow(subject).to receive(:attempt_publish_serialized) do
112
- i+=1
113
- if i == 1 # Raise an exception once
114
- raise MarchHare::Exception, "First"
115
- else
116
- "nope"
117
- end
75
+ describe "#publish_encoded" do
76
+ let(:event) { LogStash::Event.new("foo" => "bar") }
77
+ let(:sprinted_key) { double("sprinted key") }
78
+ let(:encoded_event) { LogStash::Json.dump(event) }
79
+
80
+ describe "issuing the publish" do
81
+ before do
82
+ allow(exchange).to receive(:publish).with(any_args)
83
+ allow(event).to receive(:sprintf).with(key).and_return(sprinted_key)
84
+ instance.send(:publish, event, encoded_event)
118
85
  end
119
86
 
120
- subject.publish_serialized(event, "hello")
87
+ it "should send the correct message" do
88
+ expect(exchange).to have_received(:publish).with(encoded_event, anything)
89
+ end
90
+
91
+ it "should send the correct metadata" do
92
+ expected_metadata = {:routing_key => sprinted_key, :properties => {:persistent => persistent }}
93
+
94
+ expect(exchange).to have_received(:publish).with(anything, expected_metadata)
95
+ end
121
96
  end
122
97
 
123
- it "should re-declare the exchange" do
124
- expect(subject).to have_received(:declare_exchange).twice
98
+ context "when a MarchHare::Exception is encountered" do
99
+ before do
100
+ i = 0
101
+ allow(instance).to receive(:connect!)
102
+ allow(instance).to receive(:sleep_for_retry)
103
+ allow(exchange).to receive(:publish).with(any_args) do
104
+ i += 1
105
+ raise(MarchHare::Exception, "foo") if i == 1
106
+ end
107
+
108
+ instance.send(:publish, event, encoded_event)
109
+ end
110
+
111
+ it "should execute publish twice due to a retry" do
112
+ expect(exchange).to have_received(:publish).twice
113
+ end
114
+
115
+ it "should sleep for the retry" do
116
+ expect(instance).to have_received(:sleep_for_retry).once
117
+ end
118
+
119
+ it "should send the correct message (twice)" do
120
+ expect(exchange).to have_received(:publish).with(encoded_event, anything).twice
121
+ end
122
+
123
+ it "should send the correct metadata (twice)" do
124
+ expected_metadata = {:routing_key => event.sprintf(key), :properties => {:persistent => persistent }}
125
+
126
+ expect(exchange).to have_received(:publish).with(anything, expected_metadata).twice
127
+ end
125
128
  end
129
+ end
130
+ end
131
+
132
+ # If the connection encounters an exception during its initial
133
+ # connection attempt we must handle that. Subsequent errors should be
134
+ # handled by the automatic retry mechanism built-in to MarchHare
135
+ describe "initial connection exceptions" do
136
+ subject { instance }
137
+
138
+ before do
139
+ allow(subject).to receive(:sleep_for_retry)
140
+
126
141
 
127
- it "should set the exchange to the second double" do
128
- expect(subject.instance_variable_get(:@x)).to eql(@most_recent_exchange)
142
+ i = 0
143
+ allow(subject).to receive(:connect) do
144
+ i += 1
145
+ if i == 1
146
+ raise(MarchHare::ConnectionRefused, "Error!")
147
+ else
148
+ double("connection")
149
+ end
129
150
  end
151
+
152
+ subject.send(:connect!)
153
+ end
154
+
155
+ it "should retry its connection when conn fails" do
156
+ expect(subject).to have_received(:connect).twice
157
+ end
158
+
159
+ it "should sleep between retries" do
160
+ expect(subject).to have_received(:sleep_for_retry).once
130
161
  end
131
162
  end
132
163
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-rabbitmq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-16 00:00:00.000000000 Z
11
+ date: 2015-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logstash-core
@@ -36,12 +36,12 @@ dependencies:
36
36
  requirements:
37
37
  - - ~>
38
38
  - !ruby/object:Gem::Version
39
- version: 2.5.1
39
+ version: 2.11.0
40
40
  requirement: !ruby/object:Gem::Requirement
41
41
  requirements:
42
42
  - - ~>
43
43
  - !ruby/object:Gem::Version
44
- version: 2.5.1
44
+ version: 2.11.0
45
45
  prerelease: false
46
46
  type: :runtime
47
47
  - !ruby/object:Gem::Dependency
@@ -100,10 +100,8 @@ files:
100
100
  - NOTICE.TXT
101
101
  - README.md
102
102
  - Rakefile
103
+ - examples/sample.conf
103
104
  - lib/logstash/outputs/rabbitmq.rb
104
- - lib/logstash/outputs/rabbitmq/bunny.rb
105
- - lib/logstash/outputs/rabbitmq/hot_bunnies.rb
106
- - lib/logstash/outputs/rabbitmq/march_hare.rb
107
105
  - logstash-output-rabbitmq.gemspec
108
106
  - spec/outputs/rabbitmq_spec.rb
109
107
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
@@ -1,138 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "logstash/json"
4
-
5
- class LogStash::Outputs::RabbitMQ
6
- module BunnyImpl
7
-
8
- #
9
- # API
10
- #
11
-
12
- def register
13
- require "bunny"
14
-
15
- @logger.info("Registering output", :plugin => self)
16
-
17
- connect
18
- declare_exchange
19
- end # def register
20
-
21
-
22
- def receive(event)
23
- return unless output?(event)
24
-
25
- @logger.debug("Sending event", :destination => to_s, :event => event, :key => key)
26
- key = event.sprintf(@key) if @key
27
-
28
- begin
29
- publish_serialized(event.to_json, key)
30
- rescue LogStash::Json::GeneratorError => e
31
- @logger.warn("Trouble converting event to JSON", :exception => e,
32
- :event => event)
33
- end
34
- end
35
-
36
- def publish_serialized(message, key = @key)
37
- begin
38
- if @x
39
- @x.publish(message, :persistent => @persistent, :routing_key => key)
40
- else
41
- @logger.warn("Tried to send a message, but not connected to RabbitMQ yet.")
42
- end
43
- rescue Bunny::NetworkFailure, Bunny::ConnectionClosedError, Bunny::ConnectionLevelException, Bunny::TCPConnectionFailed => e
44
- n = Bunny::Session::DEFAULT_NETWORK_RECOVERY_INTERVAL * 2
45
-
46
- @logger.error("RabbitMQ connection error: #{e.message}. Will attempt to reconnect in #{n} seconds...",
47
- :exception => e,
48
- :backtrace => e.backtrace)
49
- return if terminating?
50
-
51
- sleep n
52
- connect
53
- declare_exchange
54
- retry
55
- end
56
- end
57
-
58
- def to_s
59
- return "amqp://#{@user}@#{@host}:#{@port}#{@vhost}/#{@exchange_type}/#{@exchange}\##{@key}"
60
- end
61
-
62
- def teardown
63
- @conn.close if @conn && @conn.open?
64
- @conn = nil
65
-
66
- finished
67
- end
68
-
69
-
70
-
71
- #
72
- # Implementation
73
- #
74
-
75
- def connect
76
- @vhost ||= Bunny::DEFAULT_HOST
77
- # 5672. Will be switched to 5671 by Bunny if TLS is enabled.
78
- @port ||= AMQ::Protocol::DEFAULT_PORT
79
- @routing_key ||= "#"
80
-
81
- @settings = {
82
- :vhost => @vhost,
83
- :host => @host,
84
- :port => @port,
85
- :automatically_recover => false
86
- }
87
- @settings[:user] = @user || Bunny::DEFAULT_USER
88
- @settings[:pass] = if @password
89
- @password.value
90
- else
91
- Bunny::DEFAULT_PASSWORD
92
- end
93
-
94
- @settings[:log_level] = if @debug || @logger.debug?
95
- :debug
96
- else
97
- :error
98
- end
99
-
100
- @settings[:tls] = @ssl if @ssl
101
- @settings[:verify_ssl] = @verify_ssl if @verify_ssl
102
-
103
- proto = if @ssl
104
- "amqp"
105
- else
106
- "amqps"
107
- end
108
- @connection_url = "#{proto}://#{@user}@#{@host}:#{@port}#{vhost}/#{@queue}"
109
-
110
- begin
111
- @conn = Bunny.new(@settings)
112
-
113
- @logger.debug("Connecting to RabbitMQ. Settings: #{@settings.inspect}, queue: #{@queue.inspect}")
114
- return if terminating?
115
- @conn.start
116
-
117
- @ch = @conn.create_channel
118
- @logger.info("Connected to RabbitMQ at #{@settings[:host]}")
119
- rescue Bunny::NetworkFailure, Bunny::ConnectionClosedError, Bunny::ConnectionLevelException, Bunny::TCPConnectionFailed => e
120
- n = Bunny::Session::DEFAULT_NETWORK_RECOVERY_INTERVAL * 2
121
-
122
- @logger.error("RabbitMQ connection error: #{e.message}. Will attempt to reconnect in #{n} seconds...",
123
- :exception => e,
124
- :backtrace => e.backtrace)
125
- return if terminating?
126
-
127
- sleep n
128
- retry
129
- end
130
- end
131
-
132
- def declare_exchange
133
- @logger.debug("Declaring an exchange", :name => @exchange, :type => @exchange_type,
134
- :durable => @durable)
135
- @x = @ch.exchange(@exchange, :type => @exchange_type.to_sym, :durable => @durable)
136
- end
137
- end # BunnyImpl
138
- end # LogStash::Outputs::RabbitMQ
@@ -1 +0,0 @@
1
- require "logstash/outputs/rabbitmq/march_hare"
@@ -1,142 +0,0 @@
1
- # encoding: utf-8
2
- class LogStash::Outputs::RabbitMQ
3
- module MarchHareImpl
4
-
5
-
6
- #
7
- # API
8
- #
9
-
10
- def register
11
- require "march_hare"
12
- require "java"
13
-
14
- @logger.info("Registering output", :plugin => self)
15
-
16
- @connected = java.util.concurrent.atomic.AtomicBoolean.new
17
-
18
- connect
19
- @x = declare_exchange
20
-
21
- @connected.set(true)
22
-
23
- @codec.on_event(&method(:publish_serialized))
24
- end
25
-
26
-
27
- def receive(event)
28
- return unless output?(event)
29
-
30
- begin
31
- @codec.encode(event)
32
- rescue => e
33
- @logger.warn("Error encoding event", :exception => e, :event => event)
34
- end
35
- end
36
-
37
- def publish_serialized(event, message)
38
- attempt_publish_serialized(event, message)
39
- rescue MarchHare::Exception, IOError, com.rabbitmq.client.AlreadyClosedException => e
40
- @connected.set(false)
41
- n = 10
42
-
43
- @logger.error("RabbitMQ connection error: #{e.message}. Will attempt to reconnect in #{n} seconds...",
44
- :exception => e,
45
- :backtrace => e.backtrace)
46
- return if terminating?
47
-
48
- sleep n
49
-
50
- connect
51
- @x = declare_exchange
52
- retry
53
- end
54
-
55
- def attempt_publish_serialized(event, message)
56
- if @connected.get
57
- @x.publish(message, :routing_key => event.sprintf(@key), :properties => { :persistent => @persistent })
58
- else
59
- @logger.warn("Tried to send a message, but not connected to RabbitMQ.")
60
- end
61
- end
62
-
63
- def to_s
64
- return "amqp://#{@user}@#{@host}:#{@port}#{@vhost}/#{@exchange_type}/#{@exchange}\##{@key}"
65
- end
66
-
67
- def teardown
68
- @connected.set(false)
69
- @conn.close if @conn && @conn.open?
70
- @conn = nil
71
-
72
- finished
73
- end
74
-
75
-
76
-
77
- #
78
- # Implementation
79
- #
80
-
81
- def connect
82
- return if terminating?
83
-
84
- @vhost ||= "127.0.0.1"
85
- # 5672. Will be switched to 5671 by Bunny if TLS is enabled.
86
- @port ||= 5672
87
-
88
- @settings = {
89
- :vhost => @vhost,
90
- :host => @host,
91
- :port => @port,
92
- :user => @user,
93
- :automatic_recovery => false
94
- }
95
- @settings[:pass] = if @password
96
- @password.value
97
- else
98
- "guest"
99
- end
100
-
101
- @settings[:tls] = @ssl if @ssl
102
- proto = if @ssl
103
- "amqp"
104
- else
105
- "amqps"
106
- end
107
- @connection_url = "#{proto}://#{@user}@#{@host}:#{@port}#{vhost}/#{@queue}"
108
-
109
- begin
110
- @conn = MarchHare.connect(@settings) unless @conn && @conn.open?
111
-
112
- @logger.debug("Connecting to RabbitMQ. Settings: #{@settings.inspect}, queue: #{@queue.inspect}")
113
-
114
- @ch = @conn.create_channel
115
- @logger.info("Connected to RabbitMQ at #{@settings[:host]}")
116
- rescue MarchHare::Exception => e
117
- @connected.set(false)
118
- n = 10
119
-
120
- @logger.error("RabbitMQ connection error: #{e.message}. Will attempt to reconnect in #{n} seconds...",
121
- :exception => e,
122
- :backtrace => e.backtrace)
123
- return if terminating?
124
-
125
- sleep n
126
- retry
127
- end
128
- end
129
-
130
- def declare_exchange
131
- @logger.debug("Declaring an exchange", :name => @exchange, :type => @exchange_type,
132
- :durable => @durable)
133
- x = @ch.exchange(@exchange, :type => @exchange_type.to_sym, :durable => @durable)
134
-
135
- # sets @connected to true during recovery. MK.
136
- @connected.set(true)
137
-
138
- x
139
- end
140
-
141
- end # MarchHareImpl
142
- end