logstash-core 5.2.1-java → 5.2.2-java
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|