logstash-input-beats 2.0.3 → 2.1.1

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,9 +1,9 @@
1
- require_relative "../spec_helper"
2
- require "logstash/circuit_breaker"
1
+ require_relative "../../spec_helper"
2
+ require "logstash/inputs/beats_support/circuit_breaker"
3
3
 
4
4
  class DummyErrorTest < StandardError; end
5
5
 
6
- describe LogStash::CircuitBreaker do
6
+ describe LogStash::Inputs::BeatsSupport::CircuitBreaker do
7
7
  let(:error_threshold) { 1 }
8
8
  let(:options) do
9
9
  {
@@ -12,7 +12,7 @@ describe LogStash::CircuitBreaker do
12
12
  }
13
13
  end
14
14
 
15
- subject { LogStash::CircuitBreaker.new("testing", options) }
15
+ subject { described_class.new("testing", options) }
16
16
 
17
17
  context "when the breaker is closed" do
18
18
  it "closed by default" do
@@ -24,7 +24,7 @@ describe LogStash::CircuitBreaker do
24
24
  subject.execute do
25
25
  raise DummyErrorTest
26
26
  end
27
- }.to raise_error(LogStash::CircuitBreaker::HalfOpenBreaker)
27
+ }.to raise_error(LogStash::Inputs::BeatsSupport::CircuitBreaker::HalfOpenBreaker)
28
28
  end
29
29
 
30
30
  it "open if we pass the errors threadshold" do
@@ -32,18 +32,19 @@ describe LogStash::CircuitBreaker do
32
32
  subject.execute do
33
33
  raise DummyErrorTest
34
34
  end
35
- }.to raise_error(LogStash::CircuitBreaker::HalfOpenBreaker)
35
+ }.to raise_error(LogStash::Inputs::BeatsSupport::CircuitBreaker::HalfOpenBreaker)
36
36
 
37
37
  expect {
38
38
  subject.execute do
39
39
  raise DummyErrorTest
40
40
  end
41
- }.to raise_error(LogStash::CircuitBreaker::OpenBreaker)
41
+ }.to raise_error(LogStash::Inputs::BeatsSupport::CircuitBreaker::OpenBreaker)
42
42
  end
43
43
  end
44
44
 
45
45
  context "When the breaker is open" do
46
- let(:future_time) { Time.now + 3600 }
46
+ let(:retry_time) { 2 }
47
+ let(:options) { super.merge(:time_before_retry => retry_time) }
47
48
 
48
49
  before do
49
50
  # trip the breaker
@@ -62,7 +63,7 @@ describe LogStash::CircuitBreaker do
62
63
  end
63
64
 
64
65
  it "resets the breaker after the time before retry" do
65
- expect(Time).to receive(:now).at_least(2).and_return(future_time)
66
+ sleep(retry_time + 1)
66
67
  expect(subject.closed?).to eq(true)
67
68
  end
68
69
 
@@ -73,7 +74,7 @@ describe LogStash::CircuitBreaker do
73
74
  subject.execute do
74
75
  runned = true
75
76
  end
76
- rescue LogStash::CircuitBreaker::OpenBreaker
77
+ rescue LogStash::Inputs::BeatsSupport::CircuitBreaker::OpenBreaker
77
78
  end
78
79
 
79
80
  expect(runned).to eq(false)
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats"
3
+ require "logstash/event"
4
+ require "spec_helper"
5
+ require "thread"
6
+
7
+ Thread.abort_on_exception = true
8
+ describe LogStash::Inputs::BeatsSupport::CodecCallbackListener do
9
+ let(:data) { "Hello world" }
10
+ let(:map) do
11
+ {
12
+ "beat" => { "hostname" => "newhost" }
13
+ }
14
+ end
15
+ let(:path) { "/var/log/message" }
16
+ let(:transformer) { double("codec_transformer") }
17
+ let(:queue_timeout) { 1 }
18
+ let(:queue) { LogStash::Inputs::BeatsSupport::SynchronousQueueWithOffer.new(queue_timeout) }
19
+ let(:event) { LogStash::Event.new }
20
+
21
+ before do
22
+ allow(transformer).to receive(:transform).with(event, map).and_return(event)
23
+ end
24
+
25
+ subject { described_class.new(data, map, path, transformer, queue) }
26
+
27
+ it "expose the data" do
28
+ expect(subject.data).to eq(data)
29
+ end
30
+
31
+ it "expose the path" do
32
+ expect(subject.path).to eq(path)
33
+ end
34
+
35
+ context "when the queue is not blocked for too long" do
36
+ let(:queue_timeout) { 5 }
37
+
38
+ it "doesnt raise an exception" do
39
+ Thread.new do
40
+ loop { queue.take }
41
+ end
42
+ sleep(0.1)
43
+ expect { subject.process_event(event) }.not_to raise_error
44
+ end
45
+ end
46
+
47
+ context "when the queue is blocked for too long" do
48
+ it "raises an exception" do
49
+ expect { subject.process_event(event) }.to raise_error(LogStash::Inputs::Beats::InsertingToQueueTakeTooLong)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats"
3
+ require_relative "../../support/logstash_test"
4
+ require "spec_helper"
5
+
6
+ describe LogStash::Inputs::BeatsSupport::ConnectionHandler do
7
+ let(:config) do
8
+ {
9
+ "port" => 0,
10
+ "type" => "example",
11
+ "tags" => "beats"
12
+ }
13
+ end
14
+
15
+ let(:logger) { DummyLogger.new }
16
+ let(:input) do
17
+ LogStash::Inputs::Beats.new(config).tap do |i|
18
+ i.register
19
+ end
20
+ end
21
+ let(:connection) { double("connection") }
22
+ let(:queue) { DummyNeverBlockedQueue.new }
23
+
24
+ subject { described_class.new(connection, input, queue) }
25
+
26
+ context "#accept" do
27
+ let(:connection) { DummyConnection.new(events) }
28
+ let(:events) {
29
+ [
30
+ { :map => { "id" => 1 }, :identity_stream => "/var/log/message" },
31
+ { :map => { "id" => 2 }, :identity_stream => "/var/log/message_2" }
32
+ ]
33
+ }
34
+ it "should delegate work to `#process` for each items" do
35
+ events.each do |element|
36
+ expect(subject).to receive(:process).with(element[:map], element[:identity_stream]).and_return(true)
37
+ end
38
+
39
+ subject.accept
40
+ end
41
+ end
42
+
43
+ context "#process" do
44
+ let(:identity_stream) { "/var/log/message" }
45
+
46
+ context "without a `target_field_for_codec`" do
47
+ let(:map) { { "hello" => "world" } }
48
+
49
+ context "queue is not blocked" do
50
+ it "insert the event into the queue" do
51
+ subject.process(map, identity_stream)
52
+ event = queue.take
53
+
54
+ expect(event["hello"]).to eq(map["hello"])
55
+ expect(event["tags"]).to include("beats_input_raw_event")
56
+ end
57
+ end
58
+
59
+ context "queue is blocked" do
60
+ let(:queue_timeout) { 1 }
61
+ let(:queue) { LogStash::Inputs::BeatsSupport::SynchronousQueueWithOffer.new(queue_timeout) }
62
+
63
+ it "raise an exception" do
64
+ expect { subject.process(map, identity_stream) }.to raise_error(LogStash::Inputs::Beats::InsertingToQueueTakeTooLong)
65
+ end
66
+ end
67
+ end
68
+
69
+ context "with a codec" do
70
+ let(:message) { "Hello world" }
71
+ let(:map) { { "message" => message } }
72
+
73
+ context "queue is not blocked" do
74
+ it "insert the event into the queue" do
75
+ subject.process(map, identity_stream)
76
+ event = queue.take
77
+
78
+ expect(event["message"]).to eq(message)
79
+ expect(event["tags"]).to include("beats_input_codec_plain_applied")
80
+ end
81
+ end
82
+
83
+ context "queue is blocked" do
84
+ let(:queue_timeout) { 1 }
85
+ let(:queue) { LogStash::Inputs::BeatsSupport::SynchronousQueueWithOffer.new(queue_timeout) }
86
+
87
+ it "raise an exception" do
88
+ expect { subject.process(map, identity_stream) }.to raise_error(LogStash::Inputs::Beats::InsertingToQueueTakeTooLong)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ require "logstash/event"
3
+ require "logstash/timestamp"
4
+ require "logstash/inputs/beats"
5
+ require_relative "../../support/shared_examples"
6
+ require "spec_helper"
7
+
8
+ describe LogStash::Inputs::BeatsSupport::DecodedEventTransform do
9
+ let(:config) do
10
+ {
11
+ "port" => 0,
12
+ "type" => "example",
13
+ "tags" => "beats"
14
+ }
15
+ end
16
+
17
+ let(:input) do
18
+ LogStash::Inputs::Beats.new(config).tap do |i|
19
+ i.register
20
+ end
21
+ end
22
+ let(:event) { LogStash::Event.new }
23
+ let(:map) do
24
+ {
25
+ "@metadata" => { "hello" => "world"},
26
+ "super" => "mario"
27
+ }
28
+ end
29
+
30
+ subject { described_class.new(input).transform(event, map) }
31
+
32
+ include_examples "Common Event Transformation"
33
+
34
+ it "tags the event" do
35
+ expect(subject["tags"]).to include("beats_input_codec_plain_applied")
36
+ end
37
+
38
+ it "merges the other data from the map to the event" do
39
+ expect(subject["super"]).to eq(map["super"])
40
+ expect(subject["@metadata"]).to include(map["@metadata"])
41
+ end
42
+
43
+ context "map contains a timestamp" do
44
+ context "when its valid" do
45
+ let(:timestamp) { Time.now }
46
+ let(:map) { super.merge({"@timestamp" => timestamp }) }
47
+
48
+ it "uses as the event timestamp" do
49
+ expect(subject["@timestamp"]).to eq(LogStash::Timestamp.coerce(timestamp))
50
+ end
51
+ end
52
+
53
+ context "when its not valid" do
54
+ let(:map) { super.merge({"@timestamp" => "invalid" }) }
55
+
56
+ it "fallback the current time" do
57
+ expect(subject["@timestamp"]).to be_kind_of(LogStash::Timestamp)
58
+ end
59
+ end
60
+ end
61
+
62
+ context "when the map doesn't provide a timestamp" do
63
+ it "fallback the current time" do
64
+ expect(subject["@timestamp"]).to be_kind_of(LogStash::Timestamp)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ require "logstash/event"
3
+ require "logstash/inputs/beats"
4
+ require_relative "../../support/shared_examples"
5
+ require "spec_helper"
6
+
7
+ describe LogStash::Inputs::BeatsSupport::EventTransformCommon do
8
+ subject { described_class.new(input).transform(event) }
9
+
10
+ include_examples "Common Event Transformation"
11
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ require "logstash/event"
3
+ require "logstash/inputs/beats"
4
+ require_relative "../../support/shared_examples"
5
+ require "spec_helper"
6
+
7
+ describe LogStash::Inputs::BeatsSupport::RawEventTransform do
8
+ let(:config) do
9
+ {
10
+ "port" => 0,
11
+ "type" => "example",
12
+ "tags" => "beats"
13
+ }
14
+ end
15
+
16
+ let(:input) { LogStash::Inputs::Beats.new(config) }
17
+ let(:event) { LogStash::Event.new }
18
+
19
+ subject { described_class.new(input).transform(event) }
20
+
21
+ include_examples "Common Event Transformation"
22
+
23
+ it "tags the event" do
24
+ expect(subject["tags"]).to include("beats_input_raw_event")
25
+ end
26
+ end
@@ -17,7 +17,7 @@ describe "A client" do
17
17
  let(:host) { "127.0.0.1" }
18
18
  let(:queue) { [] }
19
19
 
20
- before do
20
+ before :each do
21
21
  expect(File).to receive(:read).at_least(1).with(certificate_file_crt) { certificate.first.to_s }
22
22
  expect(File).to receive(:read).at_least(1).with(certificate_file_key) { certificate.last.to_s }
23
23
 
@@ -29,23 +29,33 @@ describe "A client" do
29
29
  :ssl_key => certificate_file_key)
30
30
 
31
31
  @tcp_server = Thread.new do
32
+ tcp_server.run { |data, identity_stream| queue << [data, identity_stream] }
32
33
  while true
33
- tcp_server.accept do |socket|
34
- con = Lumberjack::Beats::Connection.new(socket, tcp_server)
35
- begin
36
- con.run { |data, identity_stream| queue << [data, identity_stream] }
37
- rescue
38
- # Close connection on failure. For example SSL client will make
39
- # parser for TCP based server trip.
40
- # Connection is closed by Server connection object
41
- end
42
- end
34
+ tcp_server.accept do |socket|
35
+ next if socket.nil?
36
+
37
+ begin
38
+ con = Lumberjack::Beats::Connection.new(socket, tcp_server)
39
+ con.run { |data, identity_stream| queue << [data, identity_stream] }
40
+ rescue
41
+ # Close connection on failure. For example SSL client will make
42
+ # parser for TCP based server trip.
43
+ # Connection is closed by Server connection object
44
+ end
45
+ end
43
46
  end
44
47
  end
45
48
 
46
49
  @ssl_server = Thread.new do
47
50
  ssl_server.run { |data, identity_stream| queue << [data, identity_stream] }
48
51
  end
52
+
53
+ sleep(0.1) while @ssl_server.status != "run" && @tcp_server != "run"
54
+ end
55
+
56
+ after :each do
57
+ @tcp_server.kill
58
+ @ssl_server.kill
49
59
  end
50
60
 
51
61
  shared_examples "send payload" do
@@ -132,7 +142,7 @@ describe "A client" do
132
142
  :addresses => host,
133
143
  :ssl => false)
134
144
  client.write({ "line" => "foobar" })
135
- }.to raise_error(RuntimeError)
145
+ }.to raise_error
136
146
  end
137
147
 
138
148
  context "When transmitting a payload" do
@@ -32,9 +32,9 @@ describe "Server" do
32
32
  end
33
33
  end
34
34
 
35
- sleep(1) while thread.status != "run"
35
+ sleep(0.1) while thread.status != "run"
36
36
  server.close
37
- sleep(2)
38
- expect(thread.status).to be_falsey
37
+
38
+ wait_for { thread.status }.to be_falsey
39
39
  end
40
40
  end
@@ -21,3 +21,28 @@ module LogStashTest
21
21
  end
22
22
  end
23
23
  end
24
+
25
+ class DummyNeverBlockedQueue < Array
26
+ def offer(element, timeout = nil)
27
+ push(element)
28
+ end
29
+
30
+ alias_method :take, :shift
31
+ end
32
+
33
+ class DummyConnection
34
+ def initialize(events)
35
+ @events = events
36
+ end
37
+
38
+ def run
39
+ @events.each do |element|
40
+ yield element[:map], element[:identity_stream]
41
+ end
42
+ end
43
+
44
+ def peer
45
+ "localhost:5555"
46
+ end
47
+ end
48
+
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ shared_examples "Common Event Transformation" do
3
+ let(:tag) { "140-rpm-beats" }
4
+ let(:config) do
5
+ {
6
+ "port" => 0,
7
+ "type" => "example",
8
+ "tags" => tag
9
+ }
10
+ end
11
+
12
+ let(:input) do
13
+ LogStash::Inputs::Beats.new(config).tap do |i|
14
+ i.register
15
+ end
16
+ end
17
+ let(:event) { LogStash::Event.new(event_map) }
18
+ let(:event_map) do
19
+ {
20
+ "message" => "Hello world",
21
+ }
22
+ end
23
+
24
+ it "adds configured tags to the event" do
25
+ expect(subject["tags"]).to include(tag)
26
+ end
27
+
28
+ context "when the `beast.hotname` doesnt exist on the event" do
29
+ let(:already_exist) { "already_exist" }
30
+ let(:event_map) { super.merge({ "host" => already_exist }) }
31
+
32
+ it "doesnt change the value" do
33
+ expect(subject["host"]).to eq(already_exist)
34
+ end
35
+ end
36
+
37
+ context "when the `beat.hostname` exist in the event" do
38
+ let(:producer_host) { "newhost01" }
39
+ let(:event_map) { super.merge({ "beat" => { "hostname" => producer_host }}) }
40
+
41
+ context "when `host` key doesn't exist on the event" do
42
+ it "copy the `beat.hostname` to `host` or backward compatibility" do
43
+ expect(subject["host"]).to eq(producer_host)
44
+ end
45
+ end
46
+
47
+ context "when `host` key exists on the event" do
48
+ let(:already_exist) { "already_exist" }
49
+ let(:event_map) { super.merge({ "host" => already_exist }) }
50
+
51
+ it "doesn't override it" do
52
+ expect(subject["host"]).to eq(already_exist)
53
+ end
54
+ end
55
+ end
56
+ end