logstash-input-lumberjack 1.0.3 → 1.0.4
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/lib/logstash/circuit_breaker.rb +6 -0
- data/lib/logstash/inputs/lumberjack.rb +30 -27
- data/lib/logstash/sized_queue_timeout.rb +1 -1
- data/logstash-input-lumberjack.gemspec +2 -2
- data/spec/inputs/lumberjack_spec.rb +2 -1
- data/spec/logstash/circuit_breaker_spec.rb +36 -14
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12b4f41cf358aa9dd6e7e398744f74c780371863
|
4
|
+
data.tar.gz: 91ad7e8d873cbfd3f98d310ac9169ac963ca19e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
114
|
-
|
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
|
@@ -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.
|
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.
|
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)
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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 "
|
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 "
|
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(
|
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.
|
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-
|
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.
|
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.
|
58
|
+
version: 0.0.24
|
59
59
|
prerelease: false
|
60
60
|
type: :runtime
|
61
61
|
- !ruby/object:Gem::Dependency
|