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,550 @@
1
+ # encoding: utf-8
2
+ require 'logstash/errors'
3
+ require "treetop"
4
+
5
+ class Treetop::Runtime::SyntaxNode
6
+
7
+ def compile
8
+ return "" if elements.nil?
9
+ return elements.collect(&:compile).reject(&:empty?).join("")
10
+ end
11
+
12
+ # Traverse the syntax tree recursively.
13
+ # The order should respect the order of the configuration file as it is read
14
+ # and written by humans (and the order in which it is parsed).
15
+ def recurse(e, depth=0, &block)
16
+ r = block.call(e, depth)
17
+ e.elements.each { |e| recurse(e, depth + 1, &block) } if r && e.elements
18
+ nil
19
+ end
20
+
21
+ def recursive_inject(results=[], &block)
22
+ if !elements.nil?
23
+ elements.each do |element|
24
+ if block.call(element)
25
+ results << element
26
+ else
27
+ element.recursive_inject(results, &block)
28
+ end
29
+ end
30
+ end
31
+ return results
32
+ end
33
+
34
+ # When Treetop parses the configuration file
35
+ # it will generate a tree, the generated tree will contain
36
+ # a few `Empty` nodes to represent the actual space/tab or newline in the file.
37
+ # Some of theses node will point to our concrete class.
38
+ # To fetch a specific types of object we need to follow each branch
39
+ # and ignore the empty nodes.
40
+ def recursive_select(klass)
41
+ return recursive_inject { |e| e.is_a?(klass) }
42
+ end
43
+
44
+ def recursive_inject_parent(results=[], &block)
45
+ if !parent.nil?
46
+ if block.call(parent)
47
+ results << parent
48
+ else
49
+ parent.recursive_inject_parent(results, &block)
50
+ end
51
+ end
52
+ return results
53
+ end
54
+
55
+ def recursive_select_parent(results=[], klass)
56
+ return recursive_inject_parent(results) { |e| e.is_a?(klass) }
57
+ end
58
+ end
59
+
60
+
61
+ module LogStash; module Config; module AST
62
+
63
+ def self.defered_conditionals=(val)
64
+ @defered_conditionals = val
65
+ end
66
+
67
+ def self.defered_conditionals
68
+ @defered_conditionals
69
+ end
70
+
71
+ def self.defered_conditionals_index
72
+ @defered_conditionals_index
73
+ end
74
+
75
+ def self.defered_conditionals_index=(val)
76
+ @defered_conditionals_index = val
77
+ end
78
+
79
+ class Node < Treetop::Runtime::SyntaxNode
80
+ def text_value_for_comments
81
+ text_value.gsub(/[\r\n]/, " ")
82
+ end
83
+ end
84
+
85
+ class Config < Node
86
+ def compile
87
+ LogStash::Config::AST.defered_conditionals = []
88
+ LogStash::Config::AST.defered_conditionals_index = 0
89
+ code = []
90
+
91
+ code << <<-CODE
92
+ @inputs = []
93
+ @filters = []
94
+ @outputs = []
95
+ @periodic_flushers = []
96
+ @shutdown_flushers = []
97
+ CODE
98
+
99
+ sections = recursive_select(LogStash::Config::AST::PluginSection)
100
+ sections.each do |s|
101
+ code << s.compile_initializer
102
+ end
103
+
104
+ # start inputs
105
+ definitions = []
106
+
107
+ ["filter", "output"].each do |type|
108
+ # defines @filter_func and @output_func
109
+
110
+ # This need to be defined as a singleton method
111
+ # so each instance of the pipeline has his own implementation
112
+ # of the output/filter function
113
+ definitions << "define_singleton_method :#{type}_func do |event|"
114
+ definitions << " targeted_outputs = []" if type == "output"
115
+ definitions << " events = [event]" if type == "filter"
116
+ definitions << " @logger.debug? && @logger.debug(\"#{type} received\", :event => event.to_hash)"
117
+
118
+ sections.select { |s| s.plugin_type.text_value == type }.each do |s|
119
+ definitions << s.compile.split("\n", -1).map { |e| " #{e}" }
120
+ end
121
+
122
+ definitions << " events" if type == "filter"
123
+ definitions << " targeted_outputs" if type == "output"
124
+ definitions << "end"
125
+ end
126
+
127
+ code += definitions.join("\n").split("\n", -1).collect { |l| " #{l}" }
128
+
129
+ code += LogStash::Config::AST.defered_conditionals
130
+
131
+ return code.join("\n")
132
+ end
133
+ end
134
+
135
+ class Comment < Node; end
136
+ class Whitespace < Node; end
137
+ class PluginSection < Node
138
+ # Global plugin numbering for the janky instance variable naming we use
139
+ # like @filter_<name>_1
140
+ @@i = 0
141
+
142
+ # Generate ruby code to initialize all the plugins.
143
+ def compile_initializer
144
+ generate_variables
145
+ code = []
146
+ @variables.each do |plugin, name|
147
+
148
+
149
+ code << <<-CODE
150
+ #{name} = #{plugin.compile_initializer}
151
+ @#{plugin.plugin_type}s << #{name}
152
+ CODE
153
+
154
+ # The flush method for this filter.
155
+ if plugin.plugin_type == "filter"
156
+
157
+ code << <<-CODE
158
+ #{name}_flush = lambda do |options, &block|
159
+ @logger.debug? && @logger.debug(\"Flushing\", :plugin => #{name})
160
+
161
+ events = #{name}.flush(options)
162
+
163
+ return if events.nil? || events.empty?
164
+
165
+ @logger.debug? && @logger.debug(\"Flushing\", :plugin => #{name}, :events => events)
166
+
167
+ #{plugin.compile_starting_here.gsub(/^/, " ")}
168
+
169
+ events.each{|e| block.call(e)}
170
+ end
171
+
172
+ if #{name}.respond_to?(:flush)
173
+ @periodic_flushers << #{name}_flush if #{name}.periodic_flush
174
+ @shutdown_flushers << #{name}_flush
175
+ end
176
+ CODE
177
+
178
+ end
179
+ end
180
+ return code.join("\n")
181
+ end
182
+
183
+ def variable(object)
184
+ generate_variables
185
+ return @variables[object]
186
+ end
187
+
188
+ def generate_variables
189
+ return if !@variables.nil?
190
+ @variables = {}
191
+ plugins = recursive_select(Plugin)
192
+
193
+ plugins.each do |plugin|
194
+ # Unique number for every plugin.
195
+ @@i += 1
196
+ # store things as ivars, like @filter_grok_3
197
+ var = "@#{plugin.plugin_type}_#{plugin.plugin_name}_#{@@i}"
198
+ @variables[plugin] = var
199
+ end
200
+ return @variables
201
+ end
202
+
203
+ end
204
+
205
+ class Plugins < Node; end
206
+ class Plugin < Node
207
+ def plugin_type
208
+ if recursive_select_parent(Plugin).any?
209
+ return "codec"
210
+ else
211
+ return recursive_select_parent(PluginSection).first.plugin_type.text_value
212
+ end
213
+ end
214
+
215
+ def plugin_name
216
+ return name.text_value
217
+ end
218
+
219
+ def variable_name
220
+ return recursive_select_parent(PluginSection).first.variable(self)
221
+ end
222
+
223
+ def compile_initializer
224
+ # If any parent is a Plugin, this must be a codec.
225
+
226
+ if attributes.elements.nil?
227
+ return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect})" << (plugin_type == "codec" ? "" : "\n")
228
+ else
229
+ settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?)
230
+
231
+ attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})"
232
+ return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{attributes_code})" << (plugin_type == "codec" ? "" : "\n")
233
+ end
234
+ end
235
+
236
+ def compile
237
+ case plugin_type
238
+ when "input"
239
+ return "start_input(#{variable_name})"
240
+ when "filter"
241
+ return <<-CODE
242
+ events = #{variable_name}.multi_filter(events)
243
+ CODE
244
+ when "output"
245
+ return "targeted_outputs << #{variable_name}\n"
246
+ when "codec"
247
+ settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?)
248
+ attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})"
249
+ return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{attributes_code})"
250
+ end
251
+ end
252
+
253
+ def compile_starting_here
254
+ return unless plugin_type == "filter" # only filter supported.
255
+
256
+ expressions = [
257
+ LogStash::Config::AST::Branch,
258
+ LogStash::Config::AST::Plugin
259
+ ]
260
+ code = []
261
+
262
+ # Find the branch we are in, if any (the 'if' statement, etc)
263
+ self_branch = recursive_select_parent(LogStash::Config::AST::BranchEntry).first
264
+
265
+ # Find any siblings to our branch so we can skip them later. For example,
266
+ # if we are in an 'else if' we want to skip any sibling 'else if' or
267
+ # 'else' blocks.
268
+ branch_siblings = []
269
+ if self_branch
270
+ branch_siblings = recursive_select_parent(LogStash::Config::AST::Branch).first \
271
+ .recursive_select(LogStash::Config::AST::BranchEntry) \
272
+ .reject { |b| b == self_branch }
273
+ end
274
+
275
+ #ast = recursive_select_parent(LogStash::Config::AST::PluginSection).first
276
+ ast = recursive_select_parent(LogStash::Config::AST::Config).first
277
+
278
+ found = false
279
+ recurse(ast) do |element, depth|
280
+ next false if element.is_a?(LogStash::Config::AST::PluginSection) && element.plugin_type.text_value != "filter"
281
+ if element == self
282
+ found = true
283
+ next false
284
+ end
285
+ if found && expressions.include?(element.class)
286
+ code << element.compile
287
+ next false
288
+ end
289
+ next false if branch_siblings.include?(element)
290
+ next true
291
+ end
292
+
293
+ return code.collect { |l| "#{l}\n" }.join("")
294
+ end # def compile_starting_here
295
+ end
296
+
297
+ class Name < Node
298
+ def compile
299
+ return text_value.inspect
300
+ end
301
+ end
302
+ class Attribute < Node
303
+ def compile
304
+ return %Q(#{name.compile} => #{value.compile})
305
+ end
306
+ end
307
+ class RValue < Node; end
308
+ class Value < RValue; end
309
+
310
+ module Unicode
311
+ def self.wrap(text)
312
+ return "(" + text.force_encoding(Encoding::UTF_8).inspect + ")"
313
+ end
314
+ end
315
+
316
+ class Bareword < Value
317
+ def compile
318
+ return Unicode.wrap(text_value)
319
+ end
320
+ end
321
+ class String < Value
322
+ def compile
323
+ return Unicode.wrap(text_value[1...-1])
324
+ end
325
+ end
326
+ class RegExp < Value
327
+ def compile
328
+ return "Regexp.new(" + Unicode.wrap(text_value[1...-1]) + ")"
329
+ end
330
+ end
331
+ class Number < Value
332
+ def compile
333
+ return text_value
334
+ end
335
+ end
336
+ class Array < Value
337
+ def compile
338
+ return "[" << recursive_select(Value).collect(&:compile).reject(&:empty?).join(", ") << "]"
339
+ end
340
+ end
341
+ class Hash < Value
342
+ def validate!
343
+ duplicate_values = find_duplicate_keys
344
+
345
+ if duplicate_values.size > 0
346
+ raise ConfigurationError.new(
347
+ I18n.t("logstash.agent.configuration.invalid_plugin_settings_duplicate_keys",
348
+ :keys => duplicate_values.join(', '),
349
+ :line => input.line_of(interval.first),
350
+ :column => input.column_of(interval.first),
351
+ :byte => interval.first + 1,
352
+ :after => input[0..interval.first]
353
+ )
354
+ )
355
+ end
356
+ end
357
+
358
+ def find_duplicate_keys
359
+ values = recursive_select(HashEntry).collect { |hash_entry| hash_entry.name.text_value }
360
+ values.find_all { |v| values.count(v) > 1 }.uniq
361
+ end
362
+
363
+ def compile
364
+ validate!
365
+ return "{" << recursive_select(HashEntry).collect(&:compile).reject(&:empty?).join(", ") << "}"
366
+ end
367
+ end
368
+
369
+ class HashEntries < Node
370
+ end
371
+
372
+ class HashEntry < Node
373
+ def compile
374
+ return %Q(#{name.compile} => #{value.compile})
375
+ end
376
+ end
377
+
378
+ class BranchOrPlugin < Node; end
379
+
380
+ class Branch < Node
381
+ def compile
382
+
383
+ # this construct is non obvious. we need to loop through each event and apply the conditional.
384
+ # each branch of a conditional will contain a construct (a filter for example) that also loops through
385
+ # the events variable so we have to initialize it to [event] for the branch code.
386
+ # at the end, events is returned to handle the case where no branch match and no branch code is executed
387
+ # so we must make sure to return the current event.
388
+
389
+ type = recursive_select_parent(PluginSection).first.plugin_type.text_value
390
+
391
+ if type == "filter"
392
+ i = LogStash::Config::AST.defered_conditionals_index += 1
393
+ source = <<-CODE
394
+ def cond_func_#{i}(input_events)
395
+ result = []
396
+ input_events.each do |event|
397
+ events = [event]
398
+ #{super}
399
+ end
400
+ result += events
401
+ end
402
+ result
403
+ end
404
+ CODE
405
+ LogStash::Config::AST.defered_conditionals << source
406
+
407
+ <<-CODE
408
+ events = cond_func_#{i}(events)
409
+ CODE
410
+ else # Output
411
+ <<-CODE
412
+ #{super}
413
+ end
414
+ CODE
415
+ end
416
+ end
417
+ end
418
+
419
+ class BranchEntry < Node; end
420
+
421
+ class If < BranchEntry
422
+ def compile
423
+ children = recursive_inject { |e| e.is_a?(Branch) || e.is_a?(Plugin) }
424
+ return "if #{condition.compile} # if #{condition.text_value_for_comments}\n" \
425
+ << children.collect(&:compile).map { |s| s.split("\n", -1).map { |l| " " + l }.join("\n") }.join("") << "\n"
426
+ end
427
+ end
428
+ class Elsif < BranchEntry
429
+ def compile
430
+ children = recursive_inject { |e| e.is_a?(Branch) || e.is_a?(Plugin) }
431
+ return "elsif #{condition.compile} # else if #{condition.text_value_for_comments}\n" \
432
+ << children.collect(&:compile).map { |s| s.split("\n", -1).map { |l| " " + l }.join("\n") }.join("") << "\n"
433
+ end
434
+ end
435
+ class Else < BranchEntry
436
+ def compile
437
+ children = recursive_inject { |e| e.is_a?(Branch) || e.is_a?(Plugin) }
438
+ return "else\n" \
439
+ << children.collect(&:compile).map { |s| s.split("\n", -1).map { |l| " " + l }.join("\n") }.join("") << "\n"
440
+ end
441
+ end
442
+
443
+ class Condition < Node
444
+ def compile
445
+ return "(#{super})"
446
+ end
447
+ end
448
+
449
+ module Expression
450
+ def compile
451
+ return "(#{super})"
452
+ end
453
+ end
454
+
455
+ module NegativeExpression
456
+ def compile
457
+ return "!(#{super})"
458
+ end
459
+ end
460
+
461
+ module ComparisonExpression; end
462
+
463
+ module InExpression
464
+ def compile
465
+ item, list = recursive_select(LogStash::Config::AST::RValue)
466
+ return "(x = #{list.compile}; x.respond_to?(:include?) && x.include?(#{item.compile}))"
467
+ end
468
+ end
469
+
470
+ module NotInExpression
471
+ def compile
472
+ item, list = recursive_select(LogStash::Config::AST::RValue)
473
+ return "(x = #{list.compile}; !x.respond_to?(:include?) || !x.include?(#{item.compile}))"
474
+ end
475
+ end
476
+
477
+ class MethodCall < Node
478
+ def compile
479
+ arguments = recursive_inject { |e| [String, Number, Selector, Array, MethodCall].any? { |c| e.is_a?(c) } }
480
+ return "#{method.text_value}(" << arguments.collect(&:compile).join(", ") << ")"
481
+ end
482
+ end
483
+
484
+ class RegexpExpression < Node
485
+ def compile
486
+ operator = recursive_select(LogStash::Config::AST::RegExpOperator).first.text_value
487
+ item, regexp = recursive_select(LogStash::Config::AST::RValue)
488
+ # Compile strings to regexp's
489
+ if regexp.is_a?(LogStash::Config::AST::String)
490
+ regexp = "/#{regexp.text_value[1..-2]}/"
491
+ else
492
+ regexp = regexp.compile
493
+ end
494
+ return "(#{item.compile} #{operator} #{regexp})"
495
+ end
496
+ end
497
+
498
+ module ComparisonOperator
499
+ def compile
500
+ return " #{text_value} "
501
+ end
502
+ end
503
+ module RegExpOperator
504
+ def compile
505
+ return " #{text_value} "
506
+ end
507
+ end
508
+ module BooleanOperator
509
+ def compile
510
+ return " #{text_value} "
511
+ end
512
+ end
513
+ class Selector < RValue
514
+ def compile
515
+ return "event[#{text_value.inspect}]"
516
+ end
517
+ end
518
+ class SelectorElement < Node; end
519
+ end; end; end
520
+
521
+
522
+ # Monkeypatch Treetop::Runtime::SyntaxNode's inspect method to skip
523
+ # any Whitespace or SyntaxNodes with no children.
524
+ class Treetop::Runtime::SyntaxNode
525
+ def _inspect(indent="")
526
+ em = extension_modules
527
+ interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
528
+ im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
529
+ tv = text_value
530
+ tv = "...#{tv[-20..-1]}" if tv.size > 20
531
+
532
+ indent +
533
+ self.class.to_s.sub(/.*:/,'') +
534
+ em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
535
+ " offset=#{interval.first}" +
536
+ ", #{tv.inspect}" +
537
+ im +
538
+ (elements && elements.size > 0 ?
539
+ ":" +
540
+ (elements.select { |e| !e.is_a?(LogStash::Config::AST::Whitespace) && e.elements && e.elements.size > 0 }||[]).map{|e|
541
+ begin
542
+ "\n"+e.inspect(indent+" ")
543
+ rescue # Defend against inspect not taking a parameter
544
+ "\n"+indent+" "+e.inspect
545
+ end
546
+ }.join("") :
547
+ ""
548
+ )
549
+ end
550
+ end