logstash-input-lumberjack 1.0.3 → 1.0.4

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: 13d047624d0d97f3184fec85ee0d5a3f9a1fd274
4
- data.tar.gz: 82d47b698574bd27368c49237c61e67c4bfcd5f7
3
+ metadata.gz: 12b4f41cf358aa9dd6e7e398744f74c780371863
4
+ data.tar.gz: 91ad7e8d873cbfd3f98d310ac9169ac963ca19e2
5
5
  SHA512:
6
- metadata.gz: a8109970459a4c12f5ee11feb4b0aa12c668da8f840e9ca371e7f448da447993894964bfb1f2310c8766d7e8dd304bf0b30c088a947ecef21745a51d3caf44f9
7
- data.tar.gz: 731c6a93b576bc7d221a9aaa66ee965ba12e3be7fe4d1182468195aaa9fb93483d071e136fc004326487af2a03141909981ef17ac2341cc459e82a92aa2b8a27
6
+ metadata.gz: bd7ec8da4baf22a8c947c9bffcf44aa94db2bfcb3405f59f4ed685b7e34054f30706033f64335f397c92ed8afa0213e62f4606c4f96fe08409a8fdaf3603be3a
7
+ data.tar.gz: 6b275397ba9b3917f4f12b5f7b4bc6b5b3caea0cc4edd695b443ea00fd8b5a308aab0eb39b5f99ceec46e22a61de841ce8544325927a89f0370333fdf4cc2fe6
@@ -4,8 +4,12 @@ require "cabin"
4
4
  module LogStash
5
5
  # Largely inspired by Martin's fowler circuit breaker
6
6
  class CircuitBreaker
7
+ # Raised when too many errors has occured and we refuse to execute the block
7
8
  class OpenBreaker < StandardError; end
8
9
 
10
+ # Raised when we catch an error that we count
11
+ class HalfOpenBreaker < StandardError; end
12
+
9
13
  # Error threshold before opening the breaker,
10
14
  # if the breaker is open it wont execute the code.
11
15
  DEFAULT_ERROR_THRESHOLD = 5
@@ -48,6 +52,8 @@ module LogStash
48
52
  rescue *@exceptions => e
49
53
  logger.warn("CircuitBreaker::rescuing exceptions", :name => @name, :exception => e.class)
50
54
  increment_errors(e)
55
+
56
+ raise HalfOpenBreaker
51
57
  end
52
58
 
53
59
  def closed?
@@ -31,10 +31,13 @@ class LogStash::Inputs::Lumberjack < LogStash::Inputs::Base
31
31
 
32
32
  # This setting no longer has any effect and will be removed in a future release.
33
33
  config :max_clients, :validate => :number, :deprecated => "This setting no longer has any effect. See https://github.com/logstash-plugins/logstash-input-lumberjack/pull/12 for the history of this change"
34
+
35
+ # The number of seconds before we raise a timeout,
36
+ # this option is useful to control how much time to wait if something is blocking the pipeline.
37
+ config :congestion_threshold, :validate => :number, :default => 5
34
38
 
35
39
  # TODO(sissel): Add CA to authenticate clients with.
36
-
37
- BUFFERED_QUEUE_SIZE = 20
40
+ BUFFERED_QUEUE_SIZE = 1
38
41
  RECONNECT_BACKOFF_SLEEP = 0.5
39
42
 
40
43
  def register
@@ -66,52 +69,52 @@ class LogStash::Inputs::Lumberjack < LogStash::Inputs::Base
66
69
  start_buffer_broker(output_queue)
67
70
 
68
71
  while true do
69
- begin
70
- # Wrapping the accept call into a CircuitBreaker
71
- if @circuit_breaker.closed?
72
- connection = @lumberjack.accept # Blocking call that creates a new connection
72
+ # Wrappingu the accept call into a CircuitBreaker
73
+ if @circuit_breaker.closed?
74
+ connection = @lumberjack.accept # Blocking call that creates a new connection
73
75
 
74
- invoke(connection, codec.clone) do |_codec, line, fields|
75
- _codec.decode(line) do |event|
76
+ invoke(connection, @codec.clone) do |_codec, line, fields|
77
+ _codec.decode(line) do |event|
78
+ begin
76
79
  decorate(event)
77
80
  fields.each { |k,v| event[k] = v; v.force_encoding(Encoding::UTF_8) }
78
-
79
- @circuit_breaker.execute { @buffered_queue << event }
81
+ @circuit_breaker.execute { @buffered_queue.push(event, @congestion_threshold) }
82
+ rescue => e
83
+ raise e
80
84
  end
81
85
  end
82
- else
83
- @logger.warn("Lumberjack input: the pipeline is blocked, temporary refusing new connection.")
84
- sleep(RECONNECT_BACKOFF_SLEEP)
85
86
  end
86
- # When too many errors happen inside the circuit breaker it will throw
87
- # this exception and start refusing connection, we need to catch it but
88
- # it's safe to ignore.
89
- rescue LogStash::CircuitBreaker::OpenBreaker => e
87
+ else
88
+ @logger.warn("Lumberjack input: the pipeline is blocked, temporary refusing new connection.")
89
+ sleep(RECONNECT_BACKOFF_SLEEP)
90
90
  end
91
91
  end
92
92
  rescue LogStash::ShutdownSignal
93
93
  @logger.info("Lumberjack input: received ShutdownSignal")
94
- rescue => e
95
- @logger.error("Lumberjack input: unhandled exception", :exception => e, :backtrace => e.backtrace)
96
94
  ensure
97
95
  shutdown(output_queue)
98
96
  end # def run
99
97
 
100
- private
101
- def accept(&block)
102
- connection = @lumberjack.accept # Blocking call that creates a new connection
103
- block.call(connection, @codec.clone)
104
- end
105
-
106
98
  private
107
99
  def invoke(connection, codec, &block)
108
100
  @threadpool.post do
109
101
  begin
102
+ # If any errors occur in from the events the connection should be closed in the
103
+ # library ensure block and the exception will be handled here
110
104
  connection.run do |fields|
111
105
  block.call(codec, fields.delete("line"), fields)
112
106
  end
113
- rescue => e
114
- @logger.error("Exception in lumberjack input thread", :exception => e)
107
+
108
+ # When too many errors happen inside the circuit breaker it will throw
109
+ # this exception and start refusing connection. The bubbling of theses
110
+ # exceptions make sure that the lumberjack library will close the current
111
+ # connection which will force the client to reconnect and restransmit
112
+ # his payload.
113
+ rescue LogStash::CircuitBreaker::OpenBreaker,
114
+ LogStash::CircuitBreaker::HalfOpenBreaker => e
115
+ logger.warn("Lumberjack input: The circuit breaker has detected a slowdown or stall in the pipeline, the input is closing the current connection and rejecting new connection until the pipeline recover.", :exception => e.class)
116
+ rescue => e # If we have a malformed packet we should handle that so the input doesn't crash completely.
117
+ @logger.error("Lumberjack input: unhandled exception", :exception => e, :backtrace => e.backtrace)
115
118
  end
116
119
  end
117
120
  end
@@ -9,7 +9,7 @@ module LogStash
9
9
  class SizedQueueTimeout
10
10
  class TimeoutError < StandardError; end
11
11
 
12
- DEFAULT_TIMEOUT = 2 # in seconds
12
+ DEFAULT_TIMEOUT = 5 # in seconds
13
13
 
14
14
  def initialize(max_size, options = {})
15
15
  # `concurrent-ruby` are deprecating the `Condition`
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-lumberjack'
4
- s.version = '1.0.3'
4
+ s.version = '1.0.4'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Receive events using the lumberjack protocol."
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"
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency "logstash-core", '>= 1.4.0', '< 2.0.0'
24
24
 
25
25
  s.add_runtime_dependency 'logstash-codec-plain'
26
- s.add_runtime_dependency 'jls-lumberjack', ['>=0.0.23']
26
+ s.add_runtime_dependency 'jls-lumberjack', ['>=0.0.24']
27
27
  s.add_runtime_dependency "concurrent-ruby"
28
28
 
29
29
  s.add_development_dependency 'logstash-devutils'
@@ -7,6 +7,7 @@ require "logstash/codecs/multiline"
7
7
  require "logstash/event"
8
8
  require "lumberjack/client"
9
9
 
10
+ Thread.abort_on_exception = true
10
11
  describe LogStash::Inputs::Lumberjack do
11
12
  let(:connection) { double("connection") }
12
13
  let(:certificate) { LogStashTest.certificate }
@@ -41,7 +42,7 @@ describe LogStash::Inputs::Lumberjack do
41
42
  let(:codec) { LogStash::Codecs::Multiline.new("pattern" => '\n', "what" => "previous") }
42
43
  it "clone the codec per connection" do
43
44
  expect(lumberjack.codec).to receive(:clone).once
44
- expect(lumberjack).to receive(:invoke).and_throw(:msg)
45
+ expect(lumberjack).to receive(:invoke) { break }
45
46
  lumberjack.run(queue)
46
47
  end
47
48
  end
@@ -14,33 +14,55 @@ describe LogStash::CircuitBreaker do
14
14
 
15
15
  subject { LogStash::CircuitBreaker.new("testing", options) }
16
16
 
17
+ context "when the breaker is closed" do
18
+ it "closed by default" do
19
+ expect(subject.closed?).to eq(true)
20
+ end
17
21
 
18
- it "closed by default" do
19
- expect(subject.closed?).to eq(true)
20
- end
21
-
22
- context "when having too many errors" do
23
- let(:future_time) { Time.now + 3600 }
24
- before do
25
- subject.execute do
26
- raise DummyErrorTest
27
- end
22
+ it "always raise an exception if an errors occur" do
23
+ expect {
24
+ subject.execute do
25
+ raise DummyErrorTest
26
+ end
27
+ }.to raise_error(LogStash::CircuitBreaker::HalfOpenBreaker)
28
28
  end
29
29
 
30
- it "raised an exception if we have too many errors" do
30
+ it "open if we pass the errors threadshold" do
31
+ expect {
32
+ subject.execute do
33
+ raise DummyErrorTest
34
+ end
35
+ }.to raise_error(LogStash::CircuitBreaker::HalfOpenBreaker)
36
+
31
37
  expect {
32
38
  subject.execute do
33
39
  raise DummyErrorTest
34
40
  end
35
41
  }.to raise_error(LogStash::CircuitBreaker::OpenBreaker)
36
42
  end
43
+ end
44
+
45
+ context "When the breaker is open" do
46
+ let(:future_time) { Time.now + 3600 }
47
+
48
+ before do
49
+ # trip the breaker
50
+ (error_threshold + 1).times do
51
+ begin
52
+ subject.execute do
53
+ raise DummyErrorTest
54
+ end
55
+ rescue
56
+ end
57
+ end
58
+ end
37
59
 
38
- it "sets the breaker to open" do
60
+ it "#closed? should return false" do
39
61
  expect(subject.closed?).to eq(false)
40
62
  end
41
63
 
42
64
  it "resets the breaker after the time before retry" do
43
- expect(Time).to receive(:now).at_least(1).and_return(future_time)
65
+ expect(Time).to receive(:now).at_least(2).and_return(future_time)
44
66
  expect(subject.closed?).to eq(true)
45
67
  end
46
68
 
@@ -51,7 +73,7 @@ describe LogStash::CircuitBreaker do
51
73
  subject.execute do
52
74
  runned = true
53
75
  end
54
- rescue LogStash::CircuitBreaker::OpenBreaker
76
+ rescue LogStash::CircuitBreaker::OpenBreaker
55
77
  end
56
78
 
57
79
  expect(runned).to eq(false)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-lumberjack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-31 00:00:00.000000000 Z
11
+ date: 2015-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logstash-core
@@ -50,12 +50,12 @@ dependencies:
50
50
  requirements:
51
51
  - - '>='
52
52
  - !ruby/object:Gem::Version
53
- version: 0.0.23
53
+ version: 0.0.24
54
54
  requirement: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - '>='
57
57
  - !ruby/object:Gem::Version
58
- version: 0.0.23
58
+ version: 0.0.24
59
59
  prerelease: false
60
60
  type: :runtime
61
61
  - !ruby/object:Gem::Dependency