logstash-core 1.5.0.beta2-java
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.
- checksums.yaml +7 -0
- data/lib/logstash-event.rb +2 -0
- data/lib/logstash.rb +4 -0
- data/lib/logstash/JRUBY-PR1448.rb +32 -0
- data/lib/logstash/agent.rb +355 -0
- data/lib/logstash/bundler.rb +124 -0
- data/lib/logstash/codecs/base.rb +50 -0
- data/lib/logstash/config/config_ast.rb +508 -0
- data/lib/logstash/config/file.rb +39 -0
- data/lib/logstash/config/grammar.rb +3503 -0
- data/lib/logstash/config/mixin.rb +495 -0
- data/lib/logstash/config/registry.rb +13 -0
- data/lib/logstash/environment.rb +168 -0
- data/lib/logstash/errors.rb +12 -0
- data/lib/logstash/event.rb +310 -0
- data/lib/logstash/filters/base.rb +239 -0
- data/lib/logstash/gemfile.rb +175 -0
- data/lib/logstash/inputs/base.rb +137 -0
- data/lib/logstash/inputs/threadable.rb +18 -0
- data/lib/logstash/java_integration.rb +41 -0
- data/lib/logstash/json.rb +53 -0
- data/lib/logstash/logging.rb +91 -0
- data/lib/logstash/multiqueue.rb +53 -0
- data/lib/logstash/namespace.rb +17 -0
- data/lib/logstash/outputs/base.rb +124 -0
- data/lib/logstash/patches.rb +3 -0
- data/lib/logstash/patches/bugfix_jruby_2558.rb +50 -0
- data/lib/logstash/patches/cabin.rb +34 -0
- data/lib/logstash/patches/profile_require_calls.rb +47 -0
- data/lib/logstash/pipeline.rb +305 -0
- data/lib/logstash/plugin.rb +177 -0
- data/lib/logstash/pluginmanager.rb +17 -0
- data/lib/logstash/pluginmanager/install.rb +112 -0
- data/lib/logstash/pluginmanager/list.rb +38 -0
- data/lib/logstash/pluginmanager/main.rb +22 -0
- data/lib/logstash/pluginmanager/maven_tools_patch.rb +12 -0
- data/lib/logstash/pluginmanager/uninstall.rb +49 -0
- data/lib/logstash/pluginmanager/update.rb +50 -0
- data/lib/logstash/pluginmanager/util.rb +88 -0
- data/lib/logstash/program.rb +15 -0
- data/lib/logstash/runner.rb +167 -0
- data/lib/logstash/sized_queue.rb +8 -0
- data/lib/logstash/threadwatchdog.rb +37 -0
- data/lib/logstash/timestamp.rb +97 -0
- data/lib/logstash/util.rb +152 -0
- data/lib/logstash/util/accessors.rb +88 -0
- data/lib/logstash/util/buftok.rb +139 -0
- data/lib/logstash/util/charset.rb +35 -0
- data/lib/logstash/util/fieldreference.rb +68 -0
- data/lib/logstash/util/filetools.rb +185 -0
- data/lib/logstash/util/password.rb +25 -0
- data/lib/logstash/util/plugin_version.rb +43 -0
- data/lib/logstash/util/prctl.rb +11 -0
- data/lib/logstash/util/require-helper.rb +18 -0
- data/lib/logstash/util/retryable.rb +39 -0
- data/lib/logstash/util/socket_peer.rb +7 -0
- data/lib/logstash/version.rb +6 -0
- data/locales/en.yml +176 -0
- 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
|