logstash-core 2.0.0.beta1-java → 2.0.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.
- checksums.yaml +4 -4
- data/lib/logstash/agent.rb +12 -3
- data/lib/logstash/codecs/base.rb +1 -1
- data/lib/logstash/config/cpu_core_strategy.rb +32 -0
- data/lib/logstash/config/defaults.rb +12 -0
- data/lib/logstash/config/mixin.rb +17 -0
- data/lib/logstash/filters/base.rb +7 -46
- data/lib/logstash/inputs/base.rb +29 -40
- data/lib/logstash/json.rb +10 -2
- data/lib/logstash/outputs/base.rb +6 -38
- data/lib/logstash/patches.rb +1 -0
- data/lib/logstash/patches/silence_concurrent_ruby_warning.rb +54 -0
- data/lib/logstash/patches/stronger_openssl_defaults.rb +1 -1
- data/lib/logstash/pipeline.rb +82 -97
- data/lib/logstash/plugin.rb +10 -60
- data/lib/logstash/string_interpolation.rb +1 -1
- data/lib/logstash/util/defaults_printer.rb +31 -0
- data/lib/logstash/util/worker_threads_default_printer.rb +17 -0
- data/lib/logstash/version.rb +1 -1
- data/locales/en.yml +4 -0
- data/logstash-core.gemspec +3 -1
- data/spec/core/config_cpu_core_strategy_spec.rb +123 -0
- data/spec/core/config_defaults_spec.rb +10 -0
- data/spec/core/config_mixin_spec.rb +54 -0
- data/spec/core/event_spec.rb +8 -0
- data/spec/core/pipeline_spec.rb +13 -13
- data/spec/filters/base_spec.rb +4 -71
- data/spec/license_spec.rb +13 -0
- data/spec/outputs/base_spec.rb +0 -21
- data/spec/util/defaults_printer_spec.rb +49 -0
- data/spec/util/worker_threads_default_printer_spec.rb +26 -0
- metadata +46 -7
- data/lib/logstash/multiqueue.rb +0 -53
- data/lib/logstash/util/require-helper.rb +0 -18
@@ -61,7 +61,7 @@ class OpenSSL::SSL::SSLContext
|
|
61
61
|
# For more details see: https://github.com/elastic/logstash/issues/3657
|
62
62
|
remove_const(:DEFAULT_PARAMS) if const_defined?(:DEFAULT_PARAMS)
|
63
63
|
DEFAULT_PARAMS = {
|
64
|
-
:ssl_version => "
|
64
|
+
:ssl_version => "TLS",
|
65
65
|
:ciphers => MOZILLA_INTERMEDIATE_CIPHERS,
|
66
66
|
:options => __default_options # Not a constant because it's computed at start-time.
|
67
67
|
}
|
data/lib/logstash/pipeline.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "thread"
|
2
|
+
require "thread"
|
3
3
|
require "stud/interval"
|
4
|
+
require "concurrent"
|
4
5
|
require "logstash/namespace"
|
5
6
|
require "logstash/errors"
|
6
7
|
require "logstash/event"
|
@@ -9,17 +10,24 @@ require "logstash/filters/base"
|
|
9
10
|
require "logstash/inputs/base"
|
10
11
|
require "logstash/outputs/base"
|
11
12
|
require "logstash/util/reporter"
|
13
|
+
require "logstash/config/cpu_core_strategy"
|
14
|
+
require "logstash/util/defaults_printer"
|
12
15
|
|
13
16
|
class LogStash::Pipeline
|
17
|
+
attr_reader :inputs, :filters, :outputs, :input_to_filter, :filter_to_output
|
14
18
|
|
15
19
|
def initialize(configstr)
|
16
20
|
@logger = Cabin::Channel.get(LogStash)
|
21
|
+
|
22
|
+
@inputs = nil
|
23
|
+
@filters = nil
|
24
|
+
@outputs = nil
|
25
|
+
|
17
26
|
grammar = LogStashConfigParser.new
|
18
27
|
@config = grammar.parse(configstr)
|
19
28
|
if @config.nil?
|
20
29
|
raise LogStash::ConfigurationError, grammar.failure_reason
|
21
30
|
end
|
22
|
-
|
23
31
|
# This will compile the config to ruby and evaluate the resulting code.
|
24
32
|
# The code will initialize all the plugins and define the
|
25
33
|
# filter and output methods.
|
@@ -34,36 +42,27 @@ class LogStash::Pipeline
|
|
34
42
|
end
|
35
43
|
|
36
44
|
@input_to_filter = SizedQueue.new(20)
|
45
|
+
# if no filters, pipe inputs directly to outputs
|
46
|
+
@filter_to_output = filters? ? SizedQueue.new(20) : @input_to_filter
|
37
47
|
|
38
|
-
# If no filters, pipe inputs directly to outputs
|
39
|
-
if !filters?
|
40
|
-
@filter_to_output = @input_to_filter
|
41
|
-
else
|
42
|
-
@filter_to_output = SizedQueue.new(20)
|
43
|
-
end
|
44
48
|
@settings = {
|
45
|
-
"filter-workers" =>
|
49
|
+
"filter-workers" => LogStash::Config::CpuCoreStrategy.fifty_percent
|
46
50
|
}
|
47
51
|
|
48
|
-
@
|
49
|
-
@ready = false
|
50
|
-
@started = false
|
52
|
+
# @ready requires thread safety since it is typically polled from outside the pipeline thread
|
53
|
+
@ready = Concurrent::AtomicBoolean.new(false)
|
51
54
|
@input_threads = []
|
52
55
|
end # def initialize
|
53
56
|
|
54
57
|
def ready?
|
55
|
-
@
|
56
|
-
end
|
57
|
-
|
58
|
-
def started?
|
59
|
-
@run_mutex.synchronize{@started}
|
58
|
+
@ready.value
|
60
59
|
end
|
61
60
|
|
62
61
|
def configure(setting, value)
|
63
|
-
if setting == "filter-workers"
|
62
|
+
if setting == "filter-workers" && value > 1
|
64
63
|
# Abort if we have any filters that aren't threadsafe
|
65
|
-
|
66
|
-
|
64
|
+
plugins = @filters.select { |f| !f.threadsafe? }.collect { |f| f.class.config_name }
|
65
|
+
if !plugins.size.zero?
|
67
66
|
raise LogStash::ConfigurationError, "Cannot use more than 1 filter worker because the following plugins don't work with more than one worker: #{plugins.join(", ")}"
|
68
67
|
end
|
69
68
|
end
|
@@ -75,14 +74,17 @@ class LogStash::Pipeline
|
|
75
74
|
end
|
76
75
|
|
77
76
|
def run
|
78
|
-
@
|
77
|
+
@logger.terminal(LogStash::Util::DefaultsPrinter.print(@settings))
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
begin
|
80
|
+
start_inputs
|
81
|
+
start_filters if filters?
|
82
|
+
start_outputs
|
83
|
+
ensure
|
84
|
+
# it is important to garantee @ready to be true after the startup sequence has been completed
|
85
|
+
# to potentially unblock the shutdown method which may be waiting on @ready to proceed
|
86
|
+
@ready.make_true
|
87
|
+
end
|
86
88
|
|
87
89
|
@logger.info("Pipeline started")
|
88
90
|
@logger.terminal("Logstash startup completed")
|
@@ -107,12 +109,6 @@ class LogStash::Pipeline
|
|
107
109
|
|
108
110
|
def wait_inputs
|
109
111
|
@input_threads.each(&:join)
|
110
|
-
rescue Interrupt
|
111
|
-
# rbx does weird things during do SIGINT that I haven't debugged
|
112
|
-
# so we catch Interrupt here and signal a shutdown. For some reason the
|
113
|
-
# signal handler isn't invoked it seems? I dunno, haven't looked much into
|
114
|
-
# it.
|
115
|
-
shutdown
|
116
112
|
end
|
117
113
|
|
118
114
|
def shutdown_filters
|
@@ -153,10 +149,17 @@ class LogStash::Pipeline
|
|
153
149
|
|
154
150
|
def start_filters
|
155
151
|
@filters.each(&:register)
|
156
|
-
|
152
|
+
to_start = @settings["filter-workers"]
|
153
|
+
@filter_threads = to_start.times.collect do
|
157
154
|
Thread.new { filterworker }
|
158
155
|
end
|
159
|
-
|
156
|
+
actually_started = @filter_threads.select(&:alive?).size
|
157
|
+
msg = "Worker threads expected: #{to_start}, worker threads started: #{actually_started}"
|
158
|
+
if actually_started < to_start
|
159
|
+
@logger.warn(msg)
|
160
|
+
else
|
161
|
+
@logger.info(msg)
|
162
|
+
end
|
160
163
|
@flusher_thread = Thread.new { Stud.interval(5) { @input_to_filter.push(LogStash::FLUSH) } }
|
161
164
|
end
|
162
165
|
|
@@ -175,9 +178,16 @@ class LogStash::Pipeline
|
|
175
178
|
LogStash::Util::set_thread_name("<#{plugin.class.config_name}")
|
176
179
|
begin
|
177
180
|
plugin.run(@input_to_filter)
|
178
|
-
rescue LogStash::ShutdownSignal
|
179
|
-
# ignore and quit
|
180
181
|
rescue => e
|
182
|
+
# if plugin is stopping, ignore uncatched exceptions and exit worker
|
183
|
+
if plugin.stop?
|
184
|
+
@logger.debug("Input plugin raised exception during shutdown, ignoring it.",
|
185
|
+
:plugin => plugin.class.config_name, :exception => e,
|
186
|
+
:backtrace => e.backtrace)
|
187
|
+
return
|
188
|
+
end
|
189
|
+
|
190
|
+
# otherwise, report error and restart
|
181
191
|
if @logger.debug?
|
182
192
|
@logger.error(I18n.t("logstash.pipeline.worker-error-debug",
|
183
193
|
:plugin => plugin.inspect, :error => e.to_s,
|
@@ -187,28 +197,18 @@ class LogStash::Pipeline
|
|
187
197
|
@logger.error(I18n.t("logstash.pipeline.worker-error",
|
188
198
|
:plugin => plugin.inspect, :error => e))
|
189
199
|
end
|
190
|
-
|
191
|
-
#
|
192
|
-
#
|
193
|
-
|
194
|
-
@run_mutex.synchronize{plugin.teardown}
|
195
|
-
sleep 1
|
196
|
-
retry
|
197
|
-
end
|
198
|
-
ensure
|
199
|
-
begin
|
200
|
-
# input teardown must be synchronized since is can be called concurrently by
|
201
|
-
# the input worker thread and from the pipeline thread shutdown method.
|
202
|
-
# this means that input teardown methods must support multiple calls.
|
203
|
-
@run_mutex.synchronize{plugin.teardown}
|
204
|
-
rescue LogStash::ShutdownSignal
|
205
|
-
# teardown could receive the ShutdownSignal, retry it
|
200
|
+
|
201
|
+
# Assuming the failure that caused this exception is transient,
|
202
|
+
# let's sleep for a bit and execute #run again
|
203
|
+
sleep(1)
|
206
204
|
retry
|
205
|
+
ensure
|
206
|
+
plugin.do_close
|
207
207
|
end
|
208
208
|
end # def inputworker
|
209
209
|
|
210
210
|
def filterworker
|
211
|
-
LogStash::Util
|
211
|
+
LogStash::Util.set_thread_name("|worker")
|
212
212
|
begin
|
213
213
|
while true
|
214
214
|
event = @input_to_filter.pop
|
@@ -227,65 +227,50 @@ class LogStash::Pipeline
|
|
227
227
|
break
|
228
228
|
end
|
229
229
|
end
|
230
|
-
rescue => e
|
231
|
-
|
230
|
+
rescue Exception => e
|
231
|
+
# Plugins authors should manage their own exceptions in the plugin code
|
232
|
+
# but if an exception is raised up to the worker thread they are considered
|
233
|
+
# fatal and logstash will not recover from this situation.
|
234
|
+
#
|
235
|
+
# Users need to check their configuration or see if there is a bug in the
|
236
|
+
# plugin.
|
237
|
+
@logger.error("Exception in filterworker, the pipeline stopped processing new events, please check your filter configuration and restart Logstash.",
|
238
|
+
"exception" => e, "backtrace" => e.backtrace)
|
239
|
+
raise
|
240
|
+
ensure
|
241
|
+
@filters.each(&:do_close)
|
232
242
|
end
|
233
|
-
|
234
|
-
@filters.each(&:teardown)
|
235
243
|
end # def filterworker
|
236
244
|
|
237
245
|
def outputworker
|
238
|
-
LogStash::Util
|
246
|
+
LogStash::Util.set_thread_name(">output")
|
239
247
|
@outputs.each(&:worker_setup)
|
240
248
|
|
241
249
|
while true
|
242
250
|
event = @filter_to_output.pop
|
243
251
|
break if event == LogStash::SHUTDOWN
|
244
252
|
output_func(event)
|
245
|
-
end
|
246
|
-
|
253
|
+
end
|
254
|
+
ensure
|
247
255
|
@outputs.each do |output|
|
248
|
-
output.worker_plugins.each(&:
|
256
|
+
output.worker_plugins.each(&:do_close)
|
249
257
|
end
|
250
258
|
end # def outputworker
|
251
259
|
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
255
|
-
def shutdown
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
@logger.info("Sending shutdown signal to input thread", :thread => thread)
|
261
|
-
|
262
|
-
# synchronize both ShutdownSignal and teardown below. by synchronizing both
|
263
|
-
# we will avoid potentially sending a shutdown signal when the inputworker is
|
264
|
-
# executing the teardown method.
|
265
|
-
@run_mutex.synchronize do
|
266
|
-
thread.raise(LogStash::ShutdownSignal)
|
267
|
-
begin
|
268
|
-
thread.wakeup # in case it's in blocked IO or sleeping
|
269
|
-
rescue ThreadError
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
260
|
+
# initiate the pipeline shutdown sequence
|
261
|
+
# this method is intended to be called from outside the pipeline thread
|
262
|
+
# @param before_stop [Proc] code block called before performing stop operation on input plugins
|
263
|
+
def shutdown(&before_stop)
|
264
|
+
# shutdown can only start once the pipeline has completed its startup.
|
265
|
+
# avoid potential race conditoon between the startup sequence and this
|
266
|
+
# shutdown method which can be called from another thread at any time
|
267
|
+
sleep(0.1) while !ready?
|
273
268
|
|
274
|
-
#
|
275
|
-
|
276
|
-
|
277
|
-
# input teardown must be synchronized since is can be called concurrently by
|
278
|
-
# the input worker thread and from the pipeline thread shutdown method.
|
279
|
-
# this means that input teardown methods must support multiple calls.
|
280
|
-
@run_mutex.synchronize{input.teardown}
|
281
|
-
rescue LogStash::ShutdownSignal
|
282
|
-
# teardown could receive the ShutdownSignal, retry it
|
283
|
-
retry
|
284
|
-
end
|
285
|
-
end
|
269
|
+
# TODO: should we also check against calling shutdown multiple times concurently?
|
270
|
+
|
271
|
+
before_stop.call if block_given?
|
286
272
|
|
287
|
-
|
288
|
-
# the inputs to finish, because in the #run method we wait for that anyway.
|
273
|
+
@inputs.each(&:do_stop)
|
289
274
|
end # def shutdown
|
290
275
|
|
291
276
|
def plugin(plugin_type, name, *args)
|
data/lib/logstash/plugin.rb
CHANGED
@@ -3,6 +3,7 @@ require "logstash/namespace"
|
|
3
3
|
require "logstash/logging"
|
4
4
|
require "logstash/config/mixin"
|
5
5
|
require "cabin"
|
6
|
+
require "concurrent"
|
6
7
|
|
7
8
|
class LogStash::Plugin
|
8
9
|
attr_accessor :params
|
@@ -27,72 +28,21 @@ class LogStash::Plugin
|
|
27
28
|
@logger = Cabin::Channel.get(LogStash)
|
28
29
|
end
|
29
30
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# You must also call 'super' in any subclasses.
|
31
|
+
# close is called during shutdown, after the plugin worker
|
32
|
+
# main task terminates
|
33
33
|
public
|
34
|
-
def
|
35
|
-
|
36
|
-
|
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
|
34
|
+
def do_close
|
35
|
+
@logger.debug("closing", :plugin => self)
|
36
|
+
close
|
72
37
|
end
|
73
38
|
|
74
|
-
#
|
39
|
+
# Subclasses should implement this close method if you need to perform any
|
40
|
+
# special tasks during shutdown (like flushing, etc.)
|
75
41
|
public
|
76
|
-
def
|
77
|
-
#
|
42
|
+
def close
|
43
|
+
# ..
|
78
44
|
end
|
79
45
|
|
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
46
|
def to_s
|
97
47
|
return "#{self.class.name}: #{@params}"
|
98
48
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "logstash/util"
|
4
|
+
require "logstash/util/worker_threads_default_printer"
|
5
|
+
|
6
|
+
|
7
|
+
# This class exists to format the settings for defaults used
|
8
|
+
module LogStash module Util class DefaultsPrinter
|
9
|
+
def self.print(settings)
|
10
|
+
new(settings).print
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(settings)
|
14
|
+
@settings = settings
|
15
|
+
@printers = [workers]
|
16
|
+
end
|
17
|
+
|
18
|
+
def print
|
19
|
+
collector = []
|
20
|
+
@printers.each do |printer|
|
21
|
+
printer.visit(collector)
|
22
|
+
end
|
23
|
+
"Default settings used: " + collector.join(', ')
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def workers
|
29
|
+
WorkerThreadsDefaultPrinter.new(@settings)
|
30
|
+
end
|
31
|
+
end end end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "logstash/util"
|
4
|
+
|
5
|
+
# This class exists to format the settings for default worker threads
|
6
|
+
module LogStash module Util class WorkerThreadsDefaultPrinter
|
7
|
+
|
8
|
+
def initialize(settings)
|
9
|
+
@setting = settings.fetch('filter-workers', 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit(collector)
|
13
|
+
collector.push "Filter workers: #{@setting}"
|
14
|
+
end
|
15
|
+
|
16
|
+
end end end
|
17
|
+
|
data/lib/logstash/version.rb
CHANGED