logstash-core 2.2.4.snapshot2-java → 2.3.0-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52aed4fccb5c307e3a36a7303b85100121709b49
4
- data.tar.gz: db411f7c6536b2838a4acde76fca939c27be2487
3
+ metadata.gz: 62ad94033e414179752f4aa8997e1453d707292c
4
+ data.tar.gz: 4d3dbe8a9096eed9fc2cf873b4115eb00d26adc3
5
5
  SHA512:
6
- metadata.gz: 8bee266423a94552eafd7e277b764c1eed1e8ab237f7f3506fc919f5c885c467025cc515b7529f4546b8152dadeecaa64341a36a0484057b9d9c594c9b183e4d
7
- data.tar.gz: f6dbf6b9511bd8c55632c61c617ca5b12fa9036caf1594f039bc361ae2c626189a78a7f973401df91c94387b915b8cbeef74a2c0167d104435003ea5f42b71fc
6
+ metadata.gz: 27671a2f16ee352e488edad4842c8ef8f563f7ccd1fbff9363aaac89c255960865536eacb3d825c74a60e820e9412406467e6270e3eae8444370fca983ab9f6a
7
+ data.tar.gz: 560cdb36d4971df6eb6a3f1b1359ac0599ce89887f68834762fb6ecd5e49e2f5e8e197236af2f1e1cb5b94c279aab1bf477c369572b5f90970e0570d7048c003
@@ -5,4 +5,4 @@
5
5
  # Note to authors: this should not include dashes because 'gem' barfs if
6
6
  # you include a dash in the version string.
7
7
 
8
- LOGSTASH_CORE_VERSION = "2.2.4.snapshot2"
8
+ LOGSTASH_CORE_VERSION = "2.3.0"
@@ -3,13 +3,16 @@ require "clamp" # gem 'clamp'
3
3
  require "logstash/environment"
4
4
  require "logstash/errors"
5
5
  require "logstash/config/cpu_core_strategy"
6
+ require "stud/trap"
7
+ require "logstash/config/loader"
6
8
  require "uri"
7
9
  require "net/http"
8
10
  require "logstash/pipeline"
9
- LogStash::Environment.load_locale!
10
11
 
11
12
  class LogStash::Agent < Clamp::Command
12
13
 
14
+ attr_reader :pipelines
15
+
13
16
  DEFAULT_INPUT = "input { stdin { type => stdin } }"
14
17
  DEFAULT_OUTPUT = "output { stdout { codec => rubydebug } }"
15
18
 
@@ -27,6 +30,7 @@ class LogStash::Agent < Clamp::Command
27
30
  :attribute_name => :pipeline_workers,
28
31
  :default => LogStash::Pipeline::DEFAULT_SETTINGS[:default_pipeline_workers]
29
32
 
33
+
30
34
  option ["-b", "--pipeline-batch-size"], "SIZE",
31
35
  I18n.t("logstash.agent.flag.pipeline-batch-size"),
32
36
  :attribute_name => :pipeline_batch_size,
@@ -54,10 +58,6 @@ class LogStash::Agent < Clamp::Command
54
58
  option "--verbose", :flag, I18n.t("logstash.agent.flag.verbose")
55
59
  option "--debug", :flag, I18n.t("logstash.agent.flag.debug")
56
60
 
57
- option "--debug-config", :flag,
58
- I18n.t("logstash.runner.flag.debug_config"),
59
- :attribute_name => :debug_config, :default => false
60
-
61
61
  option ["-V", "--version"], :flag,
62
62
  I18n.t("logstash.agent.flag.version")
63
63
 
@@ -75,9 +75,21 @@ class LogStash::Agent < Clamp::Command
75
75
  :attribute_name => :unsafe_shutdown,
76
76
  :default => false
77
77
 
78
- def initialize(*args)
79
- super(*args)
80
- @pipeline_settings ||= { :pipeline_id => "base" }
78
+ option ["-r", "--[no-]auto-reload"], :flag,
79
+ I18n.t("logstash.agent.flag.auto_reload"),
80
+ :attribute_name => :auto_reload, :default => false
81
+
82
+ option ["--reload-interval"], "RELOAD_INTERVAL",
83
+ I18n.t("logstash.agent.flag.reload_interval"),
84
+ :attribute_name => :reload_interval, :default => 3, &:to_i
85
+
86
+ def initialize(*params)
87
+ super(*params)
88
+ @logger = Cabin::Channel.get(LogStash)
89
+ @pipelines = {}
90
+ @pipeline_settings ||= { :pipeline_id => "main" }
91
+ @upgrade_mutex = Mutex.new
92
+ @config_loader = LogStash::Config::Loader.new(@logger)
81
93
  end
82
94
 
83
95
  def pipeline_workers=(pipeline_workers_value)
@@ -107,7 +119,6 @@ class LogStash::Agent < Clamp::Command
107
119
  raise LogStash::ConfigurationError, message
108
120
  end # def warn
109
121
 
110
- # Emit a failure message and abort.
111
122
  def fail(message)
112
123
  raise LogStash::ConfigurationError, message
113
124
  end # def fail
@@ -118,7 +129,6 @@ class LogStash::Agent < Clamp::Command
118
129
  require "logstash/pipeline"
119
130
  require "cabin" # gem 'cabin'
120
131
  require "logstash/plugin"
121
- @logger = Cabin::Channel.get(LogStash)
122
132
 
123
133
  LogStash::ShutdownWatcher.unsafe_shutdown = unsafe_shutdown?
124
134
  LogStash::ShutdownWatcher.logger = @logger
@@ -144,70 +154,63 @@ class LogStash::Agent < Clamp::Command
144
154
  end
145
155
 
146
156
  # You must specify a config_string or config_path
147
- if @config_string.nil? && @config_path.nil?
148
- fail(help + "\n" + I18n.t("logstash.agent.missing-configuration"))
157
+ if config_string.nil? && config_path.nil?
158
+ fail(I18n.t("logstash.agent.missing-configuration"))
149
159
  end
150
160
 
151
- @config_string = @config_string.to_s
161
+ if auto_reload? && config_path.nil?
162
+ # there's nothing to reload
163
+ fail(I18n.t("logstash.agent.reload-without-config-path"))
164
+ end
152
165
 
153
- if @config_path
154
- # Append the config string.
155
- # This allows users to provide both -f and -e flags. The combination
156
- # is rare, but useful for debugging.
157
- @config_string = @config_string + load_config(@config_path)
158
- else
159
- # include a default stdin input if no inputs given
160
- if @config_string !~ /input *{/
161
- @config_string += DEFAULT_INPUT
162
- end
163
- # include a default stdout output if no outputs given
164
- if @config_string !~ /output *{/
165
- @config_string += DEFAULT_OUTPUT
166
+ if config_test?
167
+ config_loader = LogStash::Config::Loader.new(@logger)
168
+ config_str = config_loader.format_config(config_path, config_string)
169
+ config_error = LogStash::Pipeline.config_valid?(config_str)
170
+ if config_error == true
171
+ @logger.terminal "Configuration OK"
172
+ return 0
173
+ else
174
+ @logger.fatal I18n.t("logstash.error", :error => config_error)
175
+ return 1
166
176
  end
167
177
  end
168
178
 
179
+ register_pipeline("main", @pipeline_settings.merge({
180
+ :config_string => config_string,
181
+ :config_path => config_path
182
+ }))
169
183
 
170
- begin
171
- pipeline = LogStash::Pipeline.new(@config_string, @pipeline_settings)
172
- rescue LoadError => e
173
- fail("Configuration problem.")
174
- end
184
+ sigint_id = trap_sigint()
185
+ sigterm_id = trap_sigterm()
186
+ sighup_id = trap_sighup()
175
187
 
176
- # Make SIGINT shutdown the pipeline.
177
- sigint_id = Stud::trap("INT") do
188
+ @logger.unsubscribe(stdout_logs) if show_startup_errors
178
189
 
179
- if @interrupted_once
180
- @logger.fatal(I18n.t("logstash.agent.forced_sigint"))
181
- exit
182
- else
183
- @logger.warn(I18n.t("logstash.agent.sigint"))
184
- Thread.new(@logger) {|logger| sleep 5; logger.warn(I18n.t("logstash.agent.slow_shutdown")) }
185
- @interrupted_once = true
186
- shutdown(pipeline)
187
- end
188
- end
190
+ @logger.info("starting agent")
189
191
 
190
- # Make SIGTERM shutdown the pipeline.
191
- sigterm_id = Stud::trap("TERM") do
192
- @logger.warn(I18n.t("logstash.agent.sigterm"))
193
- shutdown(pipeline)
194
- end
192
+ start_pipelines
195
193
 
196
- Stud::trap("HUP") do
197
- @logger.info(I18n.t("logstash.agent.sighup"))
198
- configure_logging(log_file)
199
- end
194
+ return 1 if clean_state?
200
195
 
201
- # Stop now if we are only asking for a config test.
202
- if config_test?
203
- @logger.terminal "Configuration OK"
204
- return
196
+ @thread = Thread.current # this var is implicilty used by Stud.stop?
197
+
198
+ Stud.stoppable_sleep(reload_interval) # sleep before looping
199
+
200
+ if auto_reload?
201
+ Stud.interval(reload_interval) { reload_state! }
202
+ else
203
+ while !Stud.stop?
204
+ if clean_state? || running_pipelines?
205
+ sleep 0.5
206
+ else
207
+ break
208
+ end
209
+ end
205
210
  end
206
211
 
207
- @logger.unsubscribe(stdout_logs) if show_startup_errors
212
+ shutdown
208
213
 
209
- # TODO(sissel): Get pipeline completion status.
210
- pipeline.run
211
214
  return 0
212
215
  rescue LogStash::ConfigurationError => e
213
216
  @logger.unsubscribe(stdout_logs) if show_startup_errors
@@ -224,51 +227,14 @@ class LogStash::Agent < Clamp::Command
224
227
  @log_fd.close if @log_fd
225
228
  Stud::untrap("INT", sigint_id) unless sigint_id.nil?
226
229
  Stud::untrap("TERM", sigterm_id) unless sigterm_id.nil?
230
+ Stud::untrap("HUP", sighup_id) unless sighup_id.nil?
227
231
  end # def execute
228
232
 
229
- def shutdown(pipeline)
230
- pipeline.shutdown do
231
- ::LogStash::ShutdownWatcher.start(pipeline)
232
- end
233
- end
234
-
235
- def show_version
236
- show_version_logstash
237
-
238
- if [:info, :debug].include?(verbosity?) || debug? || verbose?
239
- show_version_ruby
240
- show_version_java if LogStash::Environment.jruby?
241
- show_gems if [:debug].include?(verbosity?) || debug?
242
- end
243
- end # def show_version
244
-
245
- def show_version_logstash
246
- require "logstash/version"
247
- puts "logstash #{LOGSTASH_VERSION}"
248
- end # def show_version_logstash
249
-
250
- def show_version_ruby
251
- puts RUBY_DESCRIPTION
252
- end # def show_version_ruby
253
-
254
- def show_version_java
255
- properties = java.lang.System.getProperties
256
- puts "java #{properties["java.version"]} (#{properties["java.vendor"]})"
257
- puts "jvm #{properties["java.vm.name"]} / #{properties["java.vm.version"]}"
258
- end # def show_version_java
259
-
260
- def show_gems
261
- require "rubygems"
262
- Gem::Specification.each do |spec|
263
- puts "gem #{spec.name} #{spec.version}"
264
- end
265
- end # def show_gems
266
233
 
267
234
  # Do any start-time configuration.
268
235
  #
269
236
  # Log file stuff, plugin path checking, etc.
270
237
  def configure
271
- @pipeline_settings[:debug_config] = debug_config?
272
238
  configure_logging(log_file)
273
239
  configure_plugin_paths(plugin_paths)
274
240
  end # def configure
@@ -329,63 +295,205 @@ class LogStash::Agent < Clamp::Command
329
295
  end
330
296
  end
331
297
 
332
- def load_config(path)
333
- begin
334
- uri = URI.parse(path)
335
-
336
- case uri.scheme
337
- when nil then
338
- local_config(path)
339
- when /http/ then
340
- fetch_config(uri)
341
- when "file" then
342
- local_config(uri.path)
298
+ ## Signal Trapping ##
299
+ def trap_sigint
300
+ Stud::trap("INT") do
301
+ if @interrupted_once
302
+ @logger.fatal(I18n.t("logstash.agent.forced_sigint"))
303
+ exit
343
304
  else
344
- fail(I18n.t("logstash.agent.configuration.scheme-not-supported", :path => path))
305
+ @logger.warn(I18n.t("logstash.agent.sigint"))
306
+ Thread.new(@logger) {|logger| sleep 5; logger.warn(I18n.t("logstash.agent.slow_shutdown")) }
307
+ @interrupted_once = true
308
+ Stud.stop!(@thread)
345
309
  end
346
- rescue URI::InvalidURIError
347
- # fallback for windows.
348
- # if the parsing of the file failed we assume we can reach it locally.
349
- # some relative path on windows arent parsed correctly (.\logstash.conf)
350
- local_config(path)
351
310
  end
352
311
  end
353
312
 
354
- def local_config(path)
355
- path = File.expand_path(path)
356
- path = File.join(path, "*") if File.directory?(path)
313
+ def trap_sigterm
314
+ Stud::trap("TERM") do
315
+ @logger.warn(I18n.t("logstash.agent.sigterm"))
316
+ Stud.stop!(@thread)
317
+ end
318
+ end
319
+
320
+ def trap_sighup
321
+ Stud::trap("HUP") do
322
+ @logger.warn(I18n.t("logstash.agent.sighup"))
323
+ reload_state!
324
+ end
325
+ end
357
326
 
358
- if Dir.glob(path).length == 0
359
- fail(I18n.t("logstash.agent.configuration.file-not-found", :path => path))
327
+ ## Pipeline CRUD ##
328
+ def shutdown(pipeline)
329
+ pipeline.shutdown do
330
+ ::LogStash::ShutdownWatcher.start(pipeline)
360
331
  end
332
+ end
333
+ #
334
+ # register_pipeline - adds a pipeline to the agent's state
335
+ # @param pipeline_id [String] pipeline string identifier
336
+ # @param settings [Hash] settings that will be passed when creating the pipeline.
337
+ # keys should be symbols such as :pipeline_workers and :pipeline_batch_delay
338
+ def register_pipeline(pipeline_id, settings)
339
+ pipeline = create_pipeline(settings.merge(:pipeline_id => pipeline_id))
340
+ return unless pipeline.is_a?(LogStash::Pipeline)
341
+ if @auto_reload && pipeline.non_reloadable_plugins.any?
342
+ @logger.error(I18n.t("logstash.agent.non_reloadable_config_register"),
343
+ :pipeline_id => pipeline_id,
344
+ :plugins => pipeline.non_reloadable_plugins.map(&:class))
345
+ return
346
+ end
347
+ @pipelines[pipeline_id] = pipeline
348
+ end
361
349
 
362
- config = ""
363
- encoding_issue_files = []
364
- Dir.glob(path).sort.each do |file|
365
- next unless File.file?(file)
366
- if file.match(/~$/)
367
- @logger.debug("NOT reading config file because it is a temp file", :file => file)
368
- next
369
- end
370
- @logger.debug("Reading config file", :file => file)
371
- cfg = File.read(file)
372
- if !cfg.ascii_only? && !cfg.valid_encoding?
373
- encoding_issue_files << file
350
+ def reload_state!
351
+ @upgrade_mutex.synchronize do
352
+ @pipelines.each do |pipeline_id, _|
353
+ begin
354
+ reload_pipeline!(pipeline_id)
355
+ rescue => e
356
+ @logger.error(I18n.t("oops"), :error => e, :backtrace => e.backtrace)
357
+ end
374
358
  end
375
- config << cfg + "\n"
376
359
  end
377
- if (encoding_issue_files.any?)
378
- fail("The following config files contains non-ascii characters but are not UTF-8 encoded #{encoding_issue_files}")
360
+ end
361
+
362
+ def create_pipeline(settings)
363
+ begin
364
+ config = fetch_config(settings)
365
+ rescue => e
366
+ @logger.error("failed to fetch pipeline configuration", :message => e.message)
367
+ return
379
368
  end
380
- return config
381
- end # def load_config
382
369
 
383
- def fetch_config(uri)
384
370
  begin
385
- Net::HTTP.get(uri) + "\n"
386
- rescue Exception => e
387
- fail(I18n.t("logstash.agent.configuration.fetch-failed", :path => uri.to_s, :message => e.message))
371
+ LogStash::Pipeline.new(config, settings)
372
+ rescue => e
373
+ @logger.error("fetched an invalid config", :config => config, :reason => e.message)
374
+ return
375
+ end
376
+ end
377
+
378
+ def start_pipelines
379
+ @pipelines.each { |id, _| start_pipeline(id) }
380
+ end
381
+
382
+ def shutdown
383
+ shutdown_pipelines
384
+ end
385
+
386
+ def shutdown_pipelines
387
+ @pipelines.each { |id, _| stop_pipeline(id) }
388
+ end
389
+
390
+ def stop_pipeline(id)
391
+ pipeline = @pipelines[id]
392
+ return unless pipeline
393
+ @logger.log("stopping pipeline", :id => id)
394
+ pipeline.shutdown { LogStash::ShutdownWatcher.start(pipeline) }
395
+ @pipelines[id].thread.join
396
+ end
397
+
398
+ def running_pipelines?
399
+ @upgrade_mutex.synchronize do
400
+ @pipelines.select {|pipeline_id, _| running_pipeline?(pipeline_id) }.any?
388
401
  end
389
402
  end
390
403
 
404
+ def running_pipeline?(pipeline_id)
405
+ thread = @pipelines[pipeline_id].thread
406
+ thread.is_a?(Thread) && thread.alive?
407
+ end
408
+
409
+ def upgrade_pipeline(pipeline_id, new_pipeline)
410
+ stop_pipeline(pipeline_id)
411
+ @pipelines[pipeline_id] = new_pipeline
412
+ start_pipeline(pipeline_id)
413
+ end
414
+
415
+ def clean_state?
416
+ @pipelines.empty?
417
+ end
418
+
419
+ # since this method modifies the @pipelines hash it is
420
+ # wrapped in @upgrade_mutex in the parent call `reload_state!`
421
+ def reload_pipeline!(id)
422
+ old_pipeline = @pipelines[id]
423
+ new_pipeline = create_pipeline(old_pipeline.original_settings)
424
+ return if new_pipeline.nil?
425
+
426
+ if old_pipeline.config_str == new_pipeline.config_str
427
+ @logger.debug("no configuration change for pipeline",
428
+ :pipeline => id, :config => old_pipeline.config_str)
429
+ elsif new_pipeline.non_reloadable_plugins.any?
430
+ @logger.error(I18n.t("logstash.agent.non_reloadable_config_reload"),
431
+ :pipeline_id => id,
432
+ :plugins => new_pipeline.non_reloadable_plugins.map(&:class))
433
+ else
434
+ @logger.log("fetched new config for pipeline. upgrading..",
435
+ :pipeline => id, :config => new_pipeline.config_str)
436
+ upgrade_pipeline(id, new_pipeline)
437
+ end
438
+ end
439
+
440
+ def start_pipeline(id)
441
+ pipeline = @pipelines[id]
442
+ return unless pipeline.is_a?(LogStash::Pipeline)
443
+ return if pipeline.ready?
444
+ @logger.info("starting pipeline", :id => id)
445
+ Thread.new do
446
+ LogStash::Util.set_thread_name("pipeline.#{id}")
447
+ begin
448
+ pipeline.run
449
+ rescue => e
450
+ @logger.error("Pipeline aborted due to error", :exception => e, :backtrace => e.backtrace)
451
+ end
452
+ end
453
+ sleep 0.01 until pipeline.ready?
454
+ end
455
+
456
+ ## Pipeline Aux methods ##
457
+ def fetch_config(settings)
458
+ @config_loader.format_config(settings[:config_path], settings[:config_string])
459
+ end
460
+
461
+ private
462
+ def node_uuid
463
+ @node_uuid ||= SecureRandom.uuid
464
+ end
465
+
466
+ ### Version actions ###
467
+ def show_version
468
+ show_version_logstash
469
+
470
+ if [:info, :debug].include?(verbosity?) || debug? || verbose?
471
+ show_version_ruby
472
+ show_version_java if LogStash::Environment.jruby?
473
+ show_gems if [:debug].include?(verbosity?) || debug?
474
+ end
475
+ end # def show_version
476
+
477
+ def show_version_logstash
478
+ require "logstash/version"
479
+ puts "logstash #{LOGSTASH_VERSION}"
480
+ end # def show_version_logstash
481
+
482
+ def show_version_ruby
483
+ puts RUBY_DESCRIPTION
484
+ end # def show_version_ruby
485
+
486
+ def show_version_java
487
+ properties = java.lang.System.getProperties
488
+ puts "java #{properties["java.version"]} (#{properties["java.vendor"]})"
489
+ puts "jvm #{properties["java.vm.name"]} / #{properties["java.vm.version"]}"
490
+ end # def show_version_java
491
+
492
+ def show_gems
493
+ require "rubygems"
494
+ Gem::Specification.each do |spec|
495
+ puts "gem #{spec.name} #{spec.version}"
496
+ end
497
+ end # def show_gems
498
+
391
499
  end # class LogStash::Agent