logstash-core 5.0.0.alpha4.snapshot1-java → 5.0.0.alpha4.snapshot2-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.

Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core/version.rb +1 -1
  3. data/lib/logstash/agent.rb +31 -36
  4. data/lib/logstash/api/command_factory.rb +3 -1
  5. data/lib/logstash/api/commands/base.rb +4 -0
  6. data/lib/logstash/api/commands/node.rb +116 -0
  7. data/lib/logstash/api/commands/stats.rb +28 -77
  8. data/lib/logstash/api/modules/base.rb +2 -2
  9. data/lib/logstash/api/modules/node.rb +23 -6
  10. data/lib/logstash/api/modules/node_stats.rb +15 -1
  11. data/lib/logstash/api/rack_app.rb +9 -6
  12. data/lib/logstash/api/service.rb +8 -47
  13. data/lib/logstash/config/config_ast.rb +11 -3
  14. data/lib/logstash/config/mixin.rb +60 -22
  15. data/lib/logstash/inputs/metrics.rb +2 -2
  16. data/lib/logstash/instrument/collector.rb +5 -6
  17. data/lib/logstash/instrument/metric.rb +1 -1
  18. data/lib/logstash/instrument/metric_store.rb +54 -0
  19. data/lib/logstash/pipeline.rb +10 -4
  20. data/lib/logstash/runner.rb +2 -2
  21. data/lib/logstash/util/safe_uri.rb +48 -0
  22. data/lib/logstash/version.rb +1 -1
  23. data/lib/logstash/webserver.rb +8 -7
  24. data/logstash-core.gemspec +1 -1
  25. data/spec/api/lib/api/node_plugins_spec.rb +32 -0
  26. data/spec/api/lib/api/node_spec.rb +41 -7
  27. data/spec/api/lib/api/node_stats_spec.rb +31 -6
  28. data/spec/api/lib/api/plugins_spec.rb +1 -7
  29. data/spec/api/lib/api/root_spec.rb +2 -7
  30. data/spec/api/lib/api/support/resource_dsl_methods.rb +14 -7
  31. data/spec/api/spec_helper.rb +24 -50
  32. data/spec/logstash/agent_spec.rb +36 -13
  33. data/spec/logstash/config/config_ast_spec.rb +43 -0
  34. data/spec/logstash/config/mixin_spec.rb +138 -0
  35. data/spec/logstash/inputs/metrics_spec.rb +10 -11
  36. data/spec/logstash/instrument/collector_spec.rb +1 -1
  37. data/spec/logstash/instrument/metric_store_spec.rb +61 -0
  38. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +6 -3
  39. data/spec/logstash/pipeline_spec.rb +9 -9
  40. data/spec/support/mocks_classes.rb +2 -1
  41. metadata +39 -35
@@ -3,6 +3,11 @@ module LogStash
3
3
  module Api
4
4
  module Modules
5
5
  class NodeStats < ::LogStash::Api::Modules::Base
6
+ #set :environment, :test
7
+ #set :dump_errors, true
8
+ #set :raise_errors, true
9
+ #set :logging, Logger.new(STDERR)
10
+
6
11
 
7
12
  before do
8
13
  @stats = factory.build(:stats)
@@ -14,7 +19,8 @@ module LogStash
14
19
  payload = {
15
20
  :events => events_payload,
16
21
  :jvm => jvm_payload,
17
- :process => process_payload
22
+ :process => process_payload,
23
+ :mem => mem_payload
18
24
  }
19
25
 
20
26
  respond_with payload
@@ -40,6 +46,10 @@ module LogStash
40
46
  respond_with :process => process_payload
41
47
  end
42
48
 
49
+ get "/mem" do
50
+ respond_with :mem => mem_payload
51
+ end
52
+
43
53
  private
44
54
 
45
55
  def events_payload
@@ -53,6 +63,10 @@ module LogStash
53
63
  def process_payload
54
64
  @stats.process
55
65
  end
66
+
67
+ def mem_payload
68
+ @stats.memory
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -73,8 +73,9 @@ module LogStash
73
73
  end
74
74
  end
75
75
 
76
- def self.app(logger, environment)
77
- namespaces = rack_namespaces
76
+ def self.app(logger, agent, environment)
77
+ namespaces = rack_namespaces(agent)
78
+
78
79
  Rack::Builder.new do
79
80
  # Custom logger object. Rack CommonLogger does not work with cabin
80
81
  use ApiLogger, logger
@@ -87,21 +88,23 @@ module LogStash
87
88
  use ApiErrorHandler, logger
88
89
  end
89
90
 
90
- run LogStash::Api::Modules::Root
91
+ run LogStash::Api::Modules::Root.new(nil, agent)
91
92
  namespaces.each_pair do |namespace, app|
92
93
  map(namespace) do
93
- run app
94
+ # Pass down a reference to the current agent
95
+ # This allow the API to have direct access to the collector
96
+ run app.new(nil, agent)
94
97
  end
95
98
  end
96
99
  end
97
100
  end
98
101
 
99
- def self.rack_namespaces
102
+ def self.rack_namespaces(agent)
100
103
  {
101
104
  "/_node" => LogStash::Api::Modules::Node,
102
105
  "/_stats" => LogStash::Api::Modules::Stats,
103
106
  "/_node/stats" => LogStash::Api::Modules::NodeStats,
104
- "/_plugins" => LogStash::Api::Modules::Plugins
107
+ "/_node/plugins" => LogStash::Api::Modules::Plugins
105
108
  }
106
109
  end
107
110
  end
@@ -5,68 +5,29 @@ require "logstash/util/loggable"
5
5
  module LogStash
6
6
  module Api
7
7
  class Service
8
-
9
- include Singleton
10
8
  include LogStash::Util::Loggable
11
9
 
12
- def initialize
13
- @snapshot_rotation_mutex = Mutex.new
14
- @snapshot = nil
15
- logger.debug("[api-service] start") if logger.debug?
16
- LogStash::Instrument::Collector.instance.add_observer(self)
17
- end
10
+ attr_reader :agent
18
11
 
19
- def stop
20
- logger.debug("[api-service] stop") if logger.debug?
21
- LogStash::Instrument::Collector.instance.delete_observer(self)
22
- end
23
-
24
- def agent
25
- LogStash::Instrument::Collector.instance.agent
12
+ def initialize(agent)
13
+ @agent = agent
14
+ logger.debug("[api-service] start") if logger.debug?
26
15
  end
27
16
 
28
17
  def started?
29
- !@snapshot.nil? && has_counters?
30
- end
31
-
32
- def update(snapshot)
33
- logger.debug("[api-service] snapshot received", :snapshot_time => snapshot.created_at) if logger.debug?
34
-
35
- @snapshot_rotation_mutex.synchronize do
36
- @snapshot = snapshot
37
- end
18
+ true
38
19
  end
39
20
 
40
21
  def snapshot
41
- @snapshot_rotation_mutex.synchronize { @snapshot }
22
+ agent.metric.collector.snapshot_metric
42
23
  end
43
24
 
44
25
  def get_shallow(*path)
45
26
  snapshot.metric_store.get_shallow(*path)
46
27
  end
47
28
 
48
- def get(key)
49
- metric_store = @snapshot_rotation_mutex.synchronize { @snapshot.metric_store }
50
- if key == :jvm_memory_stats
51
- data = metric_store.get_shallow(:jvm, :memory)
52
- else
53
- data = metric_store.get_with_path("stats/events")
54
- end
55
- LogStash::Json.dump(data)
56
- end
57
-
58
- private
59
-
60
- def has_counters?
61
- (["LogStash::Instrument::MetricType::Counter", "LogStash::Instrument::MetricType::Gauge"] - metric_types).empty?
62
- end
63
-
64
- def metric_types
65
- types = []
66
- @snapshot_rotation_mutex.synchronize do
67
- types = @snapshot.metric_store.all.map { |t| t.class.to_s }
68
- end
69
- return types
29
+ def extract_metrics(path, *keys)
30
+ snapshot.metric_store.extract_metrics(path, *keys)
70
31
  end
71
32
  end
72
33
  end
@@ -76,6 +76,14 @@ module LogStash; module Config; module AST
76
76
  @defered_conditionals_index = val
77
77
  end
78
78
 
79
+ def self.plugin_instance_index
80
+ @plugin_instance_index
81
+ end
82
+
83
+ def self.plugin_instance_index=(val)
84
+ @plugin_instance_index = val
85
+ end
86
+
79
87
  class Node < Treetop::Runtime::SyntaxNode
80
88
  def text_value_for_comments
81
89
  text_value.gsub(/[\r\n]/, " ")
@@ -86,6 +94,7 @@ module LogStash; module Config; module AST
86
94
  def compile
87
95
  LogStash::Config::AST.defered_conditionals = []
88
96
  LogStash::Config::AST.defered_conditionals_index = 0
97
+ LogStash::Config::AST.plugin_instance_index = 0
89
98
  code = []
90
99
 
91
100
  code << <<-CODE
@@ -140,7 +149,6 @@ module LogStash; module Config; module AST
140
149
  # like @filter_<name>_1
141
150
  def initialize(*args)
142
151
  super(*args)
143
- @i = 0
144
152
  end
145
153
 
146
154
  # Generate ruby code to initialize all the plugins.
@@ -196,9 +204,9 @@ module LogStash; module Config; module AST
196
204
 
197
205
  plugins.each do |plugin|
198
206
  # Unique number for every plugin.
199
- @i += 1
207
+ LogStash::Config::AST.plugin_instance_index += 1
200
208
  # store things as ivars, like @filter_grok_3
201
- var = :"#{plugin.plugin_type}_#{plugin.plugin_name}_#{@i}"
209
+ var = :"#{plugin.plugin_type}_#{plugin.plugin_name}_#{LogStash::Config::AST.plugin_instance_index}"
202
210
  # puts("var=#{var.inspect}")
203
211
  @variables[plugin] = var
204
212
  end
@@ -4,6 +4,7 @@ require "logstash/config/registry"
4
4
  require "logstash/plugins/registry"
5
5
  require "logstash/logging"
6
6
  require "logstash/util/password"
7
+ require "logstash/util/safe_uri"
7
8
  require "logstash/version"
8
9
  require "logstash/environment"
9
10
  require "logstash/util/plugin_version"
@@ -327,58 +328,88 @@ module LogStash::Config::Mixin
327
328
  return true
328
329
  end # def validate_check_invalid_parameter_names
329
330
 
331
+ def validate_check_required_parameter(config_key, config_opts, k, v)
332
+ if config_key.is_a?(Regexp)
333
+ (k =~ config_key && v)
334
+ elsif config_key.is_a?(String)
335
+ k && v
336
+ end
337
+ end
338
+
330
339
  def validate_check_required_parameter_names(params)
331
340
  is_valid = true
332
341
 
333
342
  @config.each do |config_key, config|
334
343
  next unless config[:required]
335
344
 
336
- if config_key.is_a?(Regexp)
337
- next if params.keys.select { |k| k =~ config_key }.length > 0
338
- elsif config_key.is_a?(String)
339
- next if params.keys.member?(config_key)
345
+ if config_key.is_a?(Regexp) && !params.keys.any? { |k| k =~ config_key }
346
+ is_valid = false
340
347
  end
341
- @logger.error(I18n.t("logstash.runner.configuration.setting_missing",
342
- :setting => config_key, :plugin => @plugin_name,
343
- :type => @plugin_type))
344
- is_valid = false
348
+
349
+ value = params[config_key]
350
+ if value.nil? || (config[:list] && Array(value).empty?)
351
+ @logger.error(I18n.t("logstash.runner.configuration.setting_missing",
352
+ :setting => config_key, :plugin => @plugin_name,
353
+ :type => @plugin_type))
354
+ is_valid = false
355
+ end
345
356
  end
346
357
 
347
358
  return is_valid
348
359
  end
349
360
 
361
+ def process_parameter_value(value, config_settings)
362
+ config_val = config_settings[:validate]
363
+
364
+ if config_settings[:list]
365
+ value = Array(value) # coerce scalars to lists
366
+ # Empty lists are converted to nils
367
+ return true, nil if value.empty?
368
+
369
+ validated_items = value.map {|v| validate_value(v, config_val)}
370
+ is_valid = validated_items.all? {|sr| sr[0] }
371
+ processed_value = validated_items.map {|sr| sr[1]}
372
+ else
373
+ is_valid, processed_value = validate_value(value, config_val)
374
+ end
375
+
376
+ return [is_valid, processed_value]
377
+ end
378
+
350
379
  def validate_check_parameter_values(params)
351
380
  # Filter out parametrs that match regexp keys.
352
381
  # These are defined in plugins like this:
353
382
  # config /foo.*/ => ...
354
- is_valid = true
383
+ all_params_valid = true
355
384
 
356
385
  params.each do |key, value|
357
386
  @config.keys.each do |config_key|
358
387
  next unless (config_key.is_a?(Regexp) && key =~ config_key) \
359
388
  || (config_key.is_a?(String) && key == config_key)
360
- config_val = @config[config_key][:validate]
361
- #puts " Key matches."
362
- success, result = validate_value(value, config_val)
363
- if success
364
- # Accept coerced value if success
389
+
390
+ config_settings = @config[config_key]
391
+
392
+ is_valid, processed_value = process_parameter_value(value, config_settings)
393
+
394
+ if is_valid
395
+ # Accept coerced value if valid
365
396
  # Used for converting values in the config to proper objects.
366
- params[key] = result if !result.nil?
397
+ params[key] = processed_value
367
398
  else
368
399
  @logger.error(I18n.t("logstash.runner.configuration.setting_invalid",
369
400
  :plugin => @plugin_name, :type => @plugin_type,
370
401
  :setting => key, :value => value.inspect,
371
- :value_type => config_val,
372
- :note => result))
402
+ :value_type => config_settings[:validate],
403
+ :note => processed_value))
373
404
  end
374
- #puts "Result: #{key} / #{result.inspect} / #{success}"
375
- is_valid &&= success
405
+
406
+ all_params_valid &&= is_valid
376
407
 
377
408
  break # done with this param key
378
409
  end # config.each
379
410
  end # params.each
380
411
 
381
- return is_valid
412
+ return all_params_valid
382
413
  end # def validate_check_parameter_values
383
414
 
384
415
  def validator_find(key)
@@ -513,6 +544,12 @@ module LogStash::Config::Mixin
513
544
  end
514
545
 
515
546
  result = value.first.is_a?(::LogStash::Util::Password) ? value.first : ::LogStash::Util::Password.new(value.first)
547
+ when :uri
548
+ if value.size > 1
549
+ return false, "Expected uri (one value), got #{value.size} values?"
550
+ end
551
+
552
+ result = value.first.is_a?(::LogStash::Util::SafeURI) ? value.first : ::LogStash::Util::SafeURI.new(value.first)
516
553
  when :path
517
554
  if value.size > 1 # Only 1 value wanted
518
555
  return false, "Expected path (one value), got #{value.size} values?"
@@ -548,8 +585,9 @@ module LogStash::Config::Mixin
548
585
 
549
586
  def secure_params!(params)
550
587
  params.each do |key, value|
551
- if @config[key][:validate] == :password && !value.is_a?(::LogStash::Util::Password)
552
- params[key] = ::LogStash::Util::Password.new(value)
588
+ if [:uri, :password].include? @config[key][:validate]
589
+ is_valid, processed_value = process_parameter_value(value, @config[key])
590
+ params[key] = processed_value
553
591
  end
554
592
  end
555
593
  end
@@ -21,7 +21,7 @@ module LogStash module Inputs
21
21
  @queue = queue
22
22
 
23
23
  # we register to the collector after receiving the pipeline queue
24
- LogStash::Instrument::Collector.instance.add_observer(self)
24
+ metric.collector.add_observer(self)
25
25
 
26
26
  # Keep this plugin thread alive,
27
27
  # until we shutdown the metric pipeline
@@ -30,7 +30,7 @@ module LogStash module Inputs
30
30
 
31
31
  def stop
32
32
  @logger.debug("Metrics input: stopped")
33
- LogStash::Instrument::Collector.instance.delete_observer(self)
33
+ metric.collector.delete_observer(self)
34
34
  end
35
35
 
36
36
  def update(snapshot)
@@ -8,7 +8,7 @@ require "singleton"
8
8
  require "thread"
9
9
 
10
10
  module LogStash module Instrument
11
- # The Collector singleton is the single point of reference for all
11
+ # The Collector is the single point of reference for all
12
12
  # the metrics collection inside logstash, the metrics library will make
13
13
  # direct calls to this class.
14
14
  #
@@ -17,7 +17,6 @@ module LogStash module Instrument
17
17
  class Collector
18
18
  include LogStash::Util::Loggable
19
19
  include Observable
20
- include Singleton
21
20
 
22
21
  SNAPSHOT_ROTATION_TIME_SECS = 1 # seconds
23
22
  SNAPSHOT_ROTATION_TIMEOUT_INTERVAL_SECS = 10 * 60 # seconds
@@ -59,10 +58,6 @@ module LogStash module Instrument
59
58
  end
60
59
  end
61
60
 
62
- def clear
63
- @metric_store = MetricStore.new
64
- end
65
-
66
61
  # Monitor the `Concurrent::TimerTask` this update is triggered on every successful or not
67
62
  # run of the task, TimerTask implement Observable and the collector acts as
68
63
  # the observer and will keep track if something went wrong in the execution.
@@ -96,6 +91,10 @@ module LogStash module Instrument
96
91
  @snapshot_task.execute
97
92
  end
98
93
 
94
+ def stop
95
+ @snapshot_task.shutdown
96
+ end
97
+
99
98
  # Create a snapshot of the MetricStore and send it to to the registered observers
100
99
  # The observer will receive the following signature in the update methode.
101
100
  #
@@ -13,7 +13,7 @@ module LogStash module Instrument
13
13
  class Metric
14
14
  attr_reader :collector
15
15
 
16
- def initialize(collector = LogStash::Instrument::Collector.instance)
16
+ def initialize(collector)
17
17
  @collector = collector
18
18
  end
19
19
 
@@ -110,6 +110,60 @@ module LogStash module Instrument
110
110
  key_paths.reduce(get(*key_paths)) {|acc, p| acc[p]}
111
111
  end
112
112
 
113
+
114
+ # Return a hash including the values of the keys given at the path given
115
+ #
116
+ # Example Usage:
117
+ # extract_metrics(
118
+ # [:jvm, :process],
119
+ # :open_file_descriptors,
120
+ # [:cpu, [:total_in_millis, :percent]]
121
+ # [:pipelines, [:one, :two], :size]
122
+ # )
123
+ #
124
+ # Returns:
125
+ # # From the jvm.process metrics namespace
126
+ # {
127
+ # :open_file_descriptors => 123
128
+ # :cpu => { :total_in_millis => 456, :percent => 789 }
129
+ # :pipelines => {
130
+ # :one => {:size => 90210},
131
+ # :two => {:size => 8675309}
132
+ # }
133
+ # }
134
+ def extract_metrics(path, *keys)
135
+ keys.reduce({}) do |acc,k|
136
+ # Simplifiy 1-length keys
137
+ k = k.first if k.is_a?(Array) && k.size == 1
138
+
139
+ # If we have array values here we need to recurse
140
+ # There are two levels of looping here, one for the paths we might pass in
141
+ # one for the upcoming keys we might pass in
142
+ if k.is_a?(Array)
143
+ # We need to build up future executions to extract_metrics
144
+ # which means building up the path and keys arguments.
145
+ # We need a nested loop her to execute all permutations of these in case we hit
146
+ # something like [[:a,:b],[:c,:d]] which produces 4 different metrics
147
+ next_paths = Array(k.first)
148
+ next_keys = Array(k[1])
149
+ rest = k[2..-1]
150
+ next_paths.each do |next_path|
151
+ # If there already is a hash at this location use that so we don't overwrite it
152
+ np_hash = acc[next_path] || {}
153
+
154
+ acc[next_path] = next_keys.reduce(np_hash) do |a,next_key|
155
+ a.merge! extract_metrics(path + [next_path], [next_key, *rest])
156
+ end
157
+ end
158
+ else # Scalar value
159
+ res = get_shallow(*path)[k]
160
+ acc[k] = res ? res.value : nil
161
+ end
162
+
163
+ acc
164
+ end
165
+ end
166
+
113
167
  # Return all the individuals Metric,
114
168
  # This call mimic a Enum's each if a block is provided
115
169
  #