logstash-core 2.2.4.snapshot1
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 +7 -0
- data/lib/logstash-core.rb +1 -0
- data/lib/logstash-core/logstash-core.rb +3 -0
- data/lib/logstash-core/version.rb +8 -0
- data/lib/logstash/agent.rb +391 -0
- data/lib/logstash/codecs/base.rb +50 -0
- data/lib/logstash/config/config_ast.rb +550 -0
- data/lib/logstash/config/cpu_core_strategy.rb +32 -0
- data/lib/logstash/config/defaults.rb +12 -0
- data/lib/logstash/config/file.rb +39 -0
- data/lib/logstash/config/grammar.rb +3503 -0
- data/lib/logstash/config/mixin.rb +518 -0
- data/lib/logstash/config/registry.rb +13 -0
- data/lib/logstash/environment.rb +98 -0
- data/lib/logstash/errors.rb +12 -0
- data/lib/logstash/filters/base.rb +205 -0
- data/lib/logstash/inputs/base.rb +116 -0
- data/lib/logstash/inputs/threadable.rb +18 -0
- data/lib/logstash/java_integration.rb +116 -0
- data/lib/logstash/json.rb +61 -0
- data/lib/logstash/logging.rb +91 -0
- data/lib/logstash/namespace.rb +13 -0
- data/lib/logstash/output_delegator.rb +172 -0
- data/lib/logstash/outputs/base.rb +91 -0
- data/lib/logstash/patches.rb +5 -0
- data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
- data/lib/logstash/patches/cabin.rb +35 -0
- data/lib/logstash/patches/profile_require_calls.rb +47 -0
- data/lib/logstash/patches/rubygems.rb +38 -0
- data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
- data/lib/logstash/pipeline.rb +499 -0
- data/lib/logstash/pipeline_reporter.rb +114 -0
- data/lib/logstash/plugin.rb +120 -0
- data/lib/logstash/program.rb +14 -0
- data/lib/logstash/runner.rb +124 -0
- data/lib/logstash/shutdown_watcher.rb +100 -0
- data/lib/logstash/util.rb +203 -0
- data/lib/logstash/util/buftok.rb +139 -0
- data/lib/logstash/util/charset.rb +35 -0
- data/lib/logstash/util/decorators.rb +52 -0
- data/lib/logstash/util/defaults_printer.rb +31 -0
- data/lib/logstash/util/filetools.rb +186 -0
- data/lib/logstash/util/java_version.rb +66 -0
- data/lib/logstash/util/password.rb +25 -0
- data/lib/logstash/util/plugin_version.rb +56 -0
- data/lib/logstash/util/prctl.rb +10 -0
- data/lib/logstash/util/retryable.rb +40 -0
- data/lib/logstash/util/socket_peer.rb +7 -0
- data/lib/logstash/util/unicode_trimmer.rb +81 -0
- data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
- data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
- data/lib/logstash/version.rb +14 -0
- data/locales/en.yml +204 -0
- data/logstash-core.gemspec +58 -0
- data/spec/conditionals_spec.rb +429 -0
- data/spec/logstash/agent_spec.rb +85 -0
- data/spec/logstash/config/config_ast_spec.rb +146 -0
- data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
- data/spec/logstash/config/defaults_spec.rb +10 -0
- data/spec/logstash/config/mixin_spec.rb +158 -0
- data/spec/logstash/environment_spec.rb +56 -0
- data/spec/logstash/filters/base_spec.rb +251 -0
- data/spec/logstash/inputs/base_spec.rb +74 -0
- data/spec/logstash/java_integration_spec.rb +304 -0
- data/spec/logstash/json_spec.rb +96 -0
- data/spec/logstash/output_delegator_spec.rb +144 -0
- data/spec/logstash/outputs/base_spec.rb +40 -0
- data/spec/logstash/patches_spec.rb +90 -0
- data/spec/logstash/pipeline_reporter_spec.rb +85 -0
- data/spec/logstash/pipeline_spec.rb +455 -0
- data/spec/logstash/plugin_spec.rb +169 -0
- data/spec/logstash/runner_spec.rb +68 -0
- data/spec/logstash/shutdown_watcher_spec.rb +113 -0
- data/spec/logstash/util/buftok_spec.rb +31 -0
- data/spec/logstash/util/charset_spec.rb +74 -0
- data/spec/logstash/util/defaults_printer_spec.rb +50 -0
- data/spec/logstash/util/java_version_spec.rb +79 -0
- data/spec/logstash/util/plugin_version_spec.rb +64 -0
- data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
- data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
- data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
- data/spec/logstash/util_spec.rb +35 -0
- metadata +364 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module LogStash; class PipelineReporter
|
5
|
+
attr_reader :logger, :pipeline
|
6
|
+
|
7
|
+
# This is an immutable copy of the pipeline state,
|
8
|
+
# It is a proxy to a hash to allow us to add methods dynamically to the hash
|
9
|
+
class Snapshot
|
10
|
+
def initialize(data)
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
@data
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_simple_hash
|
19
|
+
{"inflight_count" => inflight_count, "stalling_thread_info" => format_threads_by_plugin}
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_str
|
23
|
+
to_simple_hash.to_s
|
24
|
+
end
|
25
|
+
alias_method :to_s, :to_str
|
26
|
+
|
27
|
+
def method_missing(meth)
|
28
|
+
@data[meth]
|
29
|
+
end
|
30
|
+
|
31
|
+
def format_threads_by_plugin
|
32
|
+
stalled_plugins = {}
|
33
|
+
stalling_threads_info.each do |thr|
|
34
|
+
key = (thr.delete("plugin") || "other")
|
35
|
+
stalled_plugins[key] ||= []
|
36
|
+
stalled_plugins[key] << thr
|
37
|
+
end
|
38
|
+
stalled_plugins
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(logger,pipeline)
|
43
|
+
@logger = logger
|
44
|
+
@pipeline = pipeline
|
45
|
+
end
|
46
|
+
|
47
|
+
# The main way of accessing data from the reporter,,
|
48
|
+
# this provides a (more or less) consistent snapshot of what's going on in the
|
49
|
+
# pipeline with some extra decoration
|
50
|
+
def snapshot
|
51
|
+
Snapshot.new(self.to_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_hash
|
55
|
+
pipeline.inflight_batches_synchronize do |batch_map|
|
56
|
+
worker_states_snap = worker_states(batch_map) # We only want to run this once
|
57
|
+
inflight_count = worker_states_snap.map {|s| s[:inflight_count] }.reduce(0, :+)
|
58
|
+
|
59
|
+
{
|
60
|
+
:events_filtered => events_filtered,
|
61
|
+
:events_consumed => events_consumed,
|
62
|
+
:worker_count => pipeline.worker_threads.size,
|
63
|
+
:inflight_count => inflight_count,
|
64
|
+
:worker_states => worker_states_snap,
|
65
|
+
:output_info => output_info,
|
66
|
+
:thread_info => pipeline.plugin_threads_info,
|
67
|
+
:stalling_threads_info => pipeline.stalling_threads_info
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def events_filtered
|
75
|
+
pipeline.events_filtered.value
|
76
|
+
end
|
77
|
+
|
78
|
+
def events_consumed
|
79
|
+
pipeline.events_consumed.value
|
80
|
+
end
|
81
|
+
|
82
|
+
def plugin_threads
|
83
|
+
pipeline.plugin_threads
|
84
|
+
end
|
85
|
+
|
86
|
+
# Not threadsafe! must be called within an `inflight_batches_synchronize` block
|
87
|
+
def worker_states(batch_map)
|
88
|
+
pipeline.worker_threads.map.with_index do |thread,idx|
|
89
|
+
status = thread.status || "dead"
|
90
|
+
inflight_count = batch_map[thread] ? batch_map[thread].size : 0
|
91
|
+
{
|
92
|
+
:status => status,
|
93
|
+
:alive => thread.alive?,
|
94
|
+
:index => idx,
|
95
|
+
:inflight_count => inflight_count
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def output_info
|
101
|
+
pipeline.outputs.map do |output_delegator|
|
102
|
+
is_multi_worker = output_delegator.worker_count > 1
|
103
|
+
|
104
|
+
{
|
105
|
+
:type => output_delegator.config_name,
|
106
|
+
:config => output_delegator.config,
|
107
|
+
:is_multi_worker => is_multi_worker,
|
108
|
+
:events_received => output_delegator.events_received,
|
109
|
+
:workers => output_delegator.workers,
|
110
|
+
:busy_workers => output_delegator.busy_workers
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "logstash/logging"
|
4
|
+
require "logstash/config/mixin"
|
5
|
+
require "cabin"
|
6
|
+
require "concurrent"
|
7
|
+
|
8
|
+
class LogStash::Plugin
|
9
|
+
attr_accessor :params
|
10
|
+
attr_accessor :logger
|
11
|
+
|
12
|
+
NL = "\n"
|
13
|
+
|
14
|
+
public
|
15
|
+
def hash
|
16
|
+
params.hash ^
|
17
|
+
self.class.name.hash
|
18
|
+
end
|
19
|
+
|
20
|
+
public
|
21
|
+
def eql?(other)
|
22
|
+
self.class.name == other.class.name && @params == other.params
|
23
|
+
end
|
24
|
+
|
25
|
+
public
|
26
|
+
def initialize(params=nil)
|
27
|
+
@params = LogStash::Util.deep_clone(params)
|
28
|
+
@logger = Cabin::Channel.get(LogStash)
|
29
|
+
end
|
30
|
+
|
31
|
+
# close is called during shutdown, after the plugin worker
|
32
|
+
# main task terminates
|
33
|
+
public
|
34
|
+
def do_close
|
35
|
+
@logger.debug("closing", :plugin => self)
|
36
|
+
close
|
37
|
+
end
|
38
|
+
|
39
|
+
# Subclasses should implement this close method if you need to perform any
|
40
|
+
# special tasks during shutdown (like flushing, etc.)
|
41
|
+
public
|
42
|
+
def close
|
43
|
+
# ..
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
return "#{self.class.name}: #{@params}"
|
48
|
+
end
|
49
|
+
|
50
|
+
public
|
51
|
+
def inspect
|
52
|
+
if !@params.nil?
|
53
|
+
description = @params
|
54
|
+
.reject { |k, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }
|
55
|
+
.collect { |k, v| "#{k}=>#{v.inspect}" }
|
56
|
+
return "<#{self.class.name} #{description.join(", ")}>"
|
57
|
+
else
|
58
|
+
return "<#{self.class.name} --->"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
public
|
63
|
+
def debug_info
|
64
|
+
[self.class.to_s, original_params]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Look up a plugin by type and name.
|
68
|
+
public
|
69
|
+
def self.lookup(type, name)
|
70
|
+
path = "logstash/#{type}s/#{name}"
|
71
|
+
|
72
|
+
# first check if plugin already exists in namespace and continue to next step if not
|
73
|
+
begin
|
74
|
+
return namespace_lookup(type, name)
|
75
|
+
rescue NameError
|
76
|
+
logger.debug("Plugin not defined in namespace, checking for plugin file", :type => type, :name => name, :path => path)
|
77
|
+
end
|
78
|
+
|
79
|
+
# try to load the plugin file. ex.: lookup("filter", "grok") will require logstash/filters/grok
|
80
|
+
require(path)
|
81
|
+
|
82
|
+
# check again if plugin is now defined in namespace after the require
|
83
|
+
namespace_lookup(type, name)
|
84
|
+
rescue LoadError, NameError => e
|
85
|
+
raise(LogStash::PluginLoadingError, I18n.t("logstash.pipeline.plugin-loading-error", :type => type, :name => name, :path => path, :error => e.to_s))
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# lookup a plugin by type and name in the existing LogStash module namespace
|
91
|
+
# ex.: namespace_lookup("filter", "grok") looks for LogStash::Filters::Grok
|
92
|
+
# @param type [String] plugin type, "input", "ouput", "filter"
|
93
|
+
# @param name [String] plugin name, ex.: "grok"
|
94
|
+
# @return [Class] the plugin class or raises NameError
|
95
|
+
# @raise NameError if plugin class does not exist or is invalid
|
96
|
+
def self.namespace_lookup(type, name)
|
97
|
+
type_const = "#{type.capitalize}s"
|
98
|
+
namespace = LogStash.const_get(type_const)
|
99
|
+
# the namespace can contain constants which are not for plugins classes (do not respond to :config_name)
|
100
|
+
# namespace.constants is the shallow collection of all constants symbols in namespace
|
101
|
+
# note that below namespace.const_get(c) should never result in a NameError since c is from the constants collection
|
102
|
+
klass_sym = namespace.constants.find { |c| is_a_plugin?(namespace.const_get(c), name) }
|
103
|
+
klass = klass_sym && namespace.const_get(klass_sym)
|
104
|
+
raise(NameError) unless klass
|
105
|
+
klass
|
106
|
+
end
|
107
|
+
|
108
|
+
# check if klass is a valid plugin for name
|
109
|
+
# @param klass [Class] plugin class
|
110
|
+
# @param name [String] plugin name
|
111
|
+
# @return [Boolean] true if klass is a valid plugin for name
|
112
|
+
def self.is_a_plugin?(klass, name)
|
113
|
+
klass.ancestors.include?(LogStash::Plugin) && klass.respond_to?(:config_name) && klass.config_name == name
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [Cabin::Channel] logger channel for class methods
|
117
|
+
def self.logger
|
118
|
+
@logger ||= Cabin::Channel.get(LogStash)
|
119
|
+
end
|
120
|
+
end # class LogStash::Plugin
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
|
4
|
+
module LogStash::Program
|
5
|
+
public
|
6
|
+
def exit(value)
|
7
|
+
if RUBY_ENGINE == "jruby"
|
8
|
+
# Kernel::exit() in jruby just tosses an exception? Let's actually exit.
|
9
|
+
Java::java.lang.System.exit(value)
|
10
|
+
else
|
11
|
+
Kernel::exit(value)
|
12
|
+
end
|
13
|
+
end # def exit
|
14
|
+
end # module LogStash::Program
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
Thread.abort_on_exception = true
|
3
|
+
Encoding.default_external = Encoding::UTF_8
|
4
|
+
$DEBUGLIST = (ENV["DEBUG"] || "").split(",")
|
5
|
+
|
6
|
+
require "logstash/environment"
|
7
|
+
|
8
|
+
LogStash::Environment.load_locale!
|
9
|
+
|
10
|
+
require "logstash/namespace"
|
11
|
+
require "logstash/program"
|
12
|
+
|
13
|
+
class LogStash::Runner
|
14
|
+
include LogStash::Program
|
15
|
+
|
16
|
+
def main(args)
|
17
|
+
require "logstash/util"
|
18
|
+
require "logstash/util/java_version"
|
19
|
+
require "stud/trap"
|
20
|
+
require "stud/task"
|
21
|
+
@startup_interruption_trap = Stud::trap("INT") { puts "Interrupted"; exit 0 }
|
22
|
+
|
23
|
+
LogStash::Util::set_thread_name(self.class.name)
|
24
|
+
|
25
|
+
if RUBY_VERSION < "1.9.2"
|
26
|
+
$stderr.puts "Ruby 1.9.2 or later is required. (You are running: " + RUBY_VERSION + ")"
|
27
|
+
return 1
|
28
|
+
end
|
29
|
+
|
30
|
+
# Print a warning to STDERR for bad java versions
|
31
|
+
LogStash::Util::JavaVersion.warn_on_bad_java_version
|
32
|
+
|
33
|
+
Stud::untrap("INT", @startup_interruption_trap)
|
34
|
+
|
35
|
+
task = run(args)
|
36
|
+
exit(task.wait)
|
37
|
+
end # def self.main
|
38
|
+
|
39
|
+
def run(args)
|
40
|
+
command = args.shift
|
41
|
+
commands = {
|
42
|
+
"version" => lambda do
|
43
|
+
require "logstash/agent"
|
44
|
+
agent_args = ["--version"]
|
45
|
+
if args.include?("--verbose")
|
46
|
+
agent_args << "--verbose"
|
47
|
+
end
|
48
|
+
return LogStash::Agent.run($0, agent_args)
|
49
|
+
end,
|
50
|
+
"irb" => lambda do
|
51
|
+
require "irb"
|
52
|
+
return IRB.start(__FILE__)
|
53
|
+
end,
|
54
|
+
"pry" => lambda do
|
55
|
+
require "pry"
|
56
|
+
return binding.pry
|
57
|
+
end,
|
58
|
+
"docgen" => lambda do
|
59
|
+
require 'docs/asciidocgen'
|
60
|
+
opts = OptionParser.new
|
61
|
+
settings = {}
|
62
|
+
opts.on("-o DIR", "--output DIR",
|
63
|
+
"Directory to output to; optional. If not specified,"\
|
64
|
+
"we write to stdout.") do |val|
|
65
|
+
settings[:output] = val
|
66
|
+
end
|
67
|
+
args = opts.parse(ARGV)
|
68
|
+
docs = LogStashConfigAsciiDocGenerator.new
|
69
|
+
args.each do |arg|
|
70
|
+
docs.generate(arg, settings)
|
71
|
+
end
|
72
|
+
return 0
|
73
|
+
end,
|
74
|
+
"agent" => lambda do
|
75
|
+
require "logstash/agent"
|
76
|
+
# Hack up a runner
|
77
|
+
agent = LogStash::Agent.new("/bin/logstash agent", $0)
|
78
|
+
begin
|
79
|
+
agent.parse(args)
|
80
|
+
rescue Clamp::HelpWanted => e
|
81
|
+
show_help(e.command)
|
82
|
+
return 0
|
83
|
+
rescue Clamp::UsageError => e
|
84
|
+
# If 'too many arguments' then give the arguments to
|
85
|
+
# the next command. Otherwise it's a real error.
|
86
|
+
raise if e.message != "too many arguments"
|
87
|
+
remaining = agent.remaining_arguments
|
88
|
+
end
|
89
|
+
|
90
|
+
return agent.execute
|
91
|
+
end
|
92
|
+
} # commands
|
93
|
+
|
94
|
+
if commands.include?(command)
|
95
|
+
return Stud::Task.new { commands[command].call }
|
96
|
+
else
|
97
|
+
if command.nil?
|
98
|
+
$stderr.puts "No command given"
|
99
|
+
else
|
100
|
+
if !%w(--help -h help).include?(command)
|
101
|
+
# Emit 'no such command' if it's not someone asking for help.
|
102
|
+
$stderr.puts "No such command #{command.inspect}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
$stderr.puts %q[
|
106
|
+
Usage: logstash <command> [command args]
|
107
|
+
Run a command with the --help flag to see the arguments.
|
108
|
+
For example: logstash agent --help
|
109
|
+
|
110
|
+
Available commands:
|
111
|
+
agent - runs the logstash agent
|
112
|
+
version - emits version info about this logstash
|
113
|
+
]
|
114
|
+
#$stderr.puts commands.keys.map { |s| " #{s}" }.join("\n")
|
115
|
+
return Stud::Task.new { 1 }
|
116
|
+
end
|
117
|
+
end # def run
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def show_help(command)
|
122
|
+
puts command.help
|
123
|
+
end
|
124
|
+
end # class LogStash::Runner
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module LogStash
|
4
|
+
class ShutdownWatcher
|
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
|
+
watcher = self.new(pipeline, cycle_period, report_every, abort_threshold)
|
38
|
+
Thread.new(watcher) { |watcher| watcher.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 << pipeline_report_snapshot
|
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)
|
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
|
+
def pipeline_report_snapshot
|
73
|
+
@pipeline.reporter.snapshot
|
74
|
+
end
|
75
|
+
|
76
|
+
# A pipeline shutdown is stalled if
|
77
|
+
# * at least REPORT_EVERY reports have been created
|
78
|
+
# * the inflight event count is in monotonically increasing
|
79
|
+
# * there are worker threads running which aren't blocked on SizedQueue pop/push
|
80
|
+
# * the stalled thread list is constant in the previous REPORT_EVERY reports
|
81
|
+
def shutdown_stalled?
|
82
|
+
return false unless @reports.size == @report_every #
|
83
|
+
# is stalled if inflight count is either constant or increasing
|
84
|
+
stalled_event_count = @reports.each_cons(2).all? do |prev_report, next_report|
|
85
|
+
prev_report.inflight_count <= next_report.inflight_count
|
86
|
+
end
|
87
|
+
if stalled_event_count
|
88
|
+
@reports.each_cons(2).all? do |prev_report, next_report|
|
89
|
+
prev_report.stalling_threads == next_report.stalling_threads
|
90
|
+
end
|
91
|
+
else
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def force_exit
|
97
|
+
exit(-1)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|