logstash-core 5.0.0.alpha4.snapshot1-java → 5.0.0.alpha4.snapshot2-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 +4 -4
- data/lib/logstash-core/version.rb +1 -1
- data/lib/logstash/agent.rb +31 -36
- data/lib/logstash/api/command_factory.rb +3 -1
- data/lib/logstash/api/commands/base.rb +4 -0
- data/lib/logstash/api/commands/node.rb +116 -0
- data/lib/logstash/api/commands/stats.rb +28 -77
- data/lib/logstash/api/modules/base.rb +2 -2
- data/lib/logstash/api/modules/node.rb +23 -6
- data/lib/logstash/api/modules/node_stats.rb +15 -1
- data/lib/logstash/api/rack_app.rb +9 -6
- data/lib/logstash/api/service.rb +8 -47
- data/lib/logstash/config/config_ast.rb +11 -3
- data/lib/logstash/config/mixin.rb +60 -22
- data/lib/logstash/inputs/metrics.rb +2 -2
- data/lib/logstash/instrument/collector.rb +5 -6
- data/lib/logstash/instrument/metric.rb +1 -1
- data/lib/logstash/instrument/metric_store.rb +54 -0
- data/lib/logstash/pipeline.rb +10 -4
- data/lib/logstash/runner.rb +2 -2
- data/lib/logstash/util/safe_uri.rb +48 -0
- data/lib/logstash/version.rb +1 -1
- data/lib/logstash/webserver.rb +8 -7
- data/logstash-core.gemspec +1 -1
- data/spec/api/lib/api/node_plugins_spec.rb +32 -0
- data/spec/api/lib/api/node_spec.rb +41 -7
- data/spec/api/lib/api/node_stats_spec.rb +31 -6
- data/spec/api/lib/api/plugins_spec.rb +1 -7
- data/spec/api/lib/api/root_spec.rb +2 -7
- data/spec/api/lib/api/support/resource_dsl_methods.rb +14 -7
- data/spec/api/spec_helper.rb +24 -50
- data/spec/logstash/agent_spec.rb +36 -13
- data/spec/logstash/config/config_ast_spec.rb +43 -0
- data/spec/logstash/config/mixin_spec.rb +138 -0
- data/spec/logstash/inputs/metrics_spec.rb +10 -11
- data/spec/logstash/instrument/collector_spec.rb +1 -1
- data/spec/logstash/instrument/metric_store_spec.rb +61 -0
- data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +6 -3
- data/spec/logstash/pipeline_spec.rb +9 -9
- data/spec/support/mocks_classes.rb +2 -1
- 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
|
-
|
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
|
-
"/
|
107
|
+
"/_node/plugins" => LogStash::Api::Modules::Plugins
|
105
108
|
}
|
106
109
|
end
|
107
110
|
end
|
data/lib/logstash/api/service.rb
CHANGED
@@ -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
|
-
|
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
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
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
|
49
|
-
|
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
|
-
|
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}_#{
|
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
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
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
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
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] =
|
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 =>
|
372
|
-
:note =>
|
402
|
+
:value_type => config_settings[:validate],
|
403
|
+
:note => processed_value))
|
373
404
|
end
|
374
|
-
|
375
|
-
|
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
|
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]
|
552
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
#
|
@@ -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
|
#
|