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,116 @@
1
+ # encoding: utf-8
2
+ require "java"
3
+
4
+ # this is mainly for usage with JrJackson json parsing in :raw mode which genenerates
5
+ # Java::JavaUtil::ArrayList and Java::JavaUtil::LinkedHashMap native objects for speed.
6
+ # these object already quacks like their Ruby equivalents Array and Hash but they will
7
+ # not test for is_a?(Array) or is_a?(Hash) and we do not want to include tests for
8
+ # both classes everywhere. see LogStash::JSon.
9
+
10
+ class Array
11
+ # enable class equivalence between Array and ArrayList
12
+ # so that ArrayList will work with case o when Array ...
13
+ def self.===(other)
14
+ return true if other.is_a?(Java::JavaUtil::Collection)
15
+ super
16
+ end
17
+ end
18
+
19
+ class Hash
20
+ # enable class equivalence between Hash and LinkedHashMap
21
+ # so that LinkedHashMap will work with case o when Hash ...
22
+ def self.===(other)
23
+ return true if other.is_a?(Java::JavaUtil::Map)
24
+ super
25
+ end
26
+ end
27
+
28
+ # map_mixin to patch LinkedHashMap and HashMap. it must be done directly on the classes,
29
+ # using a module mixin does not work, and injecting in the Map interface does not work either
30
+ # but injecting in the class works.
31
+
32
+ map_mixin = lambda do
33
+ # this is a temporary fix to solve a bug in JRuby where classes implementing the Map interface, like LinkedHashMap
34
+ # have a bug in the has_key? method that is implemented in the Enumerable module that is somehow mixed in the Map interface.
35
+ # this bug makes has_key? (and all its aliases) return false for a key that has a nil value.
36
+ # Only LinkedHashMap is patched here because patching the Map interface is not working.
37
+ # TODO find proper fix, and submit upstream
38
+ # releavant JRuby files:
39
+ # https://github.com/jruby/jruby/blob/master/core/src/main/ruby/jruby/java/java_ext/java.util.rb
40
+ # https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java
41
+ def has_key?(key)
42
+ self.containsKey(key)
43
+ end
44
+ alias_method :include?, :has_key?
45
+ alias_method :member?, :has_key?
46
+ alias_method :key?, :has_key?
47
+
48
+ # Java 8 Map implements a merge method with a different signature from
49
+ # the Ruby Hash#merge. see https://github.com/jruby/jruby/issues/1249
50
+ # this can be removed when fixed upstream
51
+ if ENV_JAVA['java.specification.version'] >= '1.8'
52
+ def merge(other)
53
+ dup.merge!(other)
54
+ end
55
+ end
56
+ end
57
+
58
+ Java::JavaUtil::LinkedHashMap.module_exec(&map_mixin)
59
+ Java::JavaUtil::HashMap.module_exec(&map_mixin)
60
+
61
+ module java::util::Map
62
+ # have Map objects like LinkedHashMap objects report is_a?(Array) == true
63
+ def is_a?(clazz)
64
+ return true if clazz == Hash
65
+ super
66
+ end
67
+ end
68
+
69
+ module java::util::Collection
70
+ # have Collections objects like ArrayList report is_a?(Array) == true
71
+ def is_a?(clazz)
72
+ return true if clazz == Array
73
+ super
74
+ end
75
+
76
+ # support the Ruby Array delete method on a Java Collection
77
+ def delete(o)
78
+ self.removeAll([o]) ? o : block_given? ? yield : nil
79
+ end
80
+
81
+ def compact
82
+ duped = Java::JavaUtil::ArrayList.new(self)
83
+ duped.compact!
84
+ duped
85
+ end
86
+
87
+ def compact!
88
+ size_before = self.size
89
+ self.removeAll(java::util::Collections.singleton(nil))
90
+ if size_before == self.size
91
+ nil
92
+ else
93
+ self
94
+ end
95
+ end
96
+
97
+ # support the Ruby intersection method on Java Collection
98
+ def &(other)
99
+ # transform self into a LinkedHashSet to remove duplicates and preserve order as defined by the Ruby Array intersection contract
100
+ duped = Java::JavaUtil::LinkedHashSet.new(self)
101
+ duped.retainAll(other)
102
+ duped
103
+ end
104
+
105
+ # support the Ruby union method on Java Collection
106
+ def |(other)
107
+ # transform self into a LinkedHashSet to remove duplicates and preserve order as defined by the Ruby Array union contract
108
+ duped = Java::JavaUtil::LinkedHashSet.new(self)
109
+ duped.addAll(other)
110
+ duped
111
+ end
112
+
113
+ def inspect
114
+ "<#{self.class.name}:#{self.hashCode} #{self.to_a(&:inspect)}>"
115
+ end
116
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ require "logstash/environment"
3
+ require "logstash/errors"
4
+ if LogStash::Environment.jruby?
5
+ require "jrjackson"
6
+ require "logstash/java_integration"
7
+ else
8
+ require "oj"
9
+ end
10
+
11
+ module LogStash
12
+ module Json
13
+ class ParserError < LogStash::Error; end
14
+ class GeneratorError < LogStash::Error; end
15
+
16
+ extend self
17
+
18
+ ### MRI
19
+
20
+ def mri_load(data, options = {})
21
+ Oj.load(data)
22
+ rescue Oj::ParseError => e
23
+ raise LogStash::Json::ParserError.new(e.message)
24
+ end
25
+
26
+ def mri_dump(o)
27
+ Oj.dump(o, :mode => :compat, :use_to_json => true)
28
+ rescue => e
29
+ raise LogStash::Json::GeneratorError.new(e.message)
30
+ end
31
+
32
+ ### JRuby
33
+
34
+ def jruby_load(data, options = {})
35
+ # TODO [guyboertje] remove these comments in 5.0
36
+ # options[:symbolize_keys] ? JrJackson::Raw.parse_sym(data) : JrJackson::Raw.parse_raw(data)
37
+
38
+ JrJackson::Ruby.parse(data, options)
39
+
40
+ rescue JrJackson::ParseError => e
41
+ raise LogStash::Json::ParserError.new(e.message)
42
+ end
43
+
44
+ def jruby_dump(o)
45
+ # TODO [guyboertje] remove these comments in 5.0
46
+ # test for enumerable here to work around an omission in JrJackson::Json.dump to
47
+ # also look for Java::JavaUtil::ArrayList, see TODO submit issue
48
+ # o.is_a?(Enumerable) ? JrJackson::Raw.generate(o) : JrJackson::Json.dump(o)
49
+
50
+ JrJackson::Base.generate(o, {})
51
+
52
+ rescue => e
53
+ raise LogStash::Json::GeneratorError.new(e.message)
54
+ end
55
+
56
+ prefix = LogStash::Environment.jruby? ? "jruby" : "mri"
57
+ alias_method :load, "#{prefix}_load".to_sym
58
+ alias_method :dump, "#{prefix}_dump".to_sym
59
+
60
+ end
61
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "cabin"
4
+ require "logger"
5
+
6
+ class LogStash::Logger
7
+ attr_accessor :target
8
+
9
+ public
10
+ def initialize(*args)
11
+ super()
12
+
13
+ #self[:program] = File.basename($0)
14
+ #subscribe(::Logger.new(*args))
15
+ @target = args[0]
16
+ @channel = Cabin::Channel.get(LogStash)
17
+
18
+ # lame hack until cabin's smart enough not to doubley-subscribe something.
19
+ # without this subscription count check, running the test suite
20
+ # causes Cabin to subscribe to STDOUT maaaaaany times.
21
+ subscriptions = @channel.instance_eval { @subscribers.count }
22
+ @channel.subscribe(@target) unless subscriptions > 0
23
+
24
+ # Set default loglevel to WARN unless $DEBUG is set (run with 'ruby -d')
25
+ @level = $DEBUG ? :debug : :warn
26
+ if ENV["LOGSTASH_DEBUG"]
27
+ @level = :debug
28
+ end
29
+
30
+ # Direct metrics elsewhere.
31
+ @channel.metrics.channel = Cabin::Channel.new
32
+ end # def initialize
33
+
34
+ # Delegation
35
+ def level=(value) @channel.level = value; end
36
+ def debug(*args); @channel.debug(*args); end
37
+ def debug?(*args); @channel.debug?(*args); end
38
+ def info(*args); @channel.info(*args); end
39
+ def info?(*args); @channel.info?(*args); end
40
+ def warn(*args); @channel.warn(*args); end
41
+ def warn?(*args); @channel.warn?(*args); end
42
+ def error(*args); @channel.error(*args); end
43
+ def error?(*args); @channel.error?(*args); end
44
+ def fatal(*args); @channel.fatal(*args); end
45
+ def fatal?(*args); @channel.fatal?(*args); end
46
+
47
+ def self.setup_log4j(logger)
48
+ require "java"
49
+
50
+ properties = java.util.Properties.new
51
+ log4j_level = "WARN"
52
+ case logger.level
53
+ when :debug
54
+ log4j_level = "DEBUG"
55
+ when :info
56
+ log4j_level = "INFO"
57
+ when :warn
58
+ log4j_level = "WARN"
59
+ end # case level
60
+ properties.setProperty("log4j.rootLogger", "#{log4j_level},logstash")
61
+
62
+ # TODO(sissel): This is a shitty hack to work around the fact that
63
+ # LogStash::Logger isn't used anymore. We should fix that.
64
+ target = logger.instance_eval { @subscribers }.values.first.instance_eval { @io }
65
+ case target
66
+ when STDOUT
67
+ properties.setProperty("log4j.appender.logstash",
68
+ "org.apache.log4j.ConsoleAppender")
69
+ properties.setProperty("log4j.appender.logstash.Target", "System.out")
70
+ when STDERR
71
+ properties.setProperty("log4j.appender.logstash",
72
+ "org.apache.log4j.ConsoleAppender")
73
+ properties.setProperty("log4j.appender.logstash.Target", "System.err")
74
+ when target.is_a?(File)
75
+ properties.setProperty("log4j.appender.logstash",
76
+ "org.apache.log4j.FileAppender")
77
+ properties.setProperty("log4j.appender.logstash.File", target.path)
78
+ else
79
+ properties.setProperty("log4j.appender.logstash", "org.apache.log4j.varia.NullAppender")
80
+ end # case target
81
+
82
+ properties.setProperty("log4j.appender.logstash.layout",
83
+ "org.apache.log4j.PatternLayout")
84
+ properties.setProperty("log4j.appender.logstash.layout.conversionPattern",
85
+ "log4j, [%d{yyyy-MM-dd}T%d{HH:mm:ss.SSS}] %5p: %c: %m%n")
86
+
87
+ org.apache.log4j.LogManager.resetConfiguration
88
+ org.apache.log4j.PropertyConfigurator.configure(properties)
89
+ logger.debug("log4j java properties setup", :log4j_level => log4j_level)
90
+ end
91
+ end # class LogStash::Logger
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ module LogStash
3
+ module Inputs; end
4
+ module Outputs; end
5
+ module Filters; end
6
+ module Search; end
7
+ module Config; end
8
+ module File; end
9
+ module Web; end
10
+ module Util; end
11
+ module PluginMixins; end
12
+ module PluginManager; end
13
+ end # module LogStash
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+ require "concurrent/atomic/atomic_fixnum"
3
+ java_import "java.util.concurrent.CopyOnWriteArrayList"
4
+
5
+ # This class goes hand in hand with the pipeline to provide a pool of
6
+ # free workers to be used by pipeline worker threads. The pool is
7
+ # internally represented with a SizedQueue set the the size of the number
8
+ # of 'workers' the output plugin is configured with.
9
+ #
10
+ # This plugin also records some basic statistics
11
+ module LogStash class OutputDelegator
12
+ attr_reader :workers, :config, :threadsafe
13
+
14
+ # The *args this takes are the same format that a Outputs::Base takes. A list of hashes with parameters in them
15
+ # Internally these just get merged together into a single hash
16
+ def initialize(logger, klass, default_worker_count, *plugin_args)
17
+ @logger = logger
18
+ @threadsafe = klass.threadsafe?
19
+ @config = plugin_args.reduce({}, :merge)
20
+ @klass = klass
21
+ @workers = java.util.concurrent.CopyOnWriteArrayList.new
22
+ @default_worker_count = default_worker_count
23
+ @registered = false
24
+ @events_received = Concurrent::AtomicFixnum.new(0)
25
+ end
26
+
27
+ def threadsafe?
28
+ !!@threadsafe
29
+ end
30
+
31
+ def warn_on_worker_override!
32
+ # The user has configured extra workers, but this plugin doesn't support it :(
33
+ if worker_limits_overriden?
34
+ message = @klass.workers_not_supported_message
35
+ warning_meta = {:plugin => @klass.config_name, :worker_count => @config["workers"]}
36
+ if message
37
+ warning_meta[:message] = message
38
+ @logger.warn(I18n.t("logstash.pipeline.output-worker-unsupported-with-message", warning_meta))
39
+ else
40
+ @logger.warn(I18n.t("logstash.pipeline.output-worker-unsupported", warning_meta))
41
+ end
42
+ end
43
+ end
44
+
45
+ def worker_limits_overriden?
46
+ @config["workers"] && @config["workers"] > 1 && @klass.workers_not_supported?
47
+ end
48
+
49
+ def target_worker_count
50
+ # Remove in 5.0 after all plugins upgraded to use class level declarations
51
+ raise ArgumentError, "Attempted to detect target worker count before instantiating a worker to test for legacy workers_not_supported!" if @workers.size == 0
52
+
53
+ if @threadsafe || @klass.workers_not_supported?
54
+ 1
55
+ else
56
+ @config["workers"] || @default_worker_count
57
+ end
58
+ end
59
+
60
+ def config_name
61
+ @klass.config_name
62
+ end
63
+
64
+ def register
65
+ raise ArgumentError, "Attempted to register #{self} twice!" if @registered
66
+ @registered = true
67
+ # We define this as an array regardless of threadsafety
68
+ # to make reporting simpler, even though a threadsafe plugin will just have
69
+ # a single instance
70
+ #
71
+ # Older plugins invoke the instance method Outputs::Base#workers_not_supported
72
+ # To detect these we need an instance to be created first :()
73
+ # TODO: In the next major version after 2.x remove support for this
74
+ @workers << @klass.new(@config)
75
+ @workers.first.register # Needed in case register calls `workers_not_supported`
76
+
77
+ @logger.debug("Will start workers for output", :worker_count => target_worker_count, :class => @klass)
78
+
79
+ # Threadsafe versions don't need additional workers
80
+ setup_additional_workers!(target_worker_count) unless @threadsafe
81
+ # We skip the first worker because that's pre-registered to deal with legacy workers_not_supported
82
+ @workers.subList(1,@workers.size).each(&:register)
83
+ setup_multi_receive!
84
+ end
85
+
86
+ def setup_additional_workers!(target_worker_count)
87
+ warn_on_worker_override!
88
+
89
+ (target_worker_count - 1).times do
90
+ inst = @klass.new(@config)
91
+ @workers << inst
92
+ end
93
+
94
+ # This queue is used to manage sharing across threads
95
+ @worker_queue = SizedQueue.new(target_worker_count)
96
+ @workers.each {|w| @worker_queue << w }
97
+ end
98
+
99
+ def setup_multi_receive!
100
+ # One might wonder why we don't use something like
101
+ # define_singleton_method(:multi_receive, method(:threadsafe_multi_receive)
102
+ # and the answer is this is buggy on Jruby 1.7.x . It works 98% of the time!
103
+ # The other 2% you get weird errors about rebinding to the same object
104
+ # Until we switch to Jruby 9.x keep the define_singleton_method parts
105
+ # the way they are, with a block
106
+ # See https://github.com/jruby/jruby/issues/3582
107
+ if threadsafe?
108
+ @threadsafe_worker = @workers.first
109
+ define_singleton_method(:multi_receive) do |events|
110
+ threadsafe_multi_receive(events)
111
+ end
112
+ else
113
+ define_singleton_method(:multi_receive) do |events|
114
+ worker_multi_receive(events)
115
+ end
116
+ end
117
+ end
118
+
119
+ def threadsafe_multi_receive(events)
120
+ @events_received.increment(events.length)
121
+
122
+ @threadsafe_worker.multi_receive(events)
123
+ end
124
+
125
+ def worker_multi_receive(events)
126
+ @events_received.increment(events.length)
127
+
128
+ worker = @worker_queue.pop
129
+ begin
130
+ worker.multi_receive(events)
131
+ ensure
132
+ @worker_queue.push(worker)
133
+ end
134
+ end
135
+
136
+ def do_close
137
+ @logger.debug("closing output delegator", :klass => @klass)
138
+
139
+ if @threadsafe
140
+ @workers.each(&:do_close)
141
+ else
142
+ worker_count.times do
143
+ worker = @worker_queue.pop
144
+ worker.do_close
145
+ end
146
+ end
147
+ end
148
+
149
+ def events_received
150
+ @events_received.value
151
+ end
152
+
153
+ # There's no concept of 'busy' workers for a threadsafe plugin!
154
+ def busy_workers
155
+ if @threadsafe
156
+ 0
157
+ else
158
+ # The pipeline reporter can run before the outputs are registered trying to pull a value here
159
+ # In that case @worker_queue is empty, we just return 0
160
+ return 0 unless @worker_queue
161
+ @workers.size - @worker_queue.size
162
+ end
163
+ end
164
+
165
+ def worker_count
166
+ @workers.size
167
+ end
168
+
169
+ private
170
+ # Needed for testing, so private
171
+ attr_reader :threadsafe_worker, :worker_queue
172
+ end end