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,455 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/inputs/generator"
4
+ require "logstash/filters/multiline"
5
+
6
+ class DummyInput < LogStash::Inputs::Base
7
+ config_name "dummyinput"
8
+ milestone 2
9
+
10
+ def register
11
+ end
12
+
13
+ def run(queue)
14
+ end
15
+
16
+ def close
17
+ end
18
+ end
19
+
20
+ class DummyCodec < LogStash::Codecs::Base
21
+ config_name "dummycodec"
22
+ milestone 2
23
+
24
+ def decode(data)
25
+ data
26
+ end
27
+
28
+ def encode(event)
29
+ event
30
+ end
31
+
32
+ def close
33
+ end
34
+ end
35
+
36
+ class DummyOutput < LogStash::Outputs::Base
37
+ config_name "dummyoutput"
38
+ milestone 2
39
+
40
+ attr_reader :num_closes, :events
41
+
42
+ def initialize(params={})
43
+ super
44
+ @num_closes = 0
45
+ @events = []
46
+ end
47
+
48
+ def register
49
+ end
50
+
51
+ def receive(event)
52
+ @events << event
53
+ end
54
+
55
+ def close
56
+ @num_closes += 1
57
+ end
58
+ end
59
+
60
+ class DummyFilter < LogStash::Filters::Base
61
+ config_name "dummyfilter"
62
+ milestone 2
63
+
64
+ def register() end
65
+
66
+ def filter(event) end
67
+
68
+ def threadsafe?() false; end
69
+
70
+ def close() end
71
+ end
72
+
73
+ class DummySafeFilter < LogStash::Filters::Base
74
+ config_name "dummysafefilter"
75
+ milestone 2
76
+
77
+ def register() end
78
+
79
+ def filter(event) end
80
+
81
+ def threadsafe?() true; end
82
+
83
+ def close() end
84
+ end
85
+
86
+ class TestPipeline < LogStash::Pipeline
87
+ attr_reader :outputs, :settings, :logger
88
+ end
89
+
90
+ describe LogStash::Pipeline do
91
+ let(:worker_thread_count) { LogStash::Pipeline::DEFAULT_SETTINGS[:default_pipeline_workers] }
92
+ let(:safe_thread_count) { 1 }
93
+ let(:override_thread_count) { 42 }
94
+
95
+ describe "defaulting the pipeline workers based on thread safety" do
96
+ before(:each) do
97
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
98
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
99
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
100
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(DummyFilter)
101
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummysafefilter").and_return(DummySafeFilter)
102
+ end
103
+
104
+ context "when there are some not threadsafe filters" do
105
+ let(:test_config_with_filters) {
106
+ <<-eos
107
+ input {
108
+ dummyinput {}
109
+ }
110
+
111
+ filter {
112
+ dummyfilter {}
113
+ }
114
+
115
+ output {
116
+ dummyoutput {}
117
+ }
118
+ eos
119
+ }
120
+
121
+ context "when there is no command line -w N set" do
122
+ it "starts one filter thread" do
123
+ msg = "Defaulting pipeline worker threads to 1 because there are some" +
124
+ " filters that might not work with multiple worker threads"
125
+ pipeline = TestPipeline.new(test_config_with_filters)
126
+ expect(pipeline.logger).to receive(:warn).with(msg,
127
+ {:count_was=>worker_thread_count, :filters=>["dummyfilter"]})
128
+ pipeline.run
129
+ expect(pipeline.worker_threads.size).to eq(safe_thread_count)
130
+ end
131
+ end
132
+
133
+ context "when there is command line -w N set" do
134
+ it "starts multiple filter thread" do
135
+ msg = "Warning: Manual override - there are filters that might" +
136
+ " not work with multiple worker threads"
137
+ pipeline = TestPipeline.new(test_config_with_filters)
138
+ expect(pipeline.logger).to receive(:warn).with(msg,
139
+ {:worker_threads=> override_thread_count, :filters=>["dummyfilter"]})
140
+ pipeline.configure(:pipeline_workers, override_thread_count)
141
+ pipeline.run
142
+ expect(pipeline.worker_threads.size).to eq(override_thread_count)
143
+ end
144
+ end
145
+ end
146
+
147
+ context "when there are threadsafe filters only" do
148
+ let(:test_config_with_filters) {
149
+ <<-eos
150
+ input {
151
+ dummyinput {}
152
+ }
153
+
154
+ filter {
155
+ dummysafefilter {}
156
+ }
157
+
158
+ output {
159
+ dummyoutput {}
160
+ }
161
+ eos
162
+ }
163
+
164
+ it "starts multiple filter threads" do
165
+ pipeline = TestPipeline.new(test_config_with_filters)
166
+ pipeline.run
167
+ expect(pipeline.worker_threads.size).to eq(worker_thread_count)
168
+ end
169
+ end
170
+ end
171
+
172
+ context "close" do
173
+ before(:each) do
174
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
175
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
176
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
177
+ end
178
+
179
+
180
+ let(:test_config_without_output_workers) {
181
+ <<-eos
182
+ input {
183
+ dummyinput {}
184
+ }
185
+
186
+ output {
187
+ dummyoutput {}
188
+ }
189
+ eos
190
+ }
191
+
192
+ let(:test_config_with_output_workers) {
193
+ <<-eos
194
+ input {
195
+ dummyinput {}
196
+ }
197
+
198
+ output {
199
+ dummyoutput {
200
+ workers => 2
201
+ }
202
+ }
203
+ eos
204
+ }
205
+
206
+ context "output close" do
207
+ it "should call close of output without output-workers" do
208
+ pipeline = TestPipeline.new(test_config_without_output_workers)
209
+ pipeline.run
210
+
211
+ expect(pipeline.outputs.size ).to eq(1)
212
+ expect(pipeline.outputs.first.workers.size ).to eq(pipeline.default_output_workers)
213
+ expect(pipeline.outputs.first.workers.first.num_closes ).to eq(1)
214
+ end
215
+
216
+ it "should call output close correctly with output workers" do
217
+ pipeline = TestPipeline.new(test_config_with_output_workers)
218
+ pipeline.run
219
+
220
+ expect(pipeline.outputs.size ).to eq(1)
221
+ # We even close the parent output worker, even though it doesn't receive messages
222
+
223
+ output_delegator = pipeline.outputs.first
224
+ output = output_delegator.workers.first
225
+
226
+ expect(output.num_closes).to eq(1)
227
+ output_delegator.workers.each do |plugin|
228
+ expect(plugin.num_closes ).to eq(1)
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ context "compiled flush function" do
235
+ describe "flusher thread" do
236
+ before(:each) do
237
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
238
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
239
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
240
+ end
241
+
242
+ let(:config) { "input { dummyinput {} } output { dummyoutput {} }"}
243
+
244
+ it "should start the flusher thread only after the pipeline is running" do
245
+ pipeline = TestPipeline.new(config)
246
+
247
+ expect(pipeline).to receive(:transition_to_running).ordered.and_call_original
248
+ expect(pipeline).to receive(:start_flusher).ordered.and_call_original
249
+
250
+ pipeline.run
251
+ end
252
+ end
253
+
254
+ context "cancelled events should not propagate down the filters" do
255
+ config <<-CONFIG
256
+ filter {
257
+ multiline {
258
+ pattern => "hello"
259
+ what => next
260
+ }
261
+ multiline {
262
+ pattern => "hello"
263
+ what => next
264
+ }
265
+ }
266
+ CONFIG
267
+
268
+ sample("hello") do
269
+ expect(subject["message"]).to eq("hello")
270
+ end
271
+ end
272
+
273
+ context "new events should propagate down the filters" do
274
+ config <<-CONFIG
275
+ filter {
276
+ clone {
277
+ clones => ["clone1"]
278
+ }
279
+ multiline {
280
+ pattern => "bar"
281
+ what => previous
282
+ }
283
+ }
284
+ CONFIG
285
+
286
+ sample(["foo", "bar"]) do
287
+ expect(subject.size).to eq(2)
288
+
289
+ expect(subject[0]["message"]).to eq("foo\nbar")
290
+ expect(subject[0]["type"]).to be_nil
291
+ expect(subject[1]["message"]).to eq("foo\nbar")
292
+ expect(subject[1]["type"]).to eq("clone1")
293
+ end
294
+ end
295
+ end
296
+
297
+ describe "max inflight warning" do
298
+ let(:config) { "input { dummyinput {} } output { dummyoutput {} }" }
299
+ let(:batch_size) { 1 }
300
+ let(:pipeline) { LogStash::Pipeline.new(config, :pipeline_batch_size => batch_size, :pipeline_workers => 1) }
301
+ let(:logger) { pipeline.logger }
302
+ let(:warning_prefix) { /CAUTION: Recommended inflight events max exceeded!/ }
303
+
304
+ before(:each) do
305
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
306
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
307
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
308
+ allow(logger).to receive(:warn)
309
+ thread = Thread.new { pipeline.run }
310
+ pipeline.shutdown
311
+ thread.join
312
+ end
313
+
314
+ it "should not raise a max inflight warning if the max_inflight count isn't exceeded" do
315
+ expect(logger).not_to have_received(:warn).with(warning_prefix)
316
+ end
317
+
318
+ context "with a too large inflight count" do
319
+ let(:batch_size) { LogStash::Pipeline::MAX_INFLIGHT_WARN_THRESHOLD + 1 }
320
+
321
+ it "should raise a max inflight warning if the max_inflight count is exceeded" do
322
+ expect(logger).to have_received(:warn).with(warning_prefix)
323
+ end
324
+ end
325
+ end
326
+
327
+ context "compiled filter funtions" do
328
+
329
+ context "new events should propagate down the filters" do
330
+ config <<-CONFIG
331
+ filter {
332
+ clone {
333
+ clones => ["clone1", "clone2"]
334
+ }
335
+ mutate {
336
+ add_field => {"foo" => "bar"}
337
+ }
338
+ }
339
+ CONFIG
340
+
341
+ sample("hello") do
342
+ expect(subject.size).to eq(3)
343
+
344
+ expect(subject[0]["message"]).to eq("hello")
345
+ expect(subject[0]["type"]).to be_nil
346
+ expect(subject[0]["foo"]).to eq("bar")
347
+
348
+ expect(subject[1]["message"]).to eq("hello")
349
+ expect(subject[1]["type"]).to eq("clone1")
350
+ expect(subject[1]["foo"]).to eq("bar")
351
+
352
+ expect(subject[2]["message"]).to eq("hello")
353
+ expect(subject[2]["type"]).to eq("clone2")
354
+ expect(subject[2]["foo"]).to eq("bar")
355
+ end
356
+ end
357
+ end
358
+
359
+ describe "stalling_threads" do
360
+ before(:each) do
361
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
362
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
363
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
364
+ end
365
+
366
+ context "when the pipeline doesn't have filters" do
367
+ let(:pipeline_with_no_filters) do
368
+ <<-eos
369
+ input { dummyinput {} }
370
+ output { dummyoutput {} }
371
+ eos
372
+ end
373
+
374
+ it "doesn't raise an error" do
375
+ pipeline = TestPipeline.new(pipeline_with_no_filters)
376
+ pipeline.run
377
+ expect { pipeline.stalling_threads_info }.to_not raise_error
378
+ end
379
+ end
380
+ end
381
+
382
+ context "Periodic Flush" do
383
+ let(:number_of_events) { 100 }
384
+ let(:config) do
385
+ <<-EOS
386
+ input {
387
+ generator {
388
+ count => #{number_of_events}
389
+ }
390
+ }
391
+ filter {
392
+ multiline {
393
+ pattern => "^NeverMatch"
394
+ negate => true
395
+ what => "previous"
396
+ }
397
+ }
398
+ output {
399
+ dummyoutput {}
400
+ }
401
+ EOS
402
+ end
403
+ let(:output) { DummyOutput.new }
404
+
405
+ before do
406
+ allow(DummyOutput).to receive(:new).with(any_args).and_return(output)
407
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_return(LogStash::Inputs::Generator)
408
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain)
409
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "multiline").and_return(LogStash::Filters::Multiline)
410
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
411
+ end
412
+
413
+ it "flushes the buffered contents of the filter" do
414
+ Thread.abort_on_exception = true
415
+ pipeline = LogStash::Pipeline.new(config, { :flush_interval => 1 })
416
+ Thread.new { pipeline.run }
417
+ sleep 0.1 while !pipeline.ready?
418
+ # give us a bit of time to flush the events
419
+ wait(15).for do
420
+ next unless output && output.events && output.events.first
421
+ output.events.first["message"].split("\n").count
422
+ end.to eq(number_of_events)
423
+ pipeline.shutdown
424
+ end
425
+ end
426
+
427
+ context "Multiple pipelines" do
428
+ before do
429
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_return(LogStash::Inputs::Generator)
430
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
431
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(DummyFilter)
432
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
433
+ end
434
+
435
+ let(:pipeline1) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
436
+ let(:pipeline2) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
437
+
438
+ it "should handle evaluating different config" do
439
+ # When the functions are compiled from the AST it will generate instance
440
+ # variables that are unique to the actual config, the intance are pointing
441
+ # to conditionals/plugins.
442
+ #
443
+ # Before the `defined_singleton_method`, the definition of the method was
444
+ # not unique per class, but the `instance variables` were unique per class.
445
+ #
446
+ # So the methods were trying to access instance variables that did not exist
447
+ # in the current instance and was returning an array containing nil values for
448
+ # the match.
449
+ expect(pipeline1.output_func(LogStash::Event.new)).not_to include(nil)
450
+ expect(pipeline1.filter_func(LogStash::Event.new)).not_to include(nil)
451
+ expect(pipeline2.output_func(LogStash::Event.new)).not_to include(nil)
452
+ expect(pipeline1.filter_func(LogStash::Event.new)).not_to include(nil)
453
+ end
454
+ end
455
+ end