logstash-core 1.5.0.beta2-java

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-event.rb +2 -0
  3. data/lib/logstash.rb +4 -0
  4. data/lib/logstash/JRUBY-PR1448.rb +32 -0
  5. data/lib/logstash/agent.rb +355 -0
  6. data/lib/logstash/bundler.rb +124 -0
  7. data/lib/logstash/codecs/base.rb +50 -0
  8. data/lib/logstash/config/config_ast.rb +508 -0
  9. data/lib/logstash/config/file.rb +39 -0
  10. data/lib/logstash/config/grammar.rb +3503 -0
  11. data/lib/logstash/config/mixin.rb +495 -0
  12. data/lib/logstash/config/registry.rb +13 -0
  13. data/lib/logstash/environment.rb +168 -0
  14. data/lib/logstash/errors.rb +12 -0
  15. data/lib/logstash/event.rb +310 -0
  16. data/lib/logstash/filters/base.rb +239 -0
  17. data/lib/logstash/gemfile.rb +175 -0
  18. data/lib/logstash/inputs/base.rb +137 -0
  19. data/lib/logstash/inputs/threadable.rb +18 -0
  20. data/lib/logstash/java_integration.rb +41 -0
  21. data/lib/logstash/json.rb +53 -0
  22. data/lib/logstash/logging.rb +91 -0
  23. data/lib/logstash/multiqueue.rb +53 -0
  24. data/lib/logstash/namespace.rb +17 -0
  25. data/lib/logstash/outputs/base.rb +124 -0
  26. data/lib/logstash/patches.rb +3 -0
  27. data/lib/logstash/patches/bugfix_jruby_2558.rb +50 -0
  28. data/lib/logstash/patches/cabin.rb +34 -0
  29. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  30. data/lib/logstash/pipeline.rb +305 -0
  31. data/lib/logstash/plugin.rb +177 -0
  32. data/lib/logstash/pluginmanager.rb +17 -0
  33. data/lib/logstash/pluginmanager/install.rb +112 -0
  34. data/lib/logstash/pluginmanager/list.rb +38 -0
  35. data/lib/logstash/pluginmanager/main.rb +22 -0
  36. data/lib/logstash/pluginmanager/maven_tools_patch.rb +12 -0
  37. data/lib/logstash/pluginmanager/uninstall.rb +49 -0
  38. data/lib/logstash/pluginmanager/update.rb +50 -0
  39. data/lib/logstash/pluginmanager/util.rb +88 -0
  40. data/lib/logstash/program.rb +15 -0
  41. data/lib/logstash/runner.rb +167 -0
  42. data/lib/logstash/sized_queue.rb +8 -0
  43. data/lib/logstash/threadwatchdog.rb +37 -0
  44. data/lib/logstash/timestamp.rb +97 -0
  45. data/lib/logstash/util.rb +152 -0
  46. data/lib/logstash/util/accessors.rb +88 -0
  47. data/lib/logstash/util/buftok.rb +139 -0
  48. data/lib/logstash/util/charset.rb +35 -0
  49. data/lib/logstash/util/fieldreference.rb +68 -0
  50. data/lib/logstash/util/filetools.rb +185 -0
  51. data/lib/logstash/util/password.rb +25 -0
  52. data/lib/logstash/util/plugin_version.rb +43 -0
  53. data/lib/logstash/util/prctl.rb +11 -0
  54. data/lib/logstash/util/require-helper.rb +18 -0
  55. data/lib/logstash/util/retryable.rb +39 -0
  56. data/lib/logstash/util/socket_peer.rb +7 -0
  57. data/lib/logstash/version.rb +6 -0
  58. data/locales/en.yml +176 -0
  59. metadata +427 -0
@@ -0,0 +1,34 @@
1
+ if ENV["PROFILE_BAD_LOG_CALLS"] || ($DEBUGLIST || []).include?("log")
2
+ # Set PROFILE_BAD_LOG_CALLS=1 in your environment if you want
3
+ # to track down logger calls that cause performance problems
4
+ #
5
+ # Related research here:
6
+ # https://github.com/jordansissel/experiments/tree/master/ruby/logger-string-vs-block
7
+ #
8
+ # Basically, the following is wastes tons of effort creating objects that are
9
+ # never used if the log level hides the log:
10
+ #
11
+ # logger.debug("something happend", :what => Happened)
12
+ #
13
+ # This is shown to be 4x faster:
14
+ #
15
+ # logger.debug(...) if logger.debug?
16
+ #
17
+ # I originally intended to use RubyParser and SexpProcessor to
18
+ # process all the logstash ruby code offline, but it was much
19
+ # faster to write this monkeypatch to warn as things are called.
20
+ require "cabin/mixins/logger"
21
+ module Cabin::Mixins::Logger
22
+ LEVELS.keys.each do |level|
23
+ m = "original_#{level}".to_sym
24
+ predicate = "#{level}?".to_sym
25
+ alias_method m, level
26
+ define_method(level) do |*args|
27
+ if !send(predicate)
28
+ warn("Unconditional log call", :location => caller[0])
29
+ end
30
+ send(m, *args)
31
+ end
32
+ end
33
+ end
34
+ end # PROFILE_BAD_LOG_CALLS
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ if ($DEBUGLIST || []).include?("require")
3
+ ROOT = File.dirname(__FILE__)
4
+ module Kernel
5
+ alias_method :require_debug, :require
6
+
7
+ def require(path)
8
+ start = Time.now
9
+ result = require_debug(path)
10
+ duration = Time.now - start
11
+
12
+ origin = caller[1]
13
+ if origin =~ /rubygems\/custom_require/
14
+ origin = caller[3]
15
+ if origin.nil?
16
+ STDERR.puts "Unknown origin"
17
+ STDERR.puts caller.join("\n")
18
+ end
19
+ end
20
+ origin = origin.gsub(/:[0-9]+:in .*/, "") if origin
21
+
22
+ # Only print require() calls that did actual work.
23
+ # require() returns true on load, false if already loaded.
24
+ if result
25
+ source = caller[0]
26
+ #p source.include?("/lib/polyglot.rb:63:in `require'") => source
27
+ if source.include?("/lib/polyglot.rb:63:in `require'")
28
+ source = caller[1]
29
+ end
30
+
31
+ #target = $LOADED_FEATURES.grep(/#{path}/).first
32
+ #puts path
33
+ #puts caller.map { |c| " #{c}" }.join("\n")
34
+ #fontsize = [10, duration * 48].max
35
+ puts "#{duration},#{path},#{source}"
36
+ end
37
+ #puts caller.map { |c| " => #{c}" }.join("\n")
38
+ end
39
+
40
+ alias_method :load_debug, :load
41
+
42
+ def load(path)
43
+ puts "load(\"#{path}\")"
44
+ return load_debug(path)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,305 @@
1
+ # encoding: utf-8
2
+ require "thread" #
3
+ require "stud/interval"
4
+ require "logstash/namespace"
5
+ require "logstash/errors"
6
+ require "logstash/event"
7
+ require "logstash/config/file"
8
+ require "logstash/filters/base"
9
+ require "logstash/inputs/base"
10
+ require "logstash/outputs/base"
11
+
12
+ class LogStash::Pipeline
13
+
14
+ FLUSH_EVENT = LogStash::FlushEvent.new
15
+
16
+ def initialize(configstr)
17
+ @logger = Cabin::Channel.get(LogStash)
18
+ grammar = LogStashConfigParser.new
19
+ @config = grammar.parse(configstr)
20
+ if @config.nil?
21
+ raise LogStash::ConfigurationError, grammar.failure_reason
22
+ end
23
+
24
+ # This will compile the config to ruby and evaluate the resulting code.
25
+ # The code will initialize all the plugins and define the
26
+ # filter and output methods.
27
+ code = @config.compile
28
+ # The config code is hard to represent as a log message...
29
+ # So just print it.
30
+ @logger.debug? && @logger.debug("Compiled pipeline code:\n#{code}")
31
+ begin
32
+ eval(code)
33
+ rescue => e
34
+ raise
35
+ end
36
+
37
+ @input_to_filter = SizedQueue.new(20)
38
+
39
+ # If no filters, pipe inputs directly to outputs
40
+ if !filters?
41
+ @filter_to_output = @input_to_filter
42
+ else
43
+ @filter_to_output = SizedQueue.new(20)
44
+ end
45
+ @settings = {
46
+ "filter-workers" => 1,
47
+ }
48
+ end # def initialize
49
+
50
+ def ready?
51
+ return @ready
52
+ end
53
+
54
+ def started?
55
+ return @started
56
+ end
57
+
58
+ def configure(setting, value)
59
+ if setting == "filter-workers"
60
+ # Abort if we have any filters that aren't threadsafe
61
+ if value > 1 && @filters.any? { |f| !f.threadsafe? }
62
+ plugins = @filters.select { |f| !f.threadsafe? }.collect { |f| f.class.config_name }
63
+ raise LogStash::ConfigurationError, "Cannot use more than 1 filter worker because the following plugins don't work with more than one worker: #{plugins.join(", ")}"
64
+ end
65
+ end
66
+ @settings[setting] = value
67
+ end
68
+
69
+ def filters?
70
+ return @filters.any?
71
+ end
72
+
73
+ def run
74
+ @started = true
75
+ @input_threads = []
76
+
77
+ start_inputs
78
+ start_filters if filters?
79
+ start_outputs
80
+
81
+ @ready = true
82
+
83
+ @logger.info("Pipeline started")
84
+ @logger.terminal("Logstash startup completed")
85
+
86
+ wait_inputs
87
+
88
+ if filters?
89
+ shutdown_filters
90
+ wait_filters
91
+ flush_filters_to_output!(:final => true)
92
+ end
93
+
94
+ shutdown_outputs
95
+ wait_outputs
96
+
97
+ @logger.info("Pipeline shutdown complete.")
98
+ @logger.terminal("Logstash shutdown completed")
99
+
100
+ # exit code
101
+ return 0
102
+ end # def run
103
+
104
+ def wait_inputs
105
+ @input_threads.each(&:join)
106
+ rescue Interrupt
107
+ # rbx does weird things during do SIGINT that I haven't debugged
108
+ # so we catch Interrupt here and signal a shutdown. For some reason the
109
+ # signal handler isn't invoked it seems? I dunno, haven't looked much into
110
+ # it.
111
+ shutdown
112
+ end
113
+
114
+ def shutdown_filters
115
+ @flusher_lock.synchronize { @flusher_thread.kill }
116
+ @input_to_filter.push(LogStash::ShutdownEvent.new)
117
+ end
118
+
119
+ def wait_filters
120
+ @filter_threads.each(&:join) if @filter_threads
121
+ end
122
+
123
+ def shutdown_outputs
124
+ # nothing, filters will do this
125
+ @filter_to_output.push(LogStash::ShutdownEvent.new)
126
+ end
127
+
128
+ def wait_outputs
129
+ # Wait for the outputs to stop
130
+ @output_threads.each(&:join)
131
+ end
132
+
133
+ def start_inputs
134
+ moreinputs = []
135
+ @inputs.each do |input|
136
+ if input.threadable && input.threads > 1
137
+ (input.threads-1).times do |i|
138
+ moreinputs << input.clone
139
+ end
140
+ end
141
+ end
142
+ @inputs += moreinputs
143
+
144
+ @inputs.each do |input|
145
+ input.register
146
+ start_input(input)
147
+ end
148
+ end
149
+
150
+ def start_filters
151
+ @filters.each(&:register)
152
+ @filter_threads = @settings["filter-workers"].times.collect do
153
+ Thread.new { filterworker }
154
+ end
155
+
156
+ @flusher_lock = Mutex.new
157
+ @flusher_thread = Thread.new { Stud.interval(5) { @flusher_lock.synchronize { @input_to_filter.push(FLUSH_EVENT) } } }
158
+ end
159
+
160
+ def start_outputs
161
+ @outputs.each(&:register)
162
+ @output_threads = [
163
+ Thread.new { outputworker }
164
+ ]
165
+ end
166
+
167
+ def start_input(plugin)
168
+ @input_threads << Thread.new { inputworker(plugin) }
169
+ end
170
+
171
+ def inputworker(plugin)
172
+ LogStash::Util::set_thread_name("<#{plugin.class.config_name}")
173
+ begin
174
+ plugin.run(@input_to_filter)
175
+ rescue LogStash::ShutdownSignal
176
+ return
177
+ rescue => e
178
+ if @logger.debug?
179
+ @logger.error(I18n.t("logstash.pipeline.worker-error-debug",
180
+ :plugin => plugin.inspect, :error => e.to_s,
181
+ :exception => e.class,
182
+ :stacktrace => e.backtrace.join("\n")))
183
+ else
184
+ @logger.error(I18n.t("logstash.pipeline.worker-error",
185
+ :plugin => plugin.inspect, :error => e))
186
+ end
187
+ puts e.backtrace if @logger.debug?
188
+ plugin.teardown
189
+ sleep 1
190
+ retry
191
+ end
192
+ rescue LogStash::ShutdownSignal
193
+ # nothing
194
+ ensure
195
+ plugin.teardown
196
+ end # def inputworker
197
+
198
+ def filterworker
199
+ LogStash::Util::set_thread_name("|worker")
200
+ begin
201
+ while true
202
+ event = @input_to_filter.pop
203
+
204
+ case event
205
+ when LogStash::Event
206
+ # use events array to guarantee ordering of origin vs created events
207
+ # where created events are emitted by filters like split or metrics
208
+ events = []
209
+ filter(event) { |newevent| events << newevent }
210
+ events.each { |event| @filter_to_output.push(event) }
211
+ when LogStash::FlushEvent
212
+ # handle filter flushing here so that non threadsafe filters (thus only running one filterworker)
213
+ # don't have to deal with thread safety implementing the flush method
214
+ @flusher_lock.synchronize { flush_filters_to_output! }
215
+ when LogStash::ShutdownEvent
216
+ # pass it down to any other filterworker and stop this worker
217
+ @input_to_filter.push(event)
218
+ break
219
+ end
220
+ end
221
+ rescue => e
222
+ @logger.error("Exception in filterworker", "exception" => e, "backtrace" => e.backtrace)
223
+ end
224
+
225
+ @filters.each(&:teardown)
226
+ end # def filterworker
227
+
228
+ def outputworker
229
+ LogStash::Util::set_thread_name(">output")
230
+ @outputs.each(&:worker_setup)
231
+
232
+ while true
233
+ event = @filter_to_output.pop
234
+ break if event.is_a?(LogStash::ShutdownEvent)
235
+ output(event)
236
+ end # while true
237
+
238
+ @outputs.each do |output|
239
+ output.worker_plugins.each(&:teardown)
240
+ end
241
+ end # def outputworker
242
+
243
+ # Shutdown this pipeline.
244
+ #
245
+ # This method is intended to be called from another thread
246
+ def shutdown
247
+ @input_threads.each do |thread|
248
+ # Interrupt all inputs
249
+ @logger.info("Sending shutdown signal to input thread",
250
+ :thread => thread)
251
+ thread.raise(LogStash::ShutdownSignal)
252
+ begin
253
+ thread.wakeup # in case it's in blocked IO or sleeping
254
+ rescue ThreadError
255
+ end
256
+
257
+ # Sometimes an input is stuck in a blocking I/O
258
+ # so we need to tell it to teardown directly
259
+ @inputs.each do |input|
260
+ input.teardown
261
+ end
262
+ end
263
+
264
+ # No need to send the ShutdownEvent to the filters/outputs nor to wait for
265
+ # the inputs to finish, because in the #run method we wait for that anyway.
266
+ end # def shutdown
267
+
268
+ def plugin(plugin_type, name, *args)
269
+ args << {} if args.empty?
270
+ klass = LogStash::Plugin.lookup(plugin_type, name)
271
+ return klass.new(*args)
272
+ end
273
+
274
+ def filter(event, &block)
275
+ @filter_func.call(event, &block)
276
+ end
277
+
278
+ def output(event)
279
+ @output_func.call(event)
280
+ end
281
+
282
+ # perform filters flush and yeild flushed event to the passed block
283
+ # @param options [Hash]
284
+ # @option options [Boolean] :final => true to signal a final shutdown flush
285
+ def flush_filters(options = {}, &block)
286
+ flushers = options[:final] ? @shutdown_flushers : @periodic_flushers
287
+
288
+ flushers.each do |flusher|
289
+ flusher.call(options, &block)
290
+ end
291
+ end
292
+
293
+ # perform filters flush into the output queue
294
+ # @param options [Hash]
295
+ # @option options [Boolean] :final => true to signal a final shutdown flush
296
+ def flush_filters_to_output!(options = {})
297
+ flush_filters(options) do |event|
298
+ unless event.cancelled?
299
+ @logger.debug? and @logger.debug("Pushing flushed events", :event => event)
300
+ @filter_to_output.push(event)
301
+ end
302
+ end
303
+ end # flush_filters_to_output!
304
+
305
+ end # class Pipeline
@@ -0,0 +1,177 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/logging"
4
+ require "logstash/config/mixin"
5
+ require "cabin"
6
+
7
+ class LogStash::Plugin
8
+ attr_accessor :params
9
+ attr_accessor :logger
10
+
11
+ NL = "\n"
12
+
13
+ public
14
+ def hash
15
+ params.hash ^
16
+ self.class.name.hash
17
+ end
18
+
19
+ public
20
+ def eql?(other)
21
+ self.class.name == other.class.name && @params == other.params
22
+ end
23
+
24
+ public
25
+ def initialize(params=nil)
26
+ @params = params
27
+ @logger = Cabin::Channel.get(LogStash)
28
+ end
29
+
30
+ # This method is called when someone or something wants this plugin to shut
31
+ # down. When you successfully shutdown, you must call 'finished'
32
+ # You must also call 'super' in any subclasses.
33
+ public
34
+ def shutdown(queue)
35
+ # By default, shutdown is assumed a no-op for all plugins.
36
+ # If you need to take special efforts to shutdown (like waiting for
37
+ # an operation to complete, etc)
38
+ teardown
39
+ @logger.info("Received shutdown signal", :plugin => self)
40
+
41
+ @shutdown_queue = queue
42
+ if @plugin_state == :finished
43
+ finished
44
+ else
45
+ @plugin_state = :terminating
46
+ end
47
+ end # def shutdown
48
+
49
+ # You should call this method when you (the plugin) are done with work
50
+ # forever.
51
+ public
52
+ def finished
53
+ # TODO(sissel): I'm not sure what I had planned for this shutdown_queue
54
+ # thing
55
+ if @shutdown_queue
56
+ @logger.info("Sending shutdown event to agent queue", :plugin => self)
57
+ @shutdown_queue << self
58
+ end
59
+
60
+ if @plugin_state != :finished
61
+ @logger.info("Plugin is finished", :plugin => self)
62
+ @plugin_state = :finished
63
+ end
64
+ end # def finished
65
+
66
+ # Subclasses should implement this teardown method if you need to perform any
67
+ # special tasks during shutdown (like flushing, etc.)
68
+ public
69
+ def teardown
70
+ # nothing by default
71
+ finished
72
+ end
73
+
74
+ # This method is called when a SIGHUP triggers a reload operation
75
+ public
76
+ def reload
77
+ # Do nothing by default
78
+ end
79
+
80
+ public
81
+ def finished?
82
+ return @plugin_state == :finished
83
+ end # def finished?
84
+
85
+ public
86
+ def running?
87
+ return @plugin_state != :finished
88
+ end # def finished?
89
+
90
+ public
91
+ def terminating?
92
+ return @plugin_state == :terminating
93
+ end # def terminating?
94
+
95
+ public
96
+ def to_s
97
+ return "#{self.class.name}: #{@params}"
98
+ end
99
+
100
+ protected
101
+ def update_watchdog(state)
102
+ Thread.current[:watchdog] = Time.now
103
+ Thread.current[:watchdog_state] = state
104
+ end
105
+
106
+ protected
107
+ def clear_watchdog
108
+ Thread.current[:watchdog] = nil
109
+ Thread.current[:watchdog_state] = nil
110
+ end
111
+
112
+ public
113
+ def inspect
114
+ if !@config.nil?
115
+ description = @config \
116
+ .select { |k,v| !v.nil? && (v.respond_to?(:empty?) && !v.empty?) } \
117
+ .collect { |k,v| "#{k}=>#{v.inspect}" }
118
+ return "<#{self.class.name} #{description.join(", ")}>"
119
+ else
120
+ return "<#{self.class.name} --->"
121
+ end
122
+ end
123
+
124
+ # Look up a plugin by type and name.
125
+ public
126
+ def self.lookup(type, name)
127
+ path = "logstash/#{type}s/#{name}"
128
+
129
+ # first check if plugin already exists in namespace and continue to next step if not
130
+ begin
131
+ return namespace_lookup(type, name)
132
+ rescue NameError
133
+ logger.debug("Plugin not defined in namespace, checking for plugin file", :type => type, :name => name, :path => path)
134
+ end
135
+
136
+ # try to load the plugin file. ex.: lookup("filter", "grok") will require logstash/filters/grok
137
+ require(path)
138
+
139
+ # check again if plugin is now defined in namespace after the require
140
+ namespace_lookup(type, name)
141
+ rescue LoadError, NameError => e
142
+ raise(LogStash::PluginLoadingError, I18n.t("logstash.pipeline.plugin-loading-error", :type => type, :name => name, :path => path, :error => e.to_s))
143
+ end
144
+
145
+ private
146
+
147
+ # lookup a plugin by type and name in the existing LogStash module namespace
148
+ # ex.: namespace_lookup("filter", "grok") looks for LogStash::Filters::Grok
149
+ # @param type [String] plugin type, "input", "ouput", "filter"
150
+ # @param name [String] plugin name, ex.: "grok"
151
+ # @return [Class] the plugin class or raises NameError
152
+ # @raise NameError if plugin class does not exist or is invalid
153
+ def self.namespace_lookup(type, name)
154
+ type_const = "#{type.capitalize}s"
155
+ namespace = LogStash.const_get(type_const)
156
+ # the namespace can contain constants which are not for plugins classes (do not respond to :config_name)
157
+ # namespace.constants is the shallow collection of all constants symbols in namespace
158
+ # note that below namespace.const_get(c) should never result in a NameError since c is from the constants collection
159
+ klass_sym = namespace.constants.find { |c| is_a_plugin?(namespace.const_get(c), name) }
160
+ klass = klass_sym && namespace.const_get(klass_sym)
161
+ raise(NameError) unless klass
162
+ klass
163
+ end
164
+
165
+ # check if klass is a valid plugin for name
166
+ # @param klass [Class] plugin class
167
+ # @param name [String] plugin name
168
+ # @return [Boolean] true if klass is a valid plugin for name
169
+ def self.is_a_plugin?(klass, name)
170
+ klass.ancestors.include?(LogStash::Plugin) && klass.respond_to?(:config_name) && klass.config_name == name
171
+ end
172
+
173
+ # @return [Cabin::Channel] logger channel for class methods
174
+ def self.logger
175
+ @logger ||= Cabin::Channel.get(LogStash)
176
+ end
177
+ end # class LogStash::Plugin