logstash-core 2.2.4.snapshot2-java → 2.3.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of logstash-core might be problematic. Click here for more details.

checksums.yaml 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