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,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