logstash-core 2.0.1.snapshot1-java → 2.1.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 +4 -4
- data/lib/logstash/agent.rb +21 -6
- data/lib/logstash/config/mixin.rb +0 -6
- data/lib/logstash/event.rb +1 -1
- data/lib/logstash/filters/base.rb +1 -2
- data/lib/logstash/inputs/base.rb +0 -5
- data/lib/logstash/outputs/base.rb +7 -5
- data/lib/logstash/pipeline.rb +85 -15
- data/lib/logstash/plugin.rb +5 -0
- data/lib/logstash/shutdown_controller.rb +127 -0
- data/lib/logstash/util.rb +35 -0
- data/lib/logstash/util/defaults_printer.rb +1 -1
- data/lib/logstash/util/worker_threads_default_printer.rb +14 -2
- data/lib/logstash/version.rb +1 -1
- data/locales/en.yml +5 -0
- data/logstash-core.gemspec +2 -1
- data/spec/core/event_spec.rb +19 -0
- data/spec/core/pipeline_spec.rb +113 -7
- data/spec/core/shutdown_controller_spec.rb +107 -0
- data/spec/license_spec.rb +1 -0
- data/spec/plugin_manager/install_spec.rb +28 -0
- data/spec/plugin_manager/update_spec.rb +39 -0
- data/spec/plugin_manager/util_spec.rb +71 -0
- data/spec/util/compress_spec.rb +121 -0
- data/spec/util/defaults_printer_spec.rb +3 -2
- data/spec/util/worker_threads_default_printer_spec.rb +30 -11
- metadata +76 -54
- data/lib/logstash/util/reporter.rb +0 -28
- data/spec/pluginmanager/util_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79705663d762e3aa65d23f6c98c0fb39923546ef
|
4
|
+
data.tar.gz: 66c3fc910d9d9290189c55843bdfbf7ed4d3ea65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 455434efcd9788628c5350cb6f593eaad237a10269b68627d32e084aaa284c9a76b41d305b71ec4e0ee4d34e09f51a8dcaa2e03985f2be8f8e03ac0bef7fc3b0
|
7
|
+
data.tar.gz: b64af5a363fcd0096d06f4163b82595735acb58a3a958b39c6258a8cb08eb415342be4206f7d6a5e7765ba8c7a1cee2339f4eae8543e6e851c2d0d92c77c27a6
|
data/lib/logstash/agent.rb
CHANGED
@@ -23,7 +23,7 @@ class LogStash::Agent < Clamp::Command
|
|
23
23
|
option ["-w", "--filterworkers"], "COUNT",
|
24
24
|
I18n.t("logstash.agent.flag.filterworkers"),
|
25
25
|
:attribute_name => :filter_workers,
|
26
|
-
:default =>
|
26
|
+
:default => 0, &:to_i
|
27
27
|
|
28
28
|
option ["-l", "--log"], "FILE",
|
29
29
|
I18n.t("logstash.agent.flag.log"),
|
@@ -50,6 +50,11 @@ class LogStash::Agent < Clamp::Command
|
|
50
50
|
I18n.t("logstash.agent.flag.configtest"),
|
51
51
|
:attribute_name => :config_test
|
52
52
|
|
53
|
+
option "--[no-]allow-unsafe-shutdown", :flag,
|
54
|
+
I18n.t("logstash.agent.flag.unsafe_shutdown"),
|
55
|
+
:attribute_name => :unsafe_shutdown,
|
56
|
+
:default => false
|
57
|
+
|
53
58
|
# Emit a warning message.
|
54
59
|
def warn(message)
|
55
60
|
# For now, all warnings are fatal.
|
@@ -75,6 +80,9 @@ class LogStash::Agent < Clamp::Command
|
|
75
80
|
require "logstash/plugin"
|
76
81
|
@logger = Cabin::Channel.get(LogStash)
|
77
82
|
|
83
|
+
LogStash::ShutdownController.unsafe_shutdown = unsafe_shutdown?
|
84
|
+
LogStash::ShutdownController.logger = @logger
|
85
|
+
|
78
86
|
if version?
|
79
87
|
show_version
|
80
88
|
return 0
|
@@ -143,7 +151,7 @@ class LogStash::Agent < Clamp::Command
|
|
143
151
|
configure_logging(log_file)
|
144
152
|
end
|
145
153
|
|
146
|
-
pipeline.configure("filter-workers", filter_workers)
|
154
|
+
pipeline.configure("filter-workers", filter_workers) if filter_workers > 0
|
147
155
|
|
148
156
|
# Stop now if we are only asking for a config test.
|
149
157
|
if config_test?
|
@@ -176,8 +184,7 @@ class LogStash::Agent < Clamp::Command
|
|
176
184
|
|
177
185
|
def shutdown(pipeline)
|
178
186
|
pipeline.shutdown do
|
179
|
-
|
180
|
-
InflightEventsReporter.start(pipeline.input_to_filter, pipeline.filter_to_output, pipeline.outputs)
|
187
|
+
::LogStash::ShutdownController.start(pipeline)
|
181
188
|
end
|
182
189
|
end
|
183
190
|
|
@@ -312,19 +319,27 @@ class LogStash::Agent < Clamp::Command
|
|
312
319
|
Dir.glob(path).sort.each do |file|
|
313
320
|
next unless File.file?(file)
|
314
321
|
if file.match(/~$/)
|
315
|
-
@logger.debug("NOT reading config file because it is a temp file", :
|
322
|
+
@logger.debug("NOT reading config file because it is a temp file", :config_file => file)
|
316
323
|
next
|
317
324
|
end
|
318
|
-
@logger.debug("Reading config file", :
|
325
|
+
@logger.debug("Reading config file", :config_file => file)
|
319
326
|
cfg = File.read(file)
|
320
327
|
if !cfg.ascii_only? && !cfg.valid_encoding?
|
321
328
|
encoding_issue_files << file
|
322
329
|
end
|
323
330
|
config << cfg + "\n"
|
331
|
+
if config_test?
|
332
|
+
@logger.debug? && @logger.debug("\nThe following is the content of a file", :config_file => file.to_s)
|
333
|
+
@logger.debug? && @logger.debug("\n" + cfg + "\n\n")
|
334
|
+
end
|
324
335
|
end
|
325
336
|
if (encoding_issue_files.any?)
|
326
337
|
fail("The following config files contains non-ascii characters but are not UTF-8 encoded #{encoding_issue_files}")
|
327
338
|
end
|
339
|
+
if config_test?
|
340
|
+
@logger.debug? && @logger.debug("\nThe following is the merged configuration")
|
341
|
+
@logger.debug? && @logger.debug("\n" + config + "\n\n")
|
342
|
+
end
|
328
343
|
return config
|
329
344
|
end # def load_config
|
330
345
|
|
@@ -35,12 +35,6 @@ module LogStash::Config::Mixin
|
|
35
35
|
attr_accessor :config
|
36
36
|
attr_accessor :original_params
|
37
37
|
|
38
|
-
CONFIGSORT = {
|
39
|
-
Symbol => 0,
|
40
|
-
String => 0,
|
41
|
-
Regexp => 100,
|
42
|
-
}
|
43
|
-
|
44
38
|
PLUGIN_VERSION_1_0_0 = LogStash::Util::PluginVersion.new(1, 0, 0)
|
45
39
|
PLUGIN_VERSION_0_9_0 = LogStash::Util::PluginVersion.new(0, 9, 0)
|
46
40
|
|
data/lib/logstash/event.rb
CHANGED
@@ -117,8 +117,6 @@ class LogStash::Filters::Base < LogStash::Plugin
|
|
117
117
|
# Optional.
|
118
118
|
config :periodic_flush, :validate => :boolean, :default => false
|
119
119
|
|
120
|
-
RESERVED = ["type", "tags", "exclude_tags", "include_fields", "exclude_fields", "add_tag", "remove_tag", "add_field", "remove_field", "include_any", "exclude_any"]
|
121
|
-
|
122
120
|
public
|
123
121
|
def initialize(params)
|
124
122
|
super
|
@@ -145,6 +143,7 @@ class LogStash::Filters::Base < LogStash::Plugin
|
|
145
143
|
# @return [Array<LogStash::Event] filtered events and any new events generated by the filter
|
146
144
|
public
|
147
145
|
def multi_filter(events)
|
146
|
+
LogStash::Util.set_thread_plugin(self)
|
148
147
|
result = []
|
149
148
|
events.each do |event|
|
150
149
|
unless event.cancelled?
|
data/lib/logstash/inputs/base.rb
CHANGED
@@ -89,11 +89,6 @@ class LogStash::Inputs::Base < LogStash::Plugin
|
|
89
89
|
@stop_called.value
|
90
90
|
end
|
91
91
|
|
92
|
-
protected
|
93
|
-
def to_event(raw, source)
|
94
|
-
raise LogStash::ThisMethodWasRemoved("LogStash::Inputs::Base#to_event - you should use codecs now instead of to_event. Not sure what this means? Get help on https://discuss.elastic.co/c/logstash")
|
95
|
-
end # def to_event
|
96
|
-
|
97
92
|
protected
|
98
93
|
def decorate(event)
|
99
94
|
# Only set 'type' if not already set. This is backwards-compatible behavior
|
@@ -1,11 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "cgi"
|
3
2
|
require "logstash/event"
|
4
3
|
require "logstash/logging"
|
5
4
|
require "logstash/plugin"
|
6
5
|
require "logstash/namespace"
|
7
6
|
require "logstash/config/mixin"
|
8
|
-
require "uri"
|
9
7
|
|
10
8
|
class LogStash::Outputs::Base < LogStash::Plugin
|
11
9
|
include LogStash::Config::Mixin
|
@@ -25,7 +23,7 @@ class LogStash::Outputs::Base < LogStash::Plugin
|
|
25
23
|
# Note that this setting may not be useful for all outputs.
|
26
24
|
config :workers, :validate => :number, :default => 1
|
27
25
|
|
28
|
-
attr_reader :worker_plugins, :worker_queue
|
26
|
+
attr_reader :worker_plugins, :worker_queue, :worker_threads
|
29
27
|
|
30
28
|
public
|
31
29
|
def workers_not_supported(message=nil)
|
@@ -58,13 +56,15 @@ class LogStash::Outputs::Base < LogStash::Plugin
|
|
58
56
|
def worker_setup
|
59
57
|
if @workers == 1
|
60
58
|
@worker_plugins = [self]
|
59
|
+
@worker_threads = []
|
61
60
|
else
|
62
61
|
define_singleton_method(:handle, method(:handle_worker))
|
63
62
|
@worker_queue = SizedQueue.new(20)
|
64
63
|
@worker_plugins = @workers.times.map { self.class.new(@original_params.merge("workers" => 1)) }
|
65
|
-
@worker_plugins.map.with_index do |plugin, i|
|
64
|
+
@worker_threads = @worker_plugins.map.with_index do |plugin, i|
|
66
65
|
Thread.new(original_params, @worker_queue) do |params, queue|
|
67
|
-
LogStash::Util
|
66
|
+
LogStash::Util.set_thread_name(">#{self.class.config_name}.#{i}")
|
67
|
+
LogStash::Util.set_thread_plugin(self)
|
68
68
|
plugin.register
|
69
69
|
while true
|
70
70
|
event = queue.pop
|
@@ -77,10 +77,12 @@ class LogStash::Outputs::Base < LogStash::Plugin
|
|
77
77
|
|
78
78
|
public
|
79
79
|
def handle(event)
|
80
|
+
LogStash::Util.set_thread_plugin(self)
|
80
81
|
receive(event)
|
81
82
|
end # def handle
|
82
83
|
|
83
84
|
def handle_worker(event)
|
85
|
+
LogStash::Util.set_thread_plugin(self)
|
84
86
|
@worker_queue.push(event)
|
85
87
|
end
|
86
88
|
|
data/lib/logstash/pipeline.rb
CHANGED
@@ -9,11 +9,11 @@ require "logstash/config/file"
|
|
9
9
|
require "logstash/filters/base"
|
10
10
|
require "logstash/inputs/base"
|
11
11
|
require "logstash/outputs/base"
|
12
|
-
require "logstash/util/reporter"
|
13
12
|
require "logstash/config/cpu_core_strategy"
|
14
13
|
require "logstash/util/defaults_printer"
|
14
|
+
require "logstash/shutdown_controller"
|
15
15
|
|
16
|
-
class
|
16
|
+
module LogStash; class Pipeline
|
17
17
|
attr_reader :inputs, :filters, :outputs, :input_to_filter, :filter_to_output
|
18
18
|
|
19
19
|
def initialize(configstr)
|
@@ -25,6 +25,7 @@ class LogStash::Pipeline
|
|
25
25
|
|
26
26
|
grammar = LogStashConfigParser.new
|
27
27
|
@config = grammar.parse(configstr)
|
28
|
+
|
28
29
|
if @config.nil?
|
29
30
|
raise LogStash::ConfigurationError, grammar.failure_reason
|
30
31
|
end
|
@@ -46,7 +47,7 @@ class LogStash::Pipeline
|
|
46
47
|
@filter_to_output = filters? ? SizedQueue.new(20) : @input_to_filter
|
47
48
|
|
48
49
|
@settings = {
|
49
|
-
"filter-workers" => LogStash::Config::CpuCoreStrategy.fifty_percent
|
50
|
+
"default-filter-workers" => LogStash::Config::CpuCoreStrategy.fifty_percent
|
50
51
|
}
|
51
52
|
|
52
53
|
# @ready requires thread safety since it is typically polled from outside the pipeline thread
|
@@ -59,14 +60,32 @@ class LogStash::Pipeline
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def configure(setting, value)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
@settings[setting] = value
|
64
|
+
end
|
65
|
+
|
66
|
+
def safe_filter_worker_count
|
67
|
+
default = @settings["default-filter-workers"]
|
68
|
+
thread_count = @settings["filter-workers"] #override from args "-w 8" or config
|
69
|
+
safe_filters, unsafe_filters = @filters.partition(&:threadsafe?)
|
70
|
+
if unsafe_filters.any?
|
71
|
+
plugins = unsafe_filters.collect { |f| f.class.config_name }
|
72
|
+
case thread_count
|
73
|
+
when nil
|
74
|
+
# user did not specify a worker thread count
|
75
|
+
# warn if the default is multiple
|
76
|
+
@logger.warn("Defaulting filter worker threads to 1 because there are some filters that might not work with multiple worker threads",
|
77
|
+
:count_was => default, :filters => plugins) if default > 1
|
78
|
+
1 # can't allow the default value to propagate if there are unsafe filters
|
79
|
+
when 0, 1
|
80
|
+
1
|
81
|
+
else
|
82
|
+
@logger.warn("Warning: Manual override - there are filters that might not work with multiple worker threads",
|
83
|
+
:worker_threads => thread_count, :filters => plugins)
|
84
|
+
thread_count # allow user to force this even if there are unsafe filters
|
67
85
|
end
|
86
|
+
else
|
87
|
+
thread_count || default
|
68
88
|
end
|
69
|
-
@settings[setting] = value
|
70
89
|
end
|
71
90
|
|
72
91
|
def filters?
|
@@ -149,9 +168,14 @@ class LogStash::Pipeline
|
|
149
168
|
|
150
169
|
def start_filters
|
151
170
|
@filters.each(&:register)
|
152
|
-
|
153
|
-
|
154
|
-
|
171
|
+
# dynamically get thread count based on filter threadsafety
|
172
|
+
# moved this test to here to allow for future config reloading
|
173
|
+
to_start = safe_filter_worker_count
|
174
|
+
@filter_threads = to_start.times.collect do |i|
|
175
|
+
Thread.new do
|
176
|
+
LogStash::Util.set_thread_name("|filterworker.#{i}")
|
177
|
+
filterworker
|
178
|
+
end
|
155
179
|
end
|
156
180
|
actually_started = @filter_threads.select(&:alive?).size
|
157
181
|
msg = "Worker threads expected: #{to_start}, worker threads started: #{actually_started}"
|
@@ -175,7 +199,8 @@ class LogStash::Pipeline
|
|
175
199
|
end
|
176
200
|
|
177
201
|
def inputworker(plugin)
|
178
|
-
LogStash::Util
|
202
|
+
LogStash::Util.set_thread_name("<#{plugin.class.config_name}")
|
203
|
+
LogStash::Util.set_thread_plugin(plugin)
|
179
204
|
begin
|
180
205
|
plugin.run(@input_to_filter)
|
181
206
|
rescue => e
|
@@ -208,7 +233,6 @@ class LogStash::Pipeline
|
|
208
233
|
end # def inputworker
|
209
234
|
|
210
235
|
def filterworker
|
211
|
-
LogStash::Util.set_thread_name("|worker")
|
212
236
|
begin
|
213
237
|
while true
|
214
238
|
event = @input_to_filter.pop
|
@@ -250,6 +274,7 @@ class LogStash::Pipeline
|
|
250
274
|
event = @filter_to_output.pop
|
251
275
|
break if event == LogStash::SHUTDOWN
|
252
276
|
output_func(event)
|
277
|
+
LogStash::Util.set_thread_plugin(nil)
|
253
278
|
end
|
254
279
|
ensure
|
255
280
|
@outputs.each do |output|
|
@@ -309,4 +334,49 @@ class LogStash::Pipeline
|
|
309
334
|
end
|
310
335
|
end # flush_filters_to_output!
|
311
336
|
|
312
|
-
|
337
|
+
def inflight_count
|
338
|
+
data = {}
|
339
|
+
total = 0
|
340
|
+
|
341
|
+
input_to_filter = @input_to_filter.size
|
342
|
+
total += input_to_filter
|
343
|
+
filter_to_output = @filter_to_output.size
|
344
|
+
total += filter_to_output
|
345
|
+
|
346
|
+
data["input_to_filter"] = input_to_filter if input_to_filter > 0
|
347
|
+
data["filter_to_output"] = filter_to_output if filter_to_output > 0
|
348
|
+
|
349
|
+
output_worker_queues = []
|
350
|
+
@outputs.each do |output|
|
351
|
+
next unless output.worker_queue && output.worker_queue.size > 0
|
352
|
+
plugin_info = output.debug_info
|
353
|
+
size = output.worker_queue.size
|
354
|
+
total += size
|
355
|
+
plugin_info << size
|
356
|
+
output_worker_queues << plugin_info
|
357
|
+
end
|
358
|
+
data["output_worker_queues"] = output_worker_queues unless output_worker_queues.empty?
|
359
|
+
data["total"] = total
|
360
|
+
data
|
361
|
+
end
|
362
|
+
|
363
|
+
def stalling_threads
|
364
|
+
plugin_threads
|
365
|
+
.reject {|t| t["blocked_on"] } # known begnin blocking statuses
|
366
|
+
.each {|t| t.delete("backtrace") }
|
367
|
+
.each {|t| t.delete("blocked_on") }
|
368
|
+
.each {|t| t.delete("status") }
|
369
|
+
end
|
370
|
+
|
371
|
+
def plugin_threads
|
372
|
+
input_threads = @input_threads.select {|t| t.alive? }.map {|t| thread_info(t) }
|
373
|
+
filter_threads = @filter_threads.select {|t| t.alive? }.map {|t| thread_info(t) }
|
374
|
+
output_threads = @output_threads.select {|t| t.alive? }.map {|t| thread_info(t) }
|
375
|
+
output_worker_threads = @outputs.flat_map {|output| output.worker_threads }.map {|t| thread_info(t) }
|
376
|
+
input_threads + filter_threads + output_threads + output_worker_threads
|
377
|
+
end
|
378
|
+
|
379
|
+
def thread_info(thread)
|
380
|
+
LogStash::Util.thread_info(thread)
|
381
|
+
end
|
382
|
+
end; end
|
data/lib/logstash/plugin.rb
CHANGED
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module LogStash
|
4
|
+
class ShutdownController
|
5
|
+
|
6
|
+
CHECK_EVERY = 1 # second
|
7
|
+
REPORT_EVERY = 5 # checks
|
8
|
+
ABORT_AFTER = 3 # stalled reports
|
9
|
+
|
10
|
+
attr_reader :cycle_period, :report_every, :abort_threshold
|
11
|
+
|
12
|
+
def initialize(pipeline, cycle_period=CHECK_EVERY, report_every=REPORT_EVERY, abort_threshold=ABORT_AFTER)
|
13
|
+
@pipeline = pipeline
|
14
|
+
@cycle_period = cycle_period
|
15
|
+
@report_every = report_every
|
16
|
+
@abort_threshold = abort_threshold
|
17
|
+
@reports = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unsafe_shutdown=(boolean)
|
21
|
+
@unsafe_shutdown = boolean
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.unsafe_shutdown?
|
25
|
+
@unsafe_shutdown
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.logger=(logger)
|
29
|
+
@logger = logger
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.logger
|
33
|
+
@logger ||= Cabin::Channel.get(LogStash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.start(pipeline, cycle_period=CHECK_EVERY, report_every=REPORT_EVERY, abort_threshold=ABORT_AFTER)
|
37
|
+
controller = self.new(pipeline, cycle_period, report_every, abort_threshold)
|
38
|
+
Thread.new(controller) { |controller| controller.start }
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
self.class.logger
|
43
|
+
end
|
44
|
+
|
45
|
+
def start
|
46
|
+
sleep(@cycle_period)
|
47
|
+
cycle_number = 0
|
48
|
+
stalled_count = 0
|
49
|
+
Stud.interval(@cycle_period) do
|
50
|
+
@reports << Report.from_pipeline(@pipeline)
|
51
|
+
@reports.delete_at(0) if @reports.size > @report_every # expire old report
|
52
|
+
if cycle_number == (@report_every - 1) # it's report time!
|
53
|
+
logger.warn(@reports.last.to_hash)
|
54
|
+
|
55
|
+
if shutdown_stalled?
|
56
|
+
logger.error("The shutdown process appears to be stalled due to busy or blocked plugins. Check the logs for more information.") if stalled_count == 0
|
57
|
+
stalled_count += 1
|
58
|
+
|
59
|
+
if self.class.unsafe_shutdown? && @abort_threshold == stalled_count
|
60
|
+
logger.fatal("Forcefully quitting logstash..")
|
61
|
+
force_exit()
|
62
|
+
break
|
63
|
+
end
|
64
|
+
else
|
65
|
+
stalled_count = 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
cycle_number = (cycle_number + 1) % @report_every
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# A pipeline shutdown is stalled if
|
73
|
+
# * at least REPORT_EVERY reports have been created
|
74
|
+
# * the inflight event count is in monotonically increasing
|
75
|
+
# * there are worker threads running which aren't blocked on SizedQueue pop/push
|
76
|
+
# * the stalled thread list is constant in the previous REPORT_EVERY reports
|
77
|
+
def shutdown_stalled?
|
78
|
+
return false unless @reports.size == @report_every #
|
79
|
+
# is stalled if inflight count is either constant or increasing
|
80
|
+
stalled_event_count = @reports.each_cons(2).all? do |prev_report, next_report|
|
81
|
+
prev_report.inflight_count["total"] <= next_report.inflight_count["total"]
|
82
|
+
end
|
83
|
+
if stalled_event_count
|
84
|
+
@reports.each_cons(2).all? do |prev_report, next_report|
|
85
|
+
prev_report.stalling_threads == next_report.stalling_threads
|
86
|
+
end
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def force_exit
|
93
|
+
exit(-1)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Report
|
98
|
+
|
99
|
+
attr_reader :inflight_count, :stalling_threads
|
100
|
+
|
101
|
+
def self.from_pipeline(pipeline)
|
102
|
+
new(pipeline.inflight_count, pipeline.stalling_threads)
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize(inflight_count, stalling_threads)
|
106
|
+
@inflight_count = inflight_count
|
107
|
+
@stalling_threads = format_threads_by_plugin(stalling_threads)
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_hash
|
111
|
+
{
|
112
|
+
"INFLIGHT_EVENT_COUNT" => @inflight_count,
|
113
|
+
"STALLING_THREADS" => @stalling_threads
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def format_threads_by_plugin(stalling_threads)
|
118
|
+
stalled_plugins = {}
|
119
|
+
stalling_threads.each do |thr|
|
120
|
+
key = (thr.delete("plugin") || "other")
|
121
|
+
stalled_plugins[key] ||= []
|
122
|
+
stalled_plugins[key] << thr
|
123
|
+
end
|
124
|
+
stalled_plugins
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|