logstash-core 5.5.3-java → 5.6.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core/logstash-core.jar +0 -0
  3. data/lib/logstash-core/version.rb +1 -1
  4. data/lib/logstash/api/commands/node.rb +2 -2
  5. data/lib/logstash/api/commands/stats.rb +2 -2
  6. data/lib/logstash/config/config_ast.rb +24 -1
  7. data/lib/logstash/config/modules_common.rb +47 -15
  8. data/lib/logstash/config/source/modules.rb +55 -0
  9. data/lib/logstash/config/string_escape.rb +27 -0
  10. data/lib/logstash/elasticsearch_client.rb +24 -2
  11. data/lib/logstash/environment.rb +2 -0
  12. data/lib/logstash/filter_delegator.rb +9 -6
  13. data/lib/logstash/instrument/collector.rb +7 -5
  14. data/lib/logstash/instrument/metric_store.rb +11 -11
  15. data/lib/logstash/instrument/namespaced_metric.rb +4 -0
  16. data/lib/logstash/instrument/namespaced_null_metric.rb +4 -0
  17. data/lib/logstash/instrument/null_metric.rb +10 -0
  18. data/lib/logstash/instrument/periodic_poller/dlq.rb +19 -0
  19. data/lib/logstash/instrument/periodic_pollers.rb +3 -1
  20. data/lib/logstash/instrument/wrapped_write_client.rb +33 -24
  21. data/lib/logstash/logging/logger.rb +26 -19
  22. data/lib/logstash/modules/{importer.rb → elasticsearch_importer.rb} +3 -3
  23. data/lib/logstash/modules/kibana_base.rb +24 -0
  24. data/lib/logstash/modules/kibana_client.rb +124 -0
  25. data/lib/logstash/modules/kibana_config.rb +29 -28
  26. data/lib/logstash/modules/kibana_dashboards.rb +36 -0
  27. data/lib/logstash/modules/kibana_importer.rb +17 -0
  28. data/lib/logstash/modules/kibana_settings.rb +40 -0
  29. data/lib/logstash/modules/logstash_config.rb +89 -17
  30. data/lib/logstash/modules/resource_base.rb +6 -5
  31. data/lib/logstash/modules/scaffold.rb +11 -3
  32. data/lib/logstash/modules/settings_merger.rb +23 -0
  33. data/lib/logstash/modules/util.rb +17 -0
  34. data/lib/logstash/output_delegator.rb +7 -5
  35. data/lib/logstash/pipeline.rb +34 -2
  36. data/lib/logstash/runner.rb +8 -13
  37. data/lib/logstash/settings.rb +20 -1
  38. data/lib/logstash/util/wrapped_acked_queue.rb +5 -24
  39. data/lib/logstash/util/wrapped_synchronous_queue.rb +14 -24
  40. data/lib/logstash/version.rb +1 -1
  41. data/locales/en.yml +11 -4
  42. data/spec/logstash/agent_spec.rb +19 -6
  43. data/spec/logstash/api/modules/node_spec.rb +2 -1
  44. data/spec/logstash/config/config_ast_spec.rb +47 -8
  45. data/spec/logstash/config/string_escape_spec.rb +24 -0
  46. data/spec/logstash/event_spec.rb +9 -0
  47. data/spec/logstash/filter_delegator_spec.rb +21 -7
  48. data/spec/logstash/instrument/periodic_poller/dlq_spec.rb +17 -0
  49. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +1 -1
  50. data/spec/logstash/legacy_ruby_event_spec.rb +4 -4
  51. data/spec/logstash/modules/logstash_config_spec.rb +56 -0
  52. data/spec/logstash/modules/scaffold_spec.rb +234 -0
  53. data/spec/logstash/output_delegator_spec.rb +15 -5
  54. data/spec/logstash/pipeline_spec.rb +76 -26
  55. data/spec/logstash/runner_spec.rb +46 -25
  56. data/spec/logstash/settings/splittable_string_array_spec.rb +51 -0
  57. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +0 -22
  58. metadata +22 -4
  59. data/lib/logstash/modules/kibana_base_resource.rb +0 -10
  60. data/lib/logstash/program.rb +0 -14
@@ -21,20 +21,10 @@ require "logstash/patches/clamp"
21
21
  require "logstash/settings"
22
22
  require "logstash/version"
23
23
  require "logstash/plugins/registry"
24
+ require "logstash/modules/util"
24
25
 
25
26
  java_import 'org.logstash.FileLockFactory'
26
27
 
27
- def register_local_modules(path)
28
- modules_path = File.join(path, File::Separator, "modules")
29
- Dir.foreach(modules_path) do |item|
30
- # Ignore unix relative path ids
31
- next if item == '.' or item == '..'
32
- # Ignore non-directories
33
- next if !File.directory?(File.join(modules_path, File::Separator, item))
34
- LogStash::PLUGIN_REGISTRY.add(:modules, item, LogStash::Modules::Scaffold.new(item, File.join(modules_path, File::Separator, item, File::Separator, "configuration")))
35
- end
36
- end
37
-
38
28
  class LogStash::Runner < Clamp::StrictCommand
39
29
  include LogStash::Util::Loggable
40
30
  # The `path.settings` and `path.logs` need to be defined in the runner instead of the `logstash-core/lib/logstash/environment.rb`
@@ -73,6 +63,11 @@ class LogStash::Runner < Clamp::StrictCommand
73
63
  :multivalued => true,
74
64
  :attribute_name => "modules_variable_list"
75
65
 
66
+ option ["--setup"], :flag,
67
+ I18n.t("logstash.runner.flag.modules_setup"),
68
+ :default => LogStash::SETTINGS.get_default("modules_setup"),
69
+ :attribute_name => "modules_setup"
70
+
76
71
  # Pipeline settings
77
72
  option ["-w", "--pipeline.workers"], "COUNT",
78
73
  I18n.t("logstash.runner.flag.pipeline-workers"),
@@ -226,7 +221,7 @@ class LogStash::Runner < Clamp::StrictCommand
226
221
  java.lang.System.setProperty("ls.log.level", setting("log.level"))
227
222
  unless java.lang.System.getProperty("log4j.configurationFile")
228
223
  log4j_config_location = ::File.join(setting("path.settings"), "log4j2.properties")
229
- LogStash::Logging::Logger::initialize("file:///" + log4j_config_location)
224
+ LogStash::Logging::Logger::reconfigure("file:///" + log4j_config_location)
230
225
  end
231
226
  # override log level that may have been introduced from a custom log4j config file
232
227
  LogStash::Logging::Logger::configure_logging(setting("log.level"))
@@ -236,7 +231,7 @@ class LogStash::Runner < Clamp::StrictCommand
236
231
  end
237
232
 
238
233
  # Add local modules to the registry before everything else
239
- register_local_modules(LogStash::Environment::LOGSTASH_HOME)
234
+ LogStash::Modules::Util.register_local_modules(LogStash::Environment::LOGSTASH_HOME)
240
235
 
241
236
  # We configure the registry and load any plugin that can register hooks
242
237
  # with logstash, this need to be done before any operation.
@@ -534,8 +534,27 @@ module LogStash
534
534
  end
535
535
  end
536
536
  end
537
- end
538
537
 
538
+ class SplittableStringArray < ArrayCoercible
539
+ DEFAULT_TOKEN = ","
540
+
541
+ def initialize(name, klass, default, strict=true, tokenizer = DEFAULT_TOKEN, &validator_proc)
542
+ @element_class = klass
543
+ @token = tokenizer
544
+ super(name, klass, default, strict, &validator_proc)
545
+ end
546
+
547
+ def coerce(value)
548
+ if value.is_a?(Array)
549
+ value
550
+ elsif value.nil?
551
+ []
552
+ else
553
+ value.split(@token).map(&:strip)
554
+ end
555
+ end
556
+ end
557
+ end
539
558
 
540
559
  SETTINGS = Settings.new
541
560
  end
@@ -57,24 +57,6 @@ module LogStash; module Util
57
57
  end
58
58
  alias_method(:<<, :push)
59
59
 
60
- # TODO - fix doc for this noop method
61
- # Offer an object to the queue, wait for the specified amount of time.
62
- # If adding to the queue was successful it will return true, false otherwise.
63
- #
64
- # @param [Object] Object to add to the queue
65
- # @param [Integer] Time in milliseconds to wait before giving up
66
- # @return [Boolean] True if adding was successful if not it return false
67
- def offer(obj, timeout_ms)
68
- raise NotImplementedError.new("The offer method is not implemented. There is no non blocking write operation yet.")
69
- end
70
-
71
- # Blocking
72
- def take
73
- check_closed("read a batch")
74
- # TODO - determine better arbitrary timeout millis
75
- @queue.read_batch(1, 200).get_elements.first
76
- end
77
-
78
60
  # Block for X millis
79
61
  def poll(millis)
80
62
  check_closed("read")
@@ -223,19 +205,18 @@ module LogStash; module Util
223
205
  end
224
206
 
225
207
  def start_clock
226
- @inflight_clocks[Thread.current] = [
227
- @event_metric.time(:duration_in_millis),
228
- @pipeline_metric.time(:duration_in_millis)
229
- ]
208
+ @inflight_clocks[Thread.current] = java.lang.System.current_time_millis
230
209
  end
231
210
 
232
211
  def stop_clock(batch)
233
212
  unless @inflight_clocks[Thread.current].nil?
234
213
  if batch.size > 0
235
- # onl/y stop (which also records) the metrics if the batch is non-empty.
214
+ # only stop (which also records) the metrics if the batch is non-empty.
236
215
  # start_clock is now called at empty batch creation and an empty batch could
237
216
  # stay empty all the way down to the close_batch call.
238
- @inflight_clocks[Thread.current].each(&:stop)
217
+ time_taken = java.lang.System.current_time_millis - @inflight_clocks[Thread.current]
218
+ @event_metric.report_time(:duration_in_millis, time_taken)
219
+ @pipeline_metric.report_time(:duration_in_millis, time_taken)
239
220
  end
240
221
  @inflight_clocks.delete(Thread.current)
241
222
  end
@@ -18,21 +18,6 @@ module LogStash; module Util
18
18
  end
19
19
  alias_method(:<<, :push)
20
20
 
21
- # Offer an object to the queue, wait for the specified amount of time.
22
- # If adding to the queue was successful it wil return true, false otherwise.
23
- #
24
- # @param [Object] Object to add to the queue
25
- # @param [Integer] Time in milliseconds to wait before giving up
26
- # @return [Boolean] True if adding was successful if not it return false
27
- def offer(obj, timeout_ms)
28
- @queue.offer(obj, timeout_ms, TimeUnit::MILLISECONDS)
29
- end
30
-
31
- # Blocking
32
- def take
33
- @queue.take
34
- end
35
-
36
21
  # Block for X millis
37
22
  def poll(millis)
38
23
  @queue.poll(millis, TimeUnit::MILLISECONDS)
@@ -83,11 +68,17 @@ module LogStash; module Util
83
68
 
84
69
  def set_events_metric(metric)
85
70
  @event_metric = metric
71
+ @event_metric_out = @event_metric.counter(:out)
72
+ @event_metric_filtered = @event_metric.counter(:filtered)
73
+ @event_metric_time = @event_metric.counter(:duration_in_millis)
86
74
  define_initial_metrics_values(@event_metric)
87
75
  end
88
76
 
89
77
  def set_pipeline_metric(metric)
90
78
  @pipeline_metric = metric
79
+ @pipeline_metric_out = @pipeline_metric.counter(:out)
80
+ @pipeline_metric_filtered = @pipeline_metric.counter(:filtered)
81
+ @pipeline_metric_time = @pipeline_metric.counter(:duration_in_millis)
91
82
  define_initial_metrics_values(@pipeline_metric)
92
83
  end
93
84
 
@@ -155,10 +146,7 @@ module LogStash; module Util
155
146
  end
156
147
 
157
148
  def start_clock
158
- @inflight_clocks[Thread.current] = [
159
- @event_metric.time(:duration_in_millis),
160
- @pipeline_metric.time(:duration_in_millis)
161
- ]
149
+ @inflight_clocks[Thread.current] = java.lang.System.current_time_millis
162
150
  end
163
151
 
164
152
  def stop_clock(batch)
@@ -167,20 +155,22 @@ module LogStash; module Util
167
155
  # only stop (which also records) the metrics if the batch is non-empty.
168
156
  # start_clock is now called at empty batch creation and an empty batch could
169
157
  # stay empty all the way down to the close_batch call.
170
- @inflight_clocks[Thread.current].each(&:stop)
158
+ time_taken = java.lang.System.current_time_millis - @inflight_clocks[Thread.current]
159
+ @event_metric_time.increment(time_taken)
160
+ @pipeline_metric_time.increment(time_taken)
171
161
  end
172
162
  @inflight_clocks.delete(Thread.current)
173
163
  end
174
164
  end
175
165
 
176
166
  def add_filtered_metrics(batch)
177
- @event_metric.increment(:filtered, batch.filtered_size)
178
- @pipeline_metric.increment(:filtered, batch.filtered_size)
167
+ @event_metric_filtered.increment(batch.filtered_size)
168
+ @pipeline_metric_filtered.increment(batch.filtered_size)
179
169
  end
180
170
 
181
171
  def add_output_metrics(batch)
182
- @event_metric.increment(:out, batch.filtered_size)
183
- @pipeline_metric.increment(:out, batch.filtered_size)
172
+ @event_metric_out.increment(batch.filtered_size)
173
+ @pipeline_metric_out.increment(batch.filtered_size)
184
174
  end
185
175
  end
186
176
 
@@ -11,4 +11,4 @@
11
11
  # eventually this file should be in the root logstash lib fir and dependencies in logstash-core should be
12
12
  # fixed.
13
13
 
14
- LOGSTASH_VERSION = "5.5.3"
14
+ LOGSTASH_VERSION = "5.6.0"
@@ -100,8 +100,10 @@ en:
100
100
  Specified modules: %{specified_modules}
101
101
  Available modules: %{available_modules}
102
102
  elasticsearch_connection_failed: >-
103
- Failed to import module configurations to Elasticsearch.
104
- Module: %{module_name} has hosts: %{hosts}
103
+ Failed to import module configurations to Elasticsearch and/or Kibana.
104
+ Module: %{module_name} has Elasticsearch hosts: %{elasticsearch_hosts} and Kibana hosts: %{kibana_hosts}
105
+ modules-too-many-specified: >-
106
+ Too many modules specified. Maximum allowed: %{max}, specified: %{specified_modules}
105
107
 
106
108
  runner:
107
109
  short-help: |-
@@ -120,10 +122,11 @@ en:
120
122
  config-module-exclusive: >-
121
123
  Settings 'path.config' (-f) or 'config.string' (-e) can't be used in conjunction with
122
124
  (--modules) or the "modules:" block in the logstash.yml file.
125
+ reload-with-modules: >-
126
+ Configuration reloading can't be used with command-line or logstash.yml specified modules.
123
127
  cli-module-override: >-
124
128
  Both command-line and logstash.yml modules configurations detected.
125
- Using command-line module configuration and ignoring logstash.yml module
126
- configuration.
129
+ Using command-line module configuration to override logstash.yml module configuration.
127
130
  reload-without-config-path: >-
128
131
  Configuration reloading also requires passing a configuration path with '-f yourlogstash.conf'
129
132
  locked-data-path: >-
@@ -227,6 +230,10 @@ en:
227
230
  '-M "MODULE_NAME.var.PLUGIN_TYPE.PLUGIN_NAME.VARIABLE_NAME=VALUE"'
228
231
  as in
229
232
  '-M "example.var.filter.mutate.fieldname=fieldvalue"'
233
+ modules_setup: |+
234
+ Load index template into Elasticsearch, and saved searches,
235
+ index-pattern, visualizations, and dashboards into Kibana when
236
+ running modules.
230
237
  configtest: |+
231
238
  Check configuration for valid syntax and then exit.
232
239
  http_host: Web API binding host
@@ -5,6 +5,7 @@ require "logstash/inputs/generator"
5
5
  require_relative "../support/mocks_classes"
6
6
  require "fileutils"
7
7
  require_relative "../support/helpers"
8
+ require 'timeout'
8
9
 
9
10
  describe LogStash::Agent do
10
11
 
@@ -16,6 +17,7 @@ describe LogStash::Agent do
16
17
  let(:config_file) { Stud::Temporary.pathname }
17
18
  let(:config_file_txt) { "input { generator { count => 100000 } } output { }" }
18
19
  let(:logger) { double("logger") }
20
+ let(:timeout) {120} #seconds
19
21
 
20
22
  subject { LogStash::Agent.new(agent_settings) }
21
23
 
@@ -151,7 +153,9 @@ describe LogStash::Agent do
151
153
 
152
154
  it "does not try to reload the pipeline" do
153
155
  t = Thread.new { subject.execute }
154
- sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
156
+ Timeout.timeout(timeout) do
157
+ sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
158
+ end
155
159
  expect(subject).to_not receive(:reload_pipeline!)
156
160
  File.open(config_file, "w") { |f| f.puts second_pipeline_config }
157
161
  subject.reload_state!
@@ -183,7 +187,9 @@ describe LogStash::Agent do
183
187
 
184
188
  it "tries to reload the pipeline" do
185
189
  t = Thread.new { subject.execute }
186
- sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
190
+ Timeout.timeout(timeout) do
191
+ sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
192
+ end
187
193
  expect(subject).to receive(:reload_pipeline!).once.and_call_original
188
194
  File.open(config_file, "w") { |f| f.puts second_pipeline_config }
189
195
  subject.reload_state!
@@ -213,8 +219,9 @@ describe LogStash::Agent do
213
219
  it "should periodically reload_state" do
214
220
  allow(subject).to receive(:clean_state?).and_return(false)
215
221
  t = Thread.new { subject.execute }
216
- sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
217
-
222
+ Timeout.timeout(timeout) do
223
+ sleep(0.01) until subject.running_pipelines? && subject.pipelines.values.first.running?
224
+ end
218
225
  expect(subject).to receive(:reload_state!).at_least(2).times
219
226
 
220
227
  sleep 1
@@ -451,7 +458,9 @@ describe LogStash::Agent do
451
458
  pipeline_thread
452
459
 
453
460
  # wait for some events to reach the dummy_output
454
- sleep(0.1) until dummy_output.events_received > initial_generator_threshold
461
+ Timeout.timeout(timeout) do
462
+ sleep(0.1) until dummy_output.events_received > initial_generator_threshold
463
+ end
455
464
  end
456
465
 
457
466
  after :each do
@@ -459,6 +468,8 @@ describe LogStash::Agent do
459
468
  subject.shutdown
460
469
  Stud.stop!(pipeline_thread)
461
470
  pipeline_thread.join
471
+ rescue
472
+ #don't care about errors here.
462
473
  ensure
463
474
  Thread.abort_on_exception = @abort_on_exception
464
475
  end
@@ -477,7 +488,9 @@ describe LogStash::Agent do
477
488
  subject.send(:"reload_pipeline!", "main")
478
489
 
479
490
  # wait until pipeline restarts
480
- sleep(0.01) until dummy_output2.events_received > 0
491
+ Timeout.timeout(timeout) do
492
+ sleep(0.01) until dummy_output2.events_received > 0
493
+ end
481
494
  end
482
495
 
483
496
  it "resets the pipeline metric collector" do
@@ -114,7 +114,8 @@ describe LogStash::Api::Modules::Node do
114
114
  "batch_size" => Numeric,
115
115
  "batch_delay" => Numeric,
116
116
  "config_reload_automatic" => Boolean,
117
- "config_reload_interval" => Numeric
117
+ "config_reload_interval" => Numeric,
118
+ "dead_letter_queue_enabled" => Boolean
118
119
  },
119
120
  "os" => {
120
121
  "name" => String,
@@ -6,6 +6,8 @@ require "logstash/config/grammar"
6
6
  require "logstash/config/config_ast"
7
7
 
8
8
  describe LogStashConfigParser do
9
+ let(:settings) { mock_settings({}) }
10
+
9
11
  context '#parse' do
10
12
  context "valid configuration" do
11
13
  it "should permit single-quoted attribute names" do
@@ -77,7 +79,7 @@ describe LogStashConfigParser do
77
79
  }
78
80
  CONFIG
79
81
  subject { LogStashConfigParser.new }
80
-
82
+
81
83
  it "should compile successfully" do
82
84
  result = subject.parse(config)
83
85
  expect(result).not_to(be_nil)
@@ -142,12 +144,50 @@ describe LogStashConfigParser do
142
144
  expect(config).to be_nil
143
145
  end
144
146
  end
147
+
148
+ context "when config.support_escapes" do
149
+ let(:parser) { LogStashConfigParser.new }
150
+
151
+ let(:processed_value) { 'The computer says, "No"' }
152
+
153
+ let(:config) {
154
+ parser.parse(%q(
155
+ input {
156
+ foo {
157
+ bar => "The computer says, \"No\""
158
+ }
159
+ }
160
+ ))
161
+ }
162
+
163
+ let(:compiled_string) { eval(config.recursive_select(LogStash::Config::AST::String).first.compile) }
164
+
165
+ before do
166
+ config.process_escape_sequences = escapes
167
+ end
168
+
169
+ context "is enabled" do
170
+ let(:escapes) { true }
171
+
172
+ it "should process escape sequences" do
173
+ expect(compiled_string).to be == processed_value
174
+ end
175
+ end
176
+
177
+ context "is false" do
178
+ let(:escapes) { false }
179
+
180
+ it "should not process escape sequences" do
181
+ expect(compiled_string).not_to be == processed_value
182
+ end
183
+ end
184
+ end
145
185
  end
146
186
 
147
187
  context "when using two plugin sections of the same type" do
148
188
  let(:pipeline_klass) do
149
189
  Class.new do
150
- def initialize(config)
190
+ def initialize(config, settings)
151
191
  grammar = LogStashConfigParser.new
152
192
  @config = grammar.parse(config)
153
193
  @code = @config.compile
@@ -166,7 +206,7 @@ describe LogStashConfigParser do
166
206
 
167
207
 
168
208
  it "should create a pipeline with both sections" do
169
- generated_objects = pipeline_klass.new(config_string).instance_variable_get("@generated_objects")
209
+ generated_objects = pipeline_klass.new(config_string, settings).instance_variable_get("@generated_objects")
170
210
  filters = generated_objects.keys.map(&:to_s).select {|obj_name| obj_name.match(/^filter.+?_\d+$/) }
171
211
  expect(filters.size).to eq(2)
172
212
  end
@@ -181,14 +221,13 @@ describe LogStashConfigParser do
181
221
 
182
222
 
183
223
  it "should create a pipeline with both sections" do
184
- generated_objects = pipeline_klass.new(config_string).instance_variable_get("@generated_objects")
224
+ generated_objects = pipeline_klass.new(config_string, settings).instance_variable_get("@generated_objects")
185
225
  outputs = generated_objects.keys.map(&:to_s).select {|obj_name| obj_name.match(/^output.+?_\d+$/) }
186
226
  expect(outputs.size).to eq(2)
187
227
  end
188
228
  end
189
229
  end
190
230
  context "when creating two instances of the same configuration" do
191
-
192
231
  let(:config_string) {
193
232
  "input { generator { } }
194
233
  filter {
@@ -201,7 +240,7 @@ describe LogStashConfigParser do
201
240
 
202
241
  let(:pipeline_klass) do
203
242
  Class.new do
204
- def initialize(config)
243
+ def initialize(config, settings)
205
244
  grammar = LogStashConfigParser.new
206
245
  @config = grammar.parse(config)
207
246
  @code = @config.compile
@@ -213,8 +252,8 @@ describe LogStashConfigParser do
213
252
 
214
253
  describe "generated conditional functionals" do
215
254
  it "should be created per instance" do
216
- instance_1 = pipeline_klass.new(config_string)
217
- instance_2 = pipeline_klass.new(config_string)
255
+ instance_1 = pipeline_klass.new(config_string, settings)
256
+ instance_2 = pipeline_klass.new(config_string, settings)
218
257
  generated_method_1 = instance_1.instance_variable_get("@generated_objects")[:cond_func_1]
219
258
  generated_method_2 = instance_2.instance_variable_get("@generated_objects")[:cond_func_1]
220
259
  expect(generated_method_1).to_not be(generated_method_2)