logstash-core 2.2.4.snapshot1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of logstash-core might be problematic. Click here for more details.

Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-core.rb +1 -0
  3. data/lib/logstash-core/logstash-core.rb +3 -0
  4. data/lib/logstash-core/version.rb +8 -0
  5. data/lib/logstash/agent.rb +391 -0
  6. data/lib/logstash/codecs/base.rb +50 -0
  7. data/lib/logstash/config/config_ast.rb +550 -0
  8. data/lib/logstash/config/cpu_core_strategy.rb +32 -0
  9. data/lib/logstash/config/defaults.rb +12 -0
  10. data/lib/logstash/config/file.rb +39 -0
  11. data/lib/logstash/config/grammar.rb +3503 -0
  12. data/lib/logstash/config/mixin.rb +518 -0
  13. data/lib/logstash/config/registry.rb +13 -0
  14. data/lib/logstash/environment.rb +98 -0
  15. data/lib/logstash/errors.rb +12 -0
  16. data/lib/logstash/filters/base.rb +205 -0
  17. data/lib/logstash/inputs/base.rb +116 -0
  18. data/lib/logstash/inputs/threadable.rb +18 -0
  19. data/lib/logstash/java_integration.rb +116 -0
  20. data/lib/logstash/json.rb +61 -0
  21. data/lib/logstash/logging.rb +91 -0
  22. data/lib/logstash/namespace.rb +13 -0
  23. data/lib/logstash/output_delegator.rb +172 -0
  24. data/lib/logstash/outputs/base.rb +91 -0
  25. data/lib/logstash/patches.rb +5 -0
  26. data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
  27. data/lib/logstash/patches/cabin.rb +35 -0
  28. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  29. data/lib/logstash/patches/rubygems.rb +38 -0
  30. data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
  31. data/lib/logstash/pipeline.rb +499 -0
  32. data/lib/logstash/pipeline_reporter.rb +114 -0
  33. data/lib/logstash/plugin.rb +120 -0
  34. data/lib/logstash/program.rb +14 -0
  35. data/lib/logstash/runner.rb +124 -0
  36. data/lib/logstash/shutdown_watcher.rb +100 -0
  37. data/lib/logstash/util.rb +203 -0
  38. data/lib/logstash/util/buftok.rb +139 -0
  39. data/lib/logstash/util/charset.rb +35 -0
  40. data/lib/logstash/util/decorators.rb +52 -0
  41. data/lib/logstash/util/defaults_printer.rb +31 -0
  42. data/lib/logstash/util/filetools.rb +186 -0
  43. data/lib/logstash/util/java_version.rb +66 -0
  44. data/lib/logstash/util/password.rb +25 -0
  45. data/lib/logstash/util/plugin_version.rb +56 -0
  46. data/lib/logstash/util/prctl.rb +10 -0
  47. data/lib/logstash/util/retryable.rb +40 -0
  48. data/lib/logstash/util/socket_peer.rb +7 -0
  49. data/lib/logstash/util/unicode_trimmer.rb +81 -0
  50. data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
  51. data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
  52. data/lib/logstash/version.rb +14 -0
  53. data/locales/en.yml +204 -0
  54. data/logstash-core.gemspec +58 -0
  55. data/spec/conditionals_spec.rb +429 -0
  56. data/spec/logstash/agent_spec.rb +85 -0
  57. data/spec/logstash/config/config_ast_spec.rb +146 -0
  58. data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
  59. data/spec/logstash/config/defaults_spec.rb +10 -0
  60. data/spec/logstash/config/mixin_spec.rb +158 -0
  61. data/spec/logstash/environment_spec.rb +56 -0
  62. data/spec/logstash/filters/base_spec.rb +251 -0
  63. data/spec/logstash/inputs/base_spec.rb +74 -0
  64. data/spec/logstash/java_integration_spec.rb +304 -0
  65. data/spec/logstash/json_spec.rb +96 -0
  66. data/spec/logstash/output_delegator_spec.rb +144 -0
  67. data/spec/logstash/outputs/base_spec.rb +40 -0
  68. data/spec/logstash/patches_spec.rb +90 -0
  69. data/spec/logstash/pipeline_reporter_spec.rb +85 -0
  70. data/spec/logstash/pipeline_spec.rb +455 -0
  71. data/spec/logstash/plugin_spec.rb +169 -0
  72. data/spec/logstash/runner_spec.rb +68 -0
  73. data/spec/logstash/shutdown_watcher_spec.rb +113 -0
  74. data/spec/logstash/util/buftok_spec.rb +31 -0
  75. data/spec/logstash/util/charset_spec.rb +74 -0
  76. data/spec/logstash/util/defaults_printer_spec.rb +50 -0
  77. data/spec/logstash/util/java_version_spec.rb +79 -0
  78. data/spec/logstash/util/plugin_version_spec.rb +64 -0
  79. data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
  80. data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
  81. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
  82. data/spec/logstash/util_spec.rb +35 -0
  83. metadata +364 -0
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/json"
4
+ require "logstash/environment"
5
+ require "logstash/util"
6
+
7
+ describe "LogStash::Json" do
8
+
9
+ let(:hash) {{"a" => 1}}
10
+ let(:json_hash) {"{\"a\":1}"}
11
+
12
+ let(:string) {"foobar"}
13
+ let(:json_string) {"\"foobar\""}
14
+
15
+ let(:array) {["foo", "bar"]}
16
+ let(:json_array) {"[\"foo\",\"bar\"]"}
17
+
18
+ let(:multi) {
19
+ [
20
+ {:ruby => "foo bar baz", :json => "\"foo bar baz\""},
21
+ {:ruby => "1", :json => "\"1\""},
22
+ {:ruby => {"a" => true}, :json => "{\"a\":true}"},
23
+ {:ruby => {"a" => nil}, :json => "{\"a\":null}"},
24
+ {:ruby => ["a", "b"], :json => "[\"a\",\"b\"]"},
25
+ {:ruby => [1, 2], :json => "[1,2]"},
26
+ {:ruby => [1, nil], :json => "[1,null]"},
27
+ {:ruby => {"a" => [1, 2]}, :json => "{\"a\":[1,2]}"},
28
+ {:ruby => {"a" => {"b" => 2}}, :json => "{\"a\":{\"b\":2}}"},
29
+ # {:ruby => , :json => },
30
+ ]
31
+ }
32
+
33
+ if LogStash::Environment.jruby?
34
+
35
+ ### JRuby specific
36
+ # Former expectation in this code were removed because of https://github.com/rspec/rspec-mocks/issues/964
37
+ # as soon as is fix we can re introduce them if decired, however for now the completeness of the test
38
+ # is also not affected as the conversion would not work if the expectation where not meet.
39
+ ###
40
+ context "jruby deserialize" do
41
+ it "should respond to load and deserialize object" do
42
+ expect(LogStash::Json.load(json_hash)).to eql(hash)
43
+ end
44
+ end
45
+
46
+ context "jruby serialize" do
47
+ it "should respond to dump and serialize object" do
48
+ expect(LogStash::Json.dump(string)).to eql(json_string)
49
+ end
50
+
51
+ it "should call JrJackson::Raw.generate for Hash" do
52
+ expect(LogStash::Json.dump(hash)).to eql(json_hash)
53
+ end
54
+
55
+ it "should call JrJackson::Raw.generate for Array" do
56
+ expect(LogStash::Json.dump(array)).to eql(json_array)
57
+ end
58
+
59
+ end
60
+
61
+ else
62
+
63
+ ### MRI specific
64
+
65
+ it "should respond to load and deserialize object on mri" do
66
+ expect(Oj).to receive(:load).with(json).and_call_original
67
+ expect(LogStash::Json.load(json)).to eql(hash)
68
+ end
69
+
70
+ it "should respond to dump and serialize object on mri" do
71
+ expect(Oj).to receive(:dump).with(hash, anything).and_call_original
72
+ expect(LogStash::Json.dump(hash)).to eql(json)
73
+ end
74
+ end
75
+
76
+ ### non specific
77
+
78
+ it "should correctly deserialize" do
79
+ multi.each do |test|
80
+ # because JrJackson in :raw mode uses Java::JavaUtil::LinkedHashMap and
81
+ # Java::JavaUtil::ArrayList, we must cast to compare.
82
+ # other than that, they quack like their Ruby equivalent
83
+ expect(LogStash::Util.normalize(LogStash::Json.load(test[:json]))).to eql(test[:ruby])
84
+ end
85
+ end
86
+
87
+ it "should correctly serialize" do
88
+ multi.each do |test|
89
+ expect(LogStash::Json.dump(test[:ruby])).to eql(test[:json])
90
+ end
91
+ end
92
+
93
+ it "should raise Json::ParserError on invalid json" do
94
+ expect{LogStash::Json.load("abc")}.to raise_error LogStash::Json::ParserError
95
+ end
96
+ end
@@ -0,0 +1,144 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe LogStash::OutputDelegator do
5
+ let(:logger) { double("logger") }
6
+ let(:events) { 7.times.map { LogStash::Event.new }}
7
+ let(:default_worker_count) { 1 }
8
+
9
+ subject { described_class.new(logger, out_klass, default_worker_count) }
10
+
11
+ context "with a plain output plugin" do
12
+ let(:out_klass) { double("output klass") }
13
+ let(:out_inst) { double("output instance") }
14
+
15
+ before do
16
+ allow(out_klass).to receive(:new).with(any_args).and_return(out_inst)
17
+ allow(out_klass).to receive(:threadsafe?).and_return(false)
18
+ allow(out_klass).to receive(:workers_not_supported?).and_return(false)
19
+ allow(out_inst).to receive(:register)
20
+ allow(out_inst).to receive(:multi_receive)
21
+ allow(logger).to receive(:debug).with(any_args)
22
+ end
23
+
24
+ it "should initialize cleanly" do
25
+ expect { subject }.not_to raise_error
26
+ end
27
+
28
+ context "after having received a batch of events" do
29
+ before do
30
+ subject.register
31
+ subject.multi_receive(events)
32
+ end
33
+
34
+ it "should pass the events through" do
35
+ expect(out_inst).to have_received(:multi_receive).with(events)
36
+ end
37
+
38
+ it "should increment the number of events received" do
39
+ expect(subject.events_received).to eql(events.length)
40
+ end
41
+ end
42
+
43
+
44
+ describe "closing" do
45
+ before do
46
+ subject.register
47
+ end
48
+
49
+ it "should register all workers on register" do
50
+ expect(out_inst).to have_received(:register)
51
+ end
52
+
53
+ it "should close all workers when closing" do
54
+ expect(out_inst).to receive(:do_close)
55
+ subject.do_close
56
+ end
57
+ end
58
+
59
+ describe "concurrency and worker support" do
60
+ before do
61
+ allow(out_inst).to receive(:id).and_return("a-simple-plugin")
62
+ allow(out_inst).to receive(:metric=).with(any_args)
63
+ allow(out_klass).to receive(:workers_not_supported?).and_return(false)
64
+ end
65
+
66
+ describe "non-threadsafe outputs that allow workers" do
67
+ let(:default_worker_count) { 3 }
68
+
69
+ before do
70
+ allow(out_klass).to receive(:threadsafe?).and_return(false)
71
+ subject.register
72
+ end
73
+
74
+ it "should instantiate multiple workers" do
75
+ expect(subject.workers.length).to eql(default_worker_count)
76
+ end
77
+
78
+ it "should send received events to the worker" do
79
+ expect(out_inst).to receive(:multi_receive).with(events)
80
+ subject.multi_receive(events)
81
+ end
82
+ end
83
+
84
+ describe "threadsafe outputs" do
85
+ before do
86
+ allow(out_klass).to receive(:threadsafe?).and_return(true)
87
+ subject.register
88
+ end
89
+
90
+ it "should return true when threadsafe? is invoked" do
91
+ expect(subject.threadsafe?).to eql(true)
92
+ end
93
+
94
+ it "should define a threadsafe_worker" do
95
+ expect(subject.send(:threadsafe_worker)).to eql(out_inst)
96
+ end
97
+
98
+ it "should utilize threadsafe_multi_receive" do
99
+ expect(subject.send(:threadsafe_worker)).to receive(:multi_receive).with(events)
100
+ subject.multi_receive(events)
101
+ end
102
+
103
+ it "should not utilize the worker queue" do
104
+ expect(subject.send(:worker_queue)).to be_nil
105
+ end
106
+
107
+ it "should send received events to the worker" do
108
+ expect(out_inst).to receive(:multi_receive).with(events)
109
+ subject.multi_receive(events)
110
+ end
111
+
112
+ it "should close all workers when closing" do
113
+ expect(out_inst).to receive(:do_close)
114
+ subject.do_close
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ # This may seem suspiciously similar to the class in outputs/base_spec
121
+ # but, in fact, we need a whole new class because using this even once
122
+ # will immutably modify the base class
123
+ class LogStash::Outputs::NOOPDelLegacyNoWorkers < ::LogStash::Outputs::Base
124
+ LEGACY_WORKERS_NOT_SUPPORTED_REASON = "legacy reason"
125
+
126
+ def register
127
+ workers_not_supported(LEGACY_WORKERS_NOT_SUPPORTED_REASON)
128
+ end
129
+ end
130
+
131
+ describe "legacy output workers_not_supported" do
132
+ let(:default_worker_count) { 2 }
133
+ let(:out_klass) { LogStash::Outputs::NOOPDelLegacyNoWorkers }
134
+
135
+ before(:each) do
136
+ allow(logger).to receive(:debug).with(any_args)
137
+ end
138
+
139
+ it "should only setup one worker" do
140
+ subject.register
141
+ expect(subject.worker_count).to eql(1)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ # use a dummy NOOP output to test Outputs::Base
5
+ class LogStash::Outputs::NOOP < LogStash::Outputs::Base
6
+ config_name "noop"
7
+ milestone 2
8
+
9
+ config :dummy_option, :validate => :string
10
+
11
+ def register; end
12
+
13
+ def receive(event)
14
+ return output?(event)
15
+ end
16
+ end
17
+
18
+ class LogStash::Outputs::NOOPLegacyNoWorkers < ::LogStash::Outputs::Base
19
+ LEGACY_WORKERS_NOT_SUPPORTED_REASON = "legacy reason"
20
+
21
+ def register
22
+ workers_not_supported(LEGACY_WORKERS_NOT_SUPPORTED_REASON)
23
+ end
24
+ end
25
+
26
+ describe "LogStash::Outputs::Base#new" do
27
+ it "should instantiate cleanly" do
28
+ params = { "dummy_option" => "potatoes", "codec" => "json", "workers" => 2 }
29
+ worker_params = params.dup; worker_params["workers"] = 1
30
+
31
+ expect do
32
+ LogStash::Outputs::NOOP.new(params.dup)
33
+ end.not_to raise_error
34
+ end
35
+
36
+ it "should move workers_not_supported declarations up to the class level" do
37
+ LogStash::Outputs::NOOPLegacyNoWorkers.new.register
38
+ expect(LogStash::Outputs::NOOPLegacyNoWorkers.workers_not_supported?).to eql(true)
39
+ end
40
+ end
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+ require "socket"
3
+ require "logstash/patches"
4
+ require "flores/pki"
5
+
6
+ describe "OpenSSL defaults" do
7
+ subject { OpenSSL::SSL::SSLContext.new }
8
+
9
+ # OpenSSL::SSL::SSLContext#ciphers returns an array of
10
+ # [ [ ciphername, version, bits, alg_bits ], [ ... ], ... ]
11
+
12
+ # List of cipher names
13
+ let(:ciphers) { subject.ciphers.map(&:first) }
14
+
15
+ # List of cipher encryption bit strength.
16
+ let(:encryption_bits) { subject.ciphers.map { |_, _, _, a| a } }
17
+
18
+ it "should not include any export ciphers" do
19
+ # SSLContext#ciphers returns an array of [ciphername, tlsversion, key_bits, alg_bits]
20
+ # Let's just check the cipher names
21
+ expect(ciphers).not_to be_any { |name| name =~ /EXPORT/ || name =~ /^EXP/ }
22
+ end
23
+
24
+ it "should not include any weak ciphers (w/ less than 128 bits in encryption algorithm)" do
25
+ # SSLContext#ciphers returns an array of [ciphername, tlsversion, key_bits, alg_bits]
26
+ expect(encryption_bits).not_to be_any { |bits| bits < 128 }
27
+ end
28
+
29
+ it "should not include a default `verify_mode`" do
30
+ expect(OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:verify_mode]).to eq(nil)
31
+ end
32
+
33
+ context "SSLSocket" do
34
+ # Code taken from the flores library by @jordansissels,
35
+ # https://github.com/jordansissel/ruby-flores/blob/master/spec/flores/pki_integration_spec.rb
36
+ # since these helpers were created to fix this particular issue
37
+ let(:csr) { Flores::PKI::CertificateSigningRequest.new }
38
+ # Here, I use a 1024-bit key for faster tests.
39
+ # Please do not use such small keys in production.
40
+ let(:key_bits) { 1024 }
41
+ let(:key) { OpenSSL::PKey::RSA.generate(key_bits, 65537) }
42
+ let(:certificate_duration) { Flores::Random.number(1..86400) }
43
+
44
+ context "with self-signed client/server certificate" do
45
+ let(:certificate_subject) { "CN=server.example.com" }
46
+ let(:certificate) { csr.create }
47
+
48
+ # Returns [socket, address, port]
49
+ let(:listener) { Flores::Random.tcp_listener }
50
+ let(:server) { listener[0] }
51
+ let(:server_address) { listener[1] }
52
+ let(:server_port) { listener[2] }
53
+
54
+ let(:server_context) { OpenSSL::SSL::SSLContext.new }
55
+ let(:client_context) { OpenSSL::SSL::SSLContext.new }
56
+
57
+ before do
58
+ csr.subject = certificate_subject
59
+ csr.public_key = key.public_key
60
+ csr.start_time = Time.now
61
+ csr.expire_time = csr.start_time + certificate_duration
62
+ csr.signing_key = key
63
+ csr.want_signature_ability = true
64
+
65
+ server_context.cert = certificate
66
+ server_context.key = key
67
+
68
+ client_store = OpenSSL::X509::Store.new
69
+ client_store.add_cert(certificate)
70
+ client_context.cert_store = client_store
71
+ client_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
72
+
73
+ ssl_server = OpenSSL::SSL::SSLServer.new(server, server_context)
74
+ Thread.new do
75
+ begin
76
+ ssl_server.accept
77
+ rescue => e
78
+ puts "Server accept failed: #{e}"
79
+ end
80
+ end
81
+ end
82
+
83
+ it "should successfully connect as a client" do
84
+ socket = TCPSocket.new(server_address, server_port)
85
+ ssl_client = OpenSSL::SSL::SSLSocket.new(socket, client_context)
86
+ expect { ssl_client.connect }.not_to raise_error
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/pipeline"
4
+ require "logstash/pipeline_reporter"
5
+
6
+ class DummyOutput < LogStash::Outputs::Base
7
+ config_name "dummyoutput"
8
+ milestone 2
9
+
10
+ attr_reader :num_closes, :events
11
+
12
+ def initialize(params={})
13
+ super
14
+ @num_closes = 0
15
+ @events = []
16
+ end
17
+
18
+ def register
19
+ end
20
+
21
+ def receive(event)
22
+ @events << event
23
+ end
24
+
25
+ def close
26
+ @num_closes += 1
27
+ end
28
+ end
29
+
30
+ #TODO: Figure out how to add more tests that actually cover inflight events
31
+ #This will require some janky multithreading stuff
32
+ describe LogStash::PipelineReporter do
33
+ let(:generator_count) { 5 }
34
+ let(:config) do
35
+ "input { generator { count => #{generator_count} } } output { dummyoutput {} } "
36
+ end
37
+ let(:pipeline) { LogStash::Pipeline.new(config)}
38
+ let(:reporter) { pipeline.reporter }
39
+
40
+ before do
41
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
42
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_call_original
43
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_call_original
44
+
45
+ @pre_snapshot = reporter.snapshot
46
+ pipeline.run
47
+ @post_snapshot = reporter.snapshot
48
+ end
49
+
50
+ describe "events filtered" do
51
+ it "should start at zero" do
52
+ expect(@pre_snapshot.events_filtered).to eql(0)
53
+ end
54
+
55
+ it "should end at the number of generated events" do
56
+ expect(@post_snapshot.events_filtered).to eql(generator_count)
57
+ end
58
+ end
59
+
60
+ describe "events consumed" do
61
+ it "should start at zero" do
62
+ expect(@pre_snapshot.events_consumed).to eql(0)
63
+ end
64
+
65
+ it "should end at the number of generated events" do
66
+ expect(@post_snapshot.events_consumed).to eql(generator_count)
67
+ end
68
+ end
69
+
70
+ describe "inflight count" do
71
+ it "should be zero before running" do
72
+ expect(@pre_snapshot.inflight_count).to eql(0)
73
+ end
74
+
75
+ it "should be zero after running" do
76
+ expect(@post_snapshot.inflight_count).to eql(0)
77
+ end
78
+ end
79
+
80
+ describe "output states" do
81
+ it "should include the count of received events" do
82
+ expect(@post_snapshot.output_info.first[:events_received]).to eql(generator_count)
83
+ end
84
+ end
85
+ end