logstash-core 5.2.1-java → 5.2.2-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.
- checksums.yaml +4 -4
- data/lib/logstash-core/logstash-core.jar +0 -0
- data/lib/logstash-core/version.rb +1 -1
- data/lib/logstash/agent.rb +110 -39
- data/lib/logstash/instrument/periodic_poller/jvm.rb +4 -9
- data/lib/logstash/pipeline.rb +136 -99
- data/lib/logstash/runner.rb +1 -1
- data/lib/logstash/version.rb +1 -1
- data/spec/logstash/agent_spec.rb +34 -12
- data/spec/logstash/pipeline_spec.rb +68 -8
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72571fd4dcaa96000b854ac8362522c0db5d3e82
|
4
|
+
data.tar.gz: 6ff9cf5d47543adfb8e45d6b28163bebe9ce40ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7aaa38c146c061f56e6654b70bcfda14c89516ebca3a98fdad2f7b347b423bc78eae89cef47547ee6a1aaa725fda4ab2c9849942ec1619eecba862996d34458
|
7
|
+
data.tar.gz: 3111f88041c5367e1724c741c625875c3bbe0e8035107b86ac60fb7651922c8b4efa5f71d02495674549eec75d5a34fbcb6ddf80c49b515e6bd73eedf64c5ffb
|
Binary file
|
data/lib/logstash/agent.rb
CHANGED
@@ -189,7 +189,22 @@ class LogStash::Agent
|
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
+
def close_pipeline(id)
|
193
|
+
pipeline = @pipelines[id]
|
194
|
+
if pipeline
|
195
|
+
@logger.warn("closing pipeline", :id => id)
|
196
|
+
pipeline.close
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def close_pipelines
|
201
|
+
@pipelines.each do |id, _|
|
202
|
+
close_pipeline(id)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
192
206
|
private
|
207
|
+
|
193
208
|
def start_webserver
|
194
209
|
options = {:http_host => @http_host, :http_ports => @http_port, :http_environment => @http_environment }
|
195
210
|
@webserver = LogStash::WebServer.new(@logger, self, options)
|
@@ -232,7 +247,21 @@ class LogStash::Agent
|
|
232
247
|
@collect_metric
|
233
248
|
end
|
234
249
|
|
235
|
-
def
|
250
|
+
def increment_reload_failures_metrics(id, message, backtrace = nil)
|
251
|
+
@instance_reload_metric.increment(:failures)
|
252
|
+
@pipeline_reload_metric.namespace([id.to_sym, :reloads]).tap do |n|
|
253
|
+
n.increment(:failures)
|
254
|
+
n.gauge(:last_error, { :message => message, :backtrace =>backtrace})
|
255
|
+
n.gauge(:last_failure_timestamp, LogStash::Timestamp.now)
|
256
|
+
end
|
257
|
+
if @logger.debug?
|
258
|
+
@logger.error("Cannot load an invalid configuration", :reason => message, :backtrace => backtrace)
|
259
|
+
else
|
260
|
+
@logger.error("Cannot load an invalid configuration", :reason => message)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def create_pipeline(settings, config = nil)
|
236
265
|
if config.nil?
|
237
266
|
begin
|
238
267
|
config = fetch_config(settings)
|
@@ -245,17 +274,7 @@ class LogStash::Agent
|
|
245
274
|
begin
|
246
275
|
LogStash::Pipeline.new(config, settings, metric)
|
247
276
|
rescue => e
|
248
|
-
|
249
|
-
@pipeline_reload_metric.namespace([settings.get("pipeline.id").to_sym, :reloads]).tap do |n|
|
250
|
-
n.increment(:failures)
|
251
|
-
n.gauge(:last_error, { :message => e.message, :backtrace => e.backtrace})
|
252
|
-
n.gauge(:last_failure_timestamp, LogStash::Timestamp.now)
|
253
|
-
end
|
254
|
-
if @logger.debug?
|
255
|
-
@logger.error("fetched an invalid config", :config => config, :reason => e.message, :backtrace => e.backtrace)
|
256
|
-
else
|
257
|
-
@logger.error("fetched an invalid config", :config => config, :reason => e.message)
|
258
|
-
end
|
277
|
+
increment_reload_failures_metrics(settings.get("pipeline.id"), e.message, e.backtrace)
|
259
278
|
return
|
260
279
|
end
|
261
280
|
end
|
@@ -264,30 +283,96 @@ class LogStash::Agent
|
|
264
283
|
@config_loader.format_config(settings.get("path.config"), settings.get("config.string"))
|
265
284
|
end
|
266
285
|
|
267
|
-
#
|
268
|
-
# wrapped in @upgrade_mutex in the parent call `reload_state!`
|
286
|
+
# reload_pipeline trys to reloads the pipeline with id using a potential new configuration if it changed
|
287
|
+
# since this method modifies the @pipelines hash it is wrapped in @upgrade_mutex in the parent call `reload_state!`
|
288
|
+
# @param id [String] the pipeline id to reload
|
269
289
|
def reload_pipeline!(id)
|
270
290
|
old_pipeline = @pipelines[id]
|
271
291
|
new_config = fetch_config(old_pipeline.settings)
|
292
|
+
|
272
293
|
if old_pipeline.config_str == new_config
|
273
|
-
@logger.debug("no configuration change for pipeline",
|
274
|
-
|
294
|
+
@logger.debug("no configuration change for pipeline", :pipeline => id)
|
295
|
+
return
|
296
|
+
end
|
297
|
+
|
298
|
+
# check if this pipeline is not reloadable. it should not happen as per the check below
|
299
|
+
# but keep it here as a safety net if a reloadable pipeline was releoaded with a non reloadable pipeline
|
300
|
+
if old_pipeline.non_reloadable_plugins.any?
|
301
|
+
@logger.error("pipeline is not reloadable", :pipeline => id)
|
302
|
+
return
|
303
|
+
end
|
304
|
+
|
305
|
+
# BasePipeline#initialize will compile the config, and load all plugins and raise an exception
|
306
|
+
# on an invalid configuration
|
307
|
+
begin
|
308
|
+
pipeline_validator = LogStash::BasePipeline.new(new_config, old_pipeline.settings)
|
309
|
+
rescue => e
|
310
|
+
increment_reload_failures_metrics(id, e.message, e.backtrace)
|
311
|
+
return
|
312
|
+
end
|
313
|
+
|
314
|
+
# check if the new pipeline will be reloadable in which case we want to log that as an error and abort
|
315
|
+
if pipeline_validator.non_reloadable_plugins.any?
|
316
|
+
@logger.error(I18n.t("logstash.agent.non_reloadable_config_reload"), :pipeline_id => id, :plugins => pipeline_validator.non_reloadable_plugins.map(&:class))
|
317
|
+
increment_reload_failures_metrics(id, "non reloadable pipeline")
|
275
318
|
return
|
276
319
|
end
|
277
320
|
|
278
|
-
|
321
|
+
# we know configis valid so we are fairly comfortable to first stop old pipeline and then start new one
|
322
|
+
upgrade_pipeline(id, old_pipeline.settings, new_config)
|
323
|
+
end
|
324
|
+
|
325
|
+
# upgrade_pipeline first stops the old pipeline and starts the new one
|
326
|
+
# this method exists only for specs to be able to expects this to be executed
|
327
|
+
# @params pipeline_id [String] the pipeline id to upgrade
|
328
|
+
# @params settings [Settings] the settings for the new pipeline
|
329
|
+
# @params new_config [String] the new pipeline config
|
330
|
+
def upgrade_pipeline(pipeline_id, settings, new_config)
|
331
|
+
@logger.warn("fetched new config for pipeline. upgrading..", :pipeline => pipeline_id, :config => new_config)
|
332
|
+
|
333
|
+
# first step: stop the old pipeline.
|
334
|
+
# IMPORTANT: a new pipeline with same settings should not be instantiated before the previous one is shutdown
|
335
|
+
|
336
|
+
stop_pipeline(pipeline_id)
|
337
|
+
reset_pipeline_metrics(pipeline_id)
|
338
|
+
|
339
|
+
# second step create and start a new pipeline now that the old one is shutdown
|
279
340
|
|
280
|
-
|
341
|
+
new_pipeline = create_pipeline(settings, new_config)
|
342
|
+
if new_pipeline.nil?
|
343
|
+
# this is a scenario where the configuration is valid (compilable) but the new pipeline refused to start
|
344
|
+
# and at this point NO pipeline is running
|
345
|
+
@logger.error("failed to create the reloaded pipeline and no pipeline is currently running", :pipeline => pipeline_id)
|
346
|
+
increment_reload_failures_metrics(pipeline_id, "failed to create the reloaded pipeline")
|
347
|
+
return
|
348
|
+
end
|
281
349
|
|
350
|
+
### at this point pipeline#close must be called if upgrade_pipeline does not succeed
|
351
|
+
|
352
|
+
# check if the new pipeline will be reloadable in which case we want to log that as an error and abort. this should normally not
|
353
|
+
# happen since the check should be done in reload_pipeline! prior to get here.
|
282
354
|
if new_pipeline.non_reloadable_plugins.any?
|
283
|
-
@logger.error(I18n.t("logstash.agent.non_reloadable_config_reload"),
|
284
|
-
|
285
|
-
|
355
|
+
@logger.error(I18n.t("logstash.agent.non_reloadable_config_reload"), :pipeline_id => pipeline_id, :plugins => new_pipeline.non_reloadable_plugins.map(&:class))
|
356
|
+
increment_reload_failures_metrics(pipeline_id, "non reloadable pipeline")
|
357
|
+
new_pipeline.close
|
286
358
|
return
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
359
|
+
end
|
360
|
+
|
361
|
+
# @pipelines[pipeline_id] must be initialized before #start_pipeline below which uses it
|
362
|
+
@pipelines[pipeline_id] = new_pipeline
|
363
|
+
|
364
|
+
if !start_pipeline(pipeline_id)
|
365
|
+
@logger.error("failed to start the reloaded pipeline and no pipeline is currently running", :pipeline => pipeline_id)
|
366
|
+
# do not call increment_reload_failures_metrics here since #start_pipeline already does it on failure
|
367
|
+
new_pipeline.close
|
368
|
+
return
|
369
|
+
end
|
370
|
+
|
371
|
+
# pipeline started successfuly, update reload success metrics
|
372
|
+
@instance_reload_metric.increment(:successes)
|
373
|
+
@pipeline_reload_metric.namespace([pipeline_id.to_sym, :reloads]).tap do |n|
|
374
|
+
n.increment(:successes)
|
375
|
+
n.gauge(:last_success_timestamp, LogStash::Timestamp.now)
|
291
376
|
end
|
292
377
|
end
|
293
378
|
|
@@ -349,20 +434,6 @@ class LogStash::Agent
|
|
349
434
|
thread.is_a?(Thread) && thread.alive?
|
350
435
|
end
|
351
436
|
|
352
|
-
def upgrade_pipeline(pipeline_id, new_pipeline)
|
353
|
-
stop_pipeline(pipeline_id)
|
354
|
-
reset_pipeline_metrics(pipeline_id)
|
355
|
-
@pipelines[pipeline_id] = new_pipeline
|
356
|
-
if start_pipeline(pipeline_id) # pipeline started successfuly
|
357
|
-
@instance_reload_metric.increment(:successes)
|
358
|
-
@pipeline_reload_metric.namespace([pipeline_id.to_sym, :reloads]).tap do |n|
|
359
|
-
n.increment(:successes)
|
360
|
-
n.gauge(:last_success_timestamp, LogStash::Timestamp.now)
|
361
|
-
end
|
362
|
-
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
437
|
def clean_state?
|
367
438
|
@pipelines.empty?
|
368
439
|
end
|
@@ -44,7 +44,7 @@ module LogStash module Instrument module PeriodicPoller
|
|
44
44
|
|
45
45
|
def collect
|
46
46
|
raw = JRMonitor.memory.generate
|
47
|
-
collect_jvm_metrics(raw)
|
47
|
+
collect_jvm_metrics(raw)
|
48
48
|
collect_pools_metrics(raw)
|
49
49
|
collect_threads_metrics
|
50
50
|
collect_process_metrics
|
@@ -69,15 +69,10 @@ module LogStash module Instrument module PeriodicPoller
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def collect_threads_metrics
|
72
|
-
|
72
|
+
threads_mx = ManagementFactory.getThreadMXBean()
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
@peak_threads = current
|
77
|
-
end
|
78
|
-
|
79
|
-
metric.gauge([:jvm, :threads], :count, threads.count)
|
80
|
-
metric.gauge([:jvm, :threads], :peak_count, @peak_threads)
|
74
|
+
metric.gauge([:jvm, :threads], :count, threads_mx.getThreadCount())
|
75
|
+
metric.gauge([:jvm, :threads], :peak_count, threads_mx.getPeakThreadCount())
|
81
76
|
end
|
82
77
|
|
83
78
|
def collect_process_metrics
|
data/lib/logstash/pipeline.rb
CHANGED
@@ -22,43 +22,24 @@ require "logstash/instrument/collector"
|
|
22
22
|
require "logstash/output_delegator"
|
23
23
|
require "logstash/filter_delegator"
|
24
24
|
|
25
|
-
module LogStash; class
|
25
|
+
module LogStash; class BasePipeline
|
26
26
|
include LogStash::Util::Loggable
|
27
27
|
|
28
|
-
attr_reader :inputs,
|
29
|
-
:filters,
|
30
|
-
:outputs,
|
31
|
-
:worker_threads,
|
32
|
-
:events_consumed,
|
33
|
-
:events_filtered,
|
34
|
-
:reporter,
|
35
|
-
:pipeline_id,
|
36
|
-
:started_at,
|
37
|
-
:thread,
|
38
|
-
:config_str,
|
39
|
-
:config_hash,
|
40
|
-
:settings,
|
41
|
-
:metric,
|
42
|
-
:filter_queue_client,
|
43
|
-
:input_queue_client,
|
44
|
-
:queue
|
45
|
-
|
46
|
-
MAX_INFLIGHT_WARN_THRESHOLD = 10_000
|
28
|
+
attr_reader :config_str, :config_hash, :inputs, :filters, :outputs, :pipeline_id
|
47
29
|
|
48
30
|
RELOAD_INCOMPATIBLE_PLUGINS = [
|
49
|
-
|
31
|
+
"LogStash::Inputs::Stdin"
|
50
32
|
]
|
51
33
|
|
52
|
-
def initialize(config_str, settings = SETTINGS
|
34
|
+
def initialize(config_str, settings = SETTINGS)
|
53
35
|
@logger = self.logger
|
54
36
|
@config_str = config_str
|
55
37
|
@config_hash = Digest::SHA1.hexdigest(@config_str)
|
56
38
|
# Every time #plugin is invoked this is incremented to give each plugin
|
57
39
|
# a unique id when auto-generating plugin ids
|
58
40
|
@plugin_counter ||= 0
|
59
|
-
|
60
|
-
@pipeline_id =
|
61
|
-
@reporter = PipelineReporter.new(@logger, self)
|
41
|
+
|
42
|
+
@pipeline_id = settings.get_value("pipeline.id") || self.object_id
|
62
43
|
|
63
44
|
# A list of plugins indexed by id
|
64
45
|
@plugins_by_id = {}
|
@@ -66,8 +47,88 @@ module LogStash; class Pipeline
|
|
66
47
|
@filters = nil
|
67
48
|
@outputs = nil
|
68
49
|
|
69
|
-
|
50
|
+
grammar = LogStashConfigParser.new
|
51
|
+
parsed_config = grammar.parse(config_str)
|
52
|
+
raise(ConfigurationError, grammar.failure_reason) if parsed_config.nil?
|
53
|
+
|
54
|
+
config_code = parsed_config.compile
|
55
|
+
|
56
|
+
# config_code = BasePipeline.compileConfig(config_str)
|
57
|
+
|
58
|
+
if settings.get_value("config.debug") && @logger.debug?
|
59
|
+
@logger.debug("Compiled pipeline code", :code => config_code)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Evaluate the config compiled code that will initialize all the plugins and define the
|
63
|
+
# filter and output methods.
|
64
|
+
begin
|
65
|
+
eval(config_code)
|
66
|
+
rescue => e
|
67
|
+
raise e
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def plugin(plugin_type, name, *args)
|
72
|
+
@plugin_counter += 1
|
73
|
+
|
74
|
+
# Collapse the array of arguments into a single merged hash
|
75
|
+
args = args.reduce({}, &:merge)
|
76
|
+
|
77
|
+
id = if args["id"].nil? || args["id"].empty?
|
78
|
+
args["id"] = "#{@config_hash}-#{@plugin_counter}"
|
79
|
+
else
|
80
|
+
args["id"]
|
81
|
+
end
|
82
|
+
|
83
|
+
raise ConfigurationError, "Two plugins have the id '#{id}', please fix this conflict" if @plugins_by_id[id]
|
84
|
+
|
85
|
+
@plugins_by_id[id] = true
|
86
|
+
|
87
|
+
# use NullMetric if called in the BasePipeline context otherwise use the @metric value
|
88
|
+
metric = @metric || Instrument::NullMetric.new
|
89
|
+
|
90
|
+
pipeline_scoped_metric = metric.namespace([:stats, :pipelines, pipeline_id.to_s.to_sym, :plugins])
|
91
|
+
|
92
|
+
# Scope plugins of type 'input' to 'inputs'
|
93
|
+
type_scoped_metric = pipeline_scoped_metric.namespace("#{plugin_type}s".to_sym)
|
94
|
+
|
95
|
+
klass = Plugin.lookup(plugin_type, name)
|
96
|
+
|
97
|
+
if plugin_type == "output"
|
98
|
+
OutputDelegator.new(@logger, klass, type_scoped_metric, OutputDelegatorStrategyRegistry.instance, args)
|
99
|
+
elsif plugin_type == "filter"
|
100
|
+
FilterDelegator.new(@logger, klass, type_scoped_metric, args)
|
101
|
+
else # input
|
102
|
+
input_plugin = klass.new(args)
|
103
|
+
input_plugin.metric = type_scoped_metric.namespace(id)
|
104
|
+
input_plugin
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def non_reloadable_plugins
|
109
|
+
(inputs + filters + outputs).select do |plugin|
|
110
|
+
RELOAD_INCOMPATIBLE_PLUGINS.include?(plugin.class.name)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end; end
|
114
|
+
|
115
|
+
module LogStash; class Pipeline < BasePipeline
|
116
|
+
attr_reader \
|
117
|
+
:worker_threads,
|
118
|
+
:events_consumed,
|
119
|
+
:events_filtered,
|
120
|
+
:reporter,
|
121
|
+
:started_at,
|
122
|
+
:thread,
|
123
|
+
:settings,
|
124
|
+
:metric,
|
125
|
+
:filter_queue_client,
|
126
|
+
:input_queue_client,
|
127
|
+
:queue
|
128
|
+
|
129
|
+
MAX_INFLIGHT_WARN_THRESHOLD = 10_000
|
70
130
|
|
131
|
+
def initialize(config_str, settings = SETTINGS, namespaced_metric = nil)
|
71
132
|
# This needs to be configured before we evaluate the code to make
|
72
133
|
# sure the metric instance is correctly send to the plugins to make the namespace scoping work
|
73
134
|
@metric = if namespaced_metric
|
@@ -76,29 +137,12 @@ module LogStash; class Pipeline
|
|
76
137
|
Instrument::NullMetric.new
|
77
138
|
end
|
78
139
|
|
79
|
-
|
80
|
-
@
|
81
|
-
|
82
|
-
raise ConfigurationError, grammar.failure_reason
|
83
|
-
end
|
84
|
-
# This will compile the config to ruby and evaluate the resulting code.
|
85
|
-
# The code will initialize all the plugins and define the
|
86
|
-
# filter and output methods.
|
87
|
-
code = @config.compile
|
88
|
-
@code = code
|
140
|
+
@settings = settings
|
141
|
+
@reporter = PipelineReporter.new(@logger, self)
|
142
|
+
@worker_threads = []
|
89
143
|
|
90
|
-
|
91
|
-
# So just print it.
|
144
|
+
super(config_str, settings)
|
92
145
|
|
93
|
-
if @settings.get_value("config.debug") && @logger.debug?
|
94
|
-
@logger.debug("Compiled pipeline code", :code => code)
|
95
|
-
end
|
96
|
-
|
97
|
-
begin
|
98
|
-
eval(code)
|
99
|
-
rescue => e
|
100
|
-
raise
|
101
|
-
end
|
102
146
|
@queue = build_queue_from_settings
|
103
147
|
@input_queue_client = @queue.write_client
|
104
148
|
@filter_queue_client = @queue.read_client
|
@@ -202,8 +246,7 @@ module LogStash; class Pipeline
|
|
202
246
|
shutdown_flusher
|
203
247
|
shutdown_workers
|
204
248
|
|
205
|
-
|
206
|
-
@queue.close
|
249
|
+
close
|
207
250
|
|
208
251
|
@logger.debug("Pipeline #{@pipeline_id} has been shutdown")
|
209
252
|
|
@@ -211,6 +254,11 @@ module LogStash; class Pipeline
|
|
211
254
|
return 0
|
212
255
|
end # def run
|
213
256
|
|
257
|
+
def close
|
258
|
+
@filter_queue_client.close
|
259
|
+
@queue.close
|
260
|
+
end
|
261
|
+
|
214
262
|
def transition_to_running
|
215
263
|
@running.make_true
|
216
264
|
end
|
@@ -227,12 +275,32 @@ module LogStash; class Pipeline
|
|
227
275
|
@running.false?
|
228
276
|
end
|
229
277
|
|
278
|
+
# register_plugin simply calls the plugin #register method and catches & logs any error
|
279
|
+
# @param plugin [Plugin] the plugin to register
|
280
|
+
# @return [Plugin] the registered plugin
|
281
|
+
def register_plugin(plugin)
|
282
|
+
plugin.register
|
283
|
+
plugin
|
284
|
+
rescue => e
|
285
|
+
@logger.error("Error registering plugin", :plugin => plugin.inspect, :error => e.message)
|
286
|
+
raise e
|
287
|
+
end
|
288
|
+
|
289
|
+
# register_plugins calls #register_plugin on the plugins list and upon exception will call Plugin#do_close on all registered plugins
|
290
|
+
# @param plugins [Array[Plugin]] the list of plugins to register
|
291
|
+
def register_plugins(plugins)
|
292
|
+
registered = []
|
293
|
+
plugins.each { |plugin| registered << register_plugin(plugin) }
|
294
|
+
rescue => e
|
295
|
+
registered.each(&:do_close)
|
296
|
+
raise e
|
297
|
+
end
|
298
|
+
|
230
299
|
def start_workers
|
231
300
|
@worker_threads.clear # In case we're restarting the pipeline
|
232
301
|
begin
|
233
|
-
|
234
|
-
@
|
235
|
-
@filters.each {|f| f.register }
|
302
|
+
register_plugins(@outputs)
|
303
|
+
register_plugins(@filters)
|
236
304
|
|
237
305
|
pipeline_workers = safe_pipeline_worker_count
|
238
306
|
batch_size = @settings.get("pipeline.batch.size")
|
@@ -263,6 +331,16 @@ module LogStash; class Pipeline
|
|
263
331
|
worker_loop(batch_size, batch_delay)
|
264
332
|
end
|
265
333
|
end
|
334
|
+
|
335
|
+
# inputs should be started last, after all workers
|
336
|
+
begin
|
337
|
+
start_inputs
|
338
|
+
rescue => e
|
339
|
+
# if there is any exception in starting inputs, make sure we shutdown workers.
|
340
|
+
# exception will already by logged in start_inputs
|
341
|
+
shutdown_workers
|
342
|
+
raise e
|
343
|
+
end
|
266
344
|
ensure
|
267
345
|
# it is important to guarantee @ready to be true after the startup sequence has been completed
|
268
346
|
# to potentially unblock the shutdown method which may be waiting on @ready to proceed
|
@@ -354,10 +432,11 @@ module LogStash; class Pipeline
|
|
354
432
|
end
|
355
433
|
@inputs += moreinputs
|
356
434
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
435
|
+
# first make sure we can register all input plugins
|
436
|
+
register_plugins(@inputs)
|
437
|
+
|
438
|
+
# then after all input plugins are sucessfully registered, start them
|
439
|
+
@inputs.each { |input| start_input(input) }
|
361
440
|
end
|
362
441
|
|
363
442
|
def start_input(plugin)
|
@@ -433,41 +512,6 @@ module LogStash; class Pipeline
|
|
433
512
|
@outputs.each(&:do_close)
|
434
513
|
end
|
435
514
|
|
436
|
-
def plugin(plugin_type, name, *args)
|
437
|
-
@plugin_counter += 1
|
438
|
-
|
439
|
-
# Collapse the array of arguments into a single merged hash
|
440
|
-
args = args.reduce({}, &:merge)
|
441
|
-
|
442
|
-
id = if args["id"].nil? || args["id"].empty?
|
443
|
-
args["id"] = "#{@config_hash}-#{@plugin_counter}"
|
444
|
-
else
|
445
|
-
args["id"]
|
446
|
-
end
|
447
|
-
|
448
|
-
raise ConfigurationError, "Two plugins have the id '#{id}', please fix this conflict" if @plugins_by_id[id]
|
449
|
-
|
450
|
-
pipeline_scoped_metric = metric.namespace([:stats, :pipelines, pipeline_id.to_s.to_sym, :plugins])
|
451
|
-
|
452
|
-
klass = Plugin.lookup(plugin_type, name)
|
453
|
-
|
454
|
-
# Scope plugins of type 'input' to 'inputs'
|
455
|
-
type_scoped_metric = pipeline_scoped_metric.namespace("#{plugin_type}s".to_sym)
|
456
|
-
plugin = if plugin_type == "output"
|
457
|
-
OutputDelegator.new(@logger, klass, type_scoped_metric,
|
458
|
-
OutputDelegatorStrategyRegistry.instance,
|
459
|
-
args)
|
460
|
-
elsif plugin_type == "filter"
|
461
|
-
FilterDelegator.new(@logger, klass, type_scoped_metric, args)
|
462
|
-
else # input
|
463
|
-
input_plugin = klass.new(args)
|
464
|
-
input_plugin.metric = type_scoped_metric.namespace(id)
|
465
|
-
input_plugin
|
466
|
-
end
|
467
|
-
|
468
|
-
@plugins_by_id[id] = plugin
|
469
|
-
end
|
470
|
-
|
471
515
|
# for backward compatibility in devutils for the rspec helpers, this method is not used
|
472
516
|
# in the pipeline anymore.
|
473
517
|
def filter(event, &block)
|
@@ -548,12 +592,6 @@ module LogStash; class Pipeline
|
|
548
592
|
.each {|t| t.delete("status") }
|
549
593
|
end
|
550
594
|
|
551
|
-
def non_reloadable_plugins
|
552
|
-
(inputs + filters + outputs).select do |plugin|
|
553
|
-
RELOAD_INCOMPATIBLE_PLUGINS.include?(plugin.class.name)
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
595
|
def collect_stats
|
558
596
|
pipeline_metric = @metric.namespace([:stats, :pipelines, pipeline_id.to_s.to_sym, :queue])
|
559
597
|
pipeline_metric.gauge(:type, settings.get("queue.type"))
|
@@ -590,5 +628,4 @@ module LogStash; class Pipeline
|
|
590
628
|
:flushing => @flushing
|
591
629
|
}
|
592
630
|
end
|
593
|
-
|
594
|
-
end end
|
631
|
+
end; end
|
data/lib/logstash/runner.rb
CHANGED
@@ -249,7 +249,7 @@ class LogStash::Runner < Clamp::StrictCommand
|
|
249
249
|
config_loader = LogStash::Config::Loader.new(logger)
|
250
250
|
config_str = config_loader.format_config(setting("path.config"), setting("config.string"))
|
251
251
|
begin
|
252
|
-
LogStash::
|
252
|
+
LogStash::BasePipeline.new(config_str)
|
253
253
|
puts "Configuration OK"
|
254
254
|
logger.info "Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash"
|
255
255
|
return 0
|
data/lib/logstash/version.rb
CHANGED
data/spec/logstash/agent_spec.rb
CHANGED
@@ -52,6 +52,10 @@ describe LogStash::Agent do
|
|
52
52
|
}
|
53
53
|
end
|
54
54
|
|
55
|
+
after(:each) do
|
56
|
+
subject.close_pipelines
|
57
|
+
end
|
58
|
+
|
55
59
|
it "should delegate settings to new pipeline" do
|
56
60
|
expect(LogStash::Pipeline).to receive(:new) do |arg1, arg2|
|
57
61
|
expect(arg1).to eq(config_string)
|
@@ -262,10 +266,14 @@ describe LogStash::Agent do
|
|
262
266
|
subject.register_pipeline(pipeline_id, pipeline_settings)
|
263
267
|
end
|
264
268
|
|
269
|
+
after(:each) do
|
270
|
+
subject.close_pipelines
|
271
|
+
end
|
272
|
+
|
265
273
|
context "when fetching a new state" do
|
266
274
|
it "upgrades the state" do
|
267
275
|
expect(subject).to receive(:fetch_config).and_return(second_pipeline_config)
|
268
|
-
expect(subject).to receive(:upgrade_pipeline).with(pipeline_id, kind_of(LogStash::
|
276
|
+
expect(subject).to receive(:upgrade_pipeline).with(pipeline_id, kind_of(LogStash::Settings), second_pipeline_config)
|
269
277
|
subject.reload_state!
|
270
278
|
end
|
271
279
|
end
|
@@ -295,6 +303,7 @@ describe LogStash::Agent do
|
|
295
303
|
|
296
304
|
after :each do
|
297
305
|
ENV["FOO"] = @foo_content
|
306
|
+
subject.close_pipelines
|
298
307
|
end
|
299
308
|
|
300
309
|
it "doesn't upgrade the state" do
|
@@ -319,14 +328,16 @@ describe LogStash::Agent do
|
|
319
328
|
end
|
320
329
|
|
321
330
|
after(:each) do
|
322
|
-
subject.
|
331
|
+
subject.close_pipelines
|
323
332
|
end
|
324
333
|
|
325
334
|
context "when the upgrade fails" do
|
326
335
|
before :each do
|
327
336
|
allow(subject).to receive(:fetch_config).and_return(new_pipeline_config)
|
328
337
|
allow(subject).to receive(:create_pipeline).and_return(nil)
|
329
|
-
allow(subject).to receive(:stop_pipeline)
|
338
|
+
allow(subject).to receive(:stop_pipeline) do |id|
|
339
|
+
subject.close_pipeline(id)
|
340
|
+
end
|
330
341
|
end
|
331
342
|
|
332
343
|
it "leaves the state untouched" do
|
@@ -346,16 +357,20 @@ describe LogStash::Agent do
|
|
346
357
|
let(:new_config) { "input { generator { count => 1 } } output { }" }
|
347
358
|
before :each do
|
348
359
|
allow(subject).to receive(:fetch_config).and_return(new_config)
|
349
|
-
allow(subject).to receive(:stop_pipeline)
|
350
360
|
allow(subject).to receive(:start_pipeline)
|
361
|
+
allow(subject).to receive(:stop_pipeline) do |id|
|
362
|
+
subject.close_pipeline(id)
|
363
|
+
end
|
351
364
|
end
|
352
365
|
it "updates the state" do
|
353
366
|
subject.send(:"reload_pipeline!", pipeline_id)
|
354
367
|
expect(subject.pipelines[pipeline_id].config_str).to eq(new_config)
|
355
368
|
end
|
356
369
|
it "starts the pipeline" do
|
357
|
-
expect(subject).to receive(:stop_pipeline)
|
358
370
|
expect(subject).to receive(:start_pipeline)
|
371
|
+
expect(subject).to receive(:stop_pipeline) do |id|
|
372
|
+
subject.close_pipeline(id)
|
373
|
+
end
|
359
374
|
subject.send(:"reload_pipeline!", pipeline_id)
|
360
375
|
end
|
361
376
|
end
|
@@ -416,6 +431,12 @@ describe LogStash::Agent do
|
|
416
431
|
let!(:dummy_output) { LogStash::Outputs::DroppingDummyOutput.new }
|
417
432
|
let!(:dummy_output2) { DummyOutput2.new }
|
418
433
|
let(:initial_generator_threshold) { 1000 }
|
434
|
+
let(:pipeline_thread) do
|
435
|
+
Thread.new do
|
436
|
+
subject.register_pipeline("main", pipeline_settings)
|
437
|
+
subject.execute
|
438
|
+
end
|
439
|
+
end
|
419
440
|
|
420
441
|
before :each do
|
421
442
|
allow(LogStash::Outputs::DroppingDummyOutput).to receive(:new).at_least(:once).with(anything).and_return(dummy_output)
|
@@ -429,10 +450,11 @@ describe LogStash::Agent do
|
|
429
450
|
@abort_on_exception = Thread.abort_on_exception
|
430
451
|
Thread.abort_on_exception = true
|
431
452
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
453
|
+
pipeline_thread
|
454
|
+
# @t = Thread.new do
|
455
|
+
# subject.register_pipeline("main", pipeline_settings)
|
456
|
+
# subject.execute
|
457
|
+
# end
|
436
458
|
|
437
459
|
# wait for some events to reach the dummy_output
|
438
460
|
sleep(0.01) until dummy_output.events_received > initial_generator_threshold
|
@@ -441,8 +463,8 @@ describe LogStash::Agent do
|
|
441
463
|
after :each do
|
442
464
|
begin
|
443
465
|
subject.shutdown
|
444
|
-
Stud.stop!(
|
445
|
-
|
466
|
+
Stud.stop!(pipeline_thread)
|
467
|
+
pipeline_thread.join
|
446
468
|
ensure
|
447
469
|
Thread.abort_on_exception = @abort_on_exception
|
448
470
|
end
|
@@ -451,8 +473,8 @@ describe LogStash::Agent do
|
|
451
473
|
context "when reloading a good config" do
|
452
474
|
let(:new_config_generator_counter) { 500 }
|
453
475
|
let(:new_config) { "input { generator { count => #{new_config_generator_counter} } } output { dummyoutput2 {} }" }
|
454
|
-
before :each do
|
455
476
|
|
477
|
+
before :each do
|
456
478
|
File.open(config_path, "w") do |f|
|
457
479
|
f.write(new_config)
|
458
480
|
f.fsync
|
@@ -138,7 +138,7 @@ describe LogStash::Pipeline do
|
|
138
138
|
Thread.abort_on_exception = true
|
139
139
|
|
140
140
|
pipeline = LogStash::Pipeline.new(config, pipeline_settings_obj)
|
141
|
-
Thread.new { pipeline.run }
|
141
|
+
t = Thread.new { pipeline.run }
|
142
142
|
sleep 0.1 while !pipeline.ready?
|
143
143
|
wait(3).for do
|
144
144
|
# give us a bit of time to flush the events
|
@@ -149,6 +149,7 @@ describe LogStash::Pipeline do
|
|
149
149
|
expect(output.events[0].get("tags")).to eq(["notdropped"])
|
150
150
|
expect(output.events[1].get("tags")).to eq(["notdropped"])
|
151
151
|
pipeline.shutdown
|
152
|
+
t.join
|
152
153
|
|
153
154
|
Thread.abort_on_exception = abort_on_exception_state
|
154
155
|
end
|
@@ -192,12 +193,14 @@ describe LogStash::Pipeline do
|
|
192
193
|
pipeline_settings_obj.set("config.debug", false)
|
193
194
|
expect(logger).not_to receive(:debug).with(/Compiled pipeline/, anything)
|
194
195
|
pipeline = TestPipeline.new(test_config_with_filters)
|
196
|
+
pipeline.close
|
195
197
|
end
|
196
198
|
|
197
199
|
it "should print the compiled code if config.debug is set to true" do
|
198
200
|
pipeline_settings_obj.set("config.debug", true)
|
199
201
|
expect(logger).to receive(:debug).with(/Compiled pipeline/, anything)
|
200
202
|
pipeline = TestPipeline.new(test_config_with_filters, pipeline_settings_obj)
|
203
|
+
pipeline.close
|
201
204
|
end
|
202
205
|
end
|
203
206
|
|
@@ -385,9 +388,12 @@ describe LogStash::Pipeline do
|
|
385
388
|
allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
|
386
389
|
allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput)
|
387
390
|
allow(logger).to receive(:warn)
|
388
|
-
thread
|
391
|
+
# pipeline must be first called outside the thread context because it lazyly initialize
|
392
|
+
p = pipeline
|
393
|
+
t = Thread.new { p.run }
|
394
|
+
sleep(0.1) until pipeline.ready?
|
389
395
|
pipeline.shutdown
|
390
|
-
|
396
|
+
t.join
|
391
397
|
end
|
392
398
|
|
393
399
|
it "should not raise a max inflight warning if the max_inflight count isn't exceeded" do
|
@@ -440,6 +446,10 @@ describe LogStash::Pipeline do
|
|
440
446
|
let(:settings) { LogStash::SETTINGS.clone }
|
441
447
|
subject { LogStash::Pipeline.new(config, settings, metric) }
|
442
448
|
|
449
|
+
after :each do
|
450
|
+
subject.close
|
451
|
+
end
|
452
|
+
|
443
453
|
context "when metric.collect is disabled" do
|
444
454
|
before :each do
|
445
455
|
settings.set("metric.collect", false)
|
@@ -528,9 +538,21 @@ describe LogStash::Pipeline do
|
|
528
538
|
allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutputmore").and_return(DummyOutputMore)
|
529
539
|
end
|
530
540
|
|
541
|
+
# multiple pipelines cannot be instantiated using the same PQ settings, force memory queue
|
542
|
+
before :each do
|
543
|
+
pipeline_workers_setting = LogStash::SETTINGS.get_setting("queue.type")
|
544
|
+
allow(pipeline_workers_setting).to receive(:value).and_return("memory")
|
545
|
+
pipeline_settings.each {|k, v| pipeline_settings_obj.set(k, v) }
|
546
|
+
end
|
547
|
+
|
531
548
|
let(:pipeline1) { LogStash::Pipeline.new("input { dummyinputgenerator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
|
532
549
|
let(:pipeline2) { LogStash::Pipeline.new("input { dummyinputgenerator {} } filter { dummyfilter {} } output { dummyoutputmore {}}") }
|
533
550
|
|
551
|
+
after do
|
552
|
+
pipeline1.close
|
553
|
+
pipeline2.close
|
554
|
+
end
|
555
|
+
|
534
556
|
it "should handle evaluating different config" do
|
535
557
|
expect(pipeline1.output_func(LogStash::Event.new)).not_to include(nil)
|
536
558
|
expect(pipeline1.filter_func(LogStash::Event.new)).not_to include(nil)
|
@@ -573,7 +595,7 @@ describe LogStash::Pipeline do
|
|
573
595
|
it "flushes the buffered contents of the filter" do
|
574
596
|
Thread.abort_on_exception = true
|
575
597
|
pipeline = LogStash::Pipeline.new(config, pipeline_settings_obj)
|
576
|
-
Thread.new { pipeline.run }
|
598
|
+
t = Thread.new { pipeline.run }
|
577
599
|
sleep 0.1 while !pipeline.ready?
|
578
600
|
wait(3).for do
|
579
601
|
# give us a bit of time to flush the events
|
@@ -582,6 +604,7 @@ describe LogStash::Pipeline do
|
|
582
604
|
event = output.events.pop
|
583
605
|
expect(event.get("message").count("\n")).to eq(99)
|
584
606
|
pipeline.shutdown
|
607
|
+
t.join
|
585
608
|
end
|
586
609
|
end
|
587
610
|
|
@@ -596,6 +619,13 @@ describe LogStash::Pipeline do
|
|
596
619
|
let(:pipeline1) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
|
597
620
|
let(:pipeline2) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
|
598
621
|
|
622
|
+
# multiple pipelines cannot be instantiated using the same PQ settings, force memory queue
|
623
|
+
before :each do
|
624
|
+
pipeline_workers_setting = LogStash::SETTINGS.get_setting("queue.type")
|
625
|
+
allow(pipeline_workers_setting).to receive(:value).and_return("memory")
|
626
|
+
pipeline_settings.each {|k, v| pipeline_settings_obj.set(k, v) }
|
627
|
+
end
|
628
|
+
|
599
629
|
it "should handle evaluating different config" do
|
600
630
|
# When the functions are compiled from the AST it will generate instance
|
601
631
|
# variables that are unique to the actual config, the intances are pointing
|
@@ -626,8 +656,14 @@ describe LogStash::Pipeline do
|
|
626
656
|
|
627
657
|
subject { described_class.new(config) }
|
628
658
|
|
629
|
-
|
630
|
-
|
659
|
+
context "when the pipeline is not started" do
|
660
|
+
after :each do
|
661
|
+
subject.close
|
662
|
+
end
|
663
|
+
|
664
|
+
it "returns nil when the pipeline isnt started" do
|
665
|
+
expect(subject.started_at).to be_nil
|
666
|
+
end
|
631
667
|
end
|
632
668
|
|
633
669
|
it "return when the pipeline started working" do
|
@@ -648,6 +684,10 @@ describe LogStash::Pipeline do
|
|
648
684
|
subject { described_class.new(config) }
|
649
685
|
|
650
686
|
context "when the pipeline is not started" do
|
687
|
+
after :each do
|
688
|
+
subject.close
|
689
|
+
end
|
690
|
+
|
651
691
|
it "returns 0" do
|
652
692
|
expect(subject.uptime).to eq(0)
|
653
693
|
end
|
@@ -655,10 +695,14 @@ describe LogStash::Pipeline do
|
|
655
695
|
|
656
696
|
context "when the pipeline is started" do
|
657
697
|
it "return the duration in milliseconds" do
|
658
|
-
|
698
|
+
# subject must be first call outside the thread context because of lazy initialization
|
699
|
+
s = subject
|
700
|
+
t = Thread.new { s.run }
|
701
|
+
sleep(0.1) until subject.ready?
|
659
702
|
sleep(0.1)
|
660
703
|
expect(subject.uptime).to be > 0
|
661
704
|
subject.shutdown
|
705
|
+
t.join
|
662
706
|
end
|
663
707
|
end
|
664
708
|
end
|
@@ -704,6 +748,12 @@ describe LogStash::Pipeline do
|
|
704
748
|
end
|
705
749
|
let(:dummyoutput) { ::LogStash::Outputs::DummyOutput.new({ "id" => dummy_output_id }) }
|
706
750
|
let(:metric_store) { subject.metric.collector.snapshot_metric.metric_store }
|
751
|
+
let(:pipeline_thread) do
|
752
|
+
# subject has to be called for the first time outside the thread because it will create a race condition
|
753
|
+
# with the subject.ready? call since subject is lazily initialized
|
754
|
+
s = subject
|
755
|
+
Thread.new { s.run }
|
756
|
+
end
|
707
757
|
|
708
758
|
before :each do
|
709
759
|
allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(dummyoutput)
|
@@ -712,7 +762,9 @@ describe LogStash::Pipeline do
|
|
712
762
|
allow(LogStash::Plugin).to receive(:lookup).with("filter", "multiline").and_return(LogStash::Filters::Multiline)
|
713
763
|
allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput)
|
714
764
|
|
715
|
-
|
765
|
+
pipeline_thread
|
766
|
+
sleep(0.1) until subject.ready?
|
767
|
+
|
716
768
|
# make sure we have received all the generated events
|
717
769
|
wait(3).for do
|
718
770
|
# give us a bit of time to flush the events
|
@@ -722,6 +774,7 @@ describe LogStash::Pipeline do
|
|
722
774
|
|
723
775
|
after :each do
|
724
776
|
subject.shutdown
|
777
|
+
pipeline_thread.join
|
725
778
|
end
|
726
779
|
|
727
780
|
context "global metric" do
|
@@ -787,6 +840,13 @@ describe LogStash::Pipeline do
|
|
787
840
|
let(:pipeline1) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
|
788
841
|
let(:pipeline2) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
|
789
842
|
|
843
|
+
# multiple pipelines cannot be instantiated using the same PQ settings, force memory queue
|
844
|
+
before :each do
|
845
|
+
pipeline_workers_setting = LogStash::SETTINGS.get_setting("queue.type")
|
846
|
+
allow(pipeline_workers_setting).to receive(:value).and_return("memory")
|
847
|
+
pipeline_settings.each {|k, v| pipeline_settings_obj.set(k, v) }
|
848
|
+
end
|
849
|
+
|
790
850
|
it "should not add ivars" do
|
791
851
|
expect(pipeline1.instance_variables).to eq(pipeline2.instance_variables)
|
792
852
|
end
|
metadata
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.2.
|
4
|
+
version: 5.2.2
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 5.2.
|
18
|
+
version: 5.2.2
|
19
19
|
name: logstash-core-event-java
|
20
20
|
prerelease: false
|
21
21
|
type: :runtime
|
@@ -23,13 +23,13 @@ dependencies:
|
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.2.
|
26
|
+
version: 5.2.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - '='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.2.
|
32
|
+
version: 5.2.2
|
33
33
|
name: logstash-core-queue-jruby
|
34
34
|
prerelease: false
|
35
35
|
type: :runtime
|
@@ -37,7 +37,7 @@ dependencies:
|
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 5.2.
|
40
|
+
version: 5.2.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|