logstash-core 2.2.4.snapshot1

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.

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