logstash-core 2.1.3-java → 2.2.0-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.
- checksums.yaml +4 -4
- data/lib/logstash-core.rb +1 -3
- data/lib/logstash-core/logstash-core.rb +3 -0
- data/lib/logstash-core/version.rb +8 -0
- data/lib/logstash/agent.rb +48 -20
- data/lib/logstash/codecs/base.rb +2 -2
- data/lib/logstash/config/config_ast.rb +8 -3
- data/lib/logstash/environment.rb +0 -16
- data/lib/logstash/filters/base.rb +9 -5
- data/lib/logstash/inputs/base.rb +1 -1
- data/lib/logstash/output_delegator.rb +150 -0
- data/lib/logstash/outputs/base.rb +37 -40
- data/lib/logstash/pipeline.rb +259 -178
- data/lib/logstash/pipeline_reporter.rb +114 -0
- data/lib/logstash/plugin.rb +1 -1
- data/lib/logstash/{shutdown_controller.rb → shutdown_watcher.rb} +10 -37
- data/lib/logstash/util.rb +17 -0
- data/lib/logstash/util/decorators.rb +14 -7
- data/lib/logstash/util/worker_threads_default_printer.rb +4 -4
- data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
- data/lib/logstash/version.rb +10 -2
- data/locales/en.yml +8 -3
- data/logstash-core.gemspec +5 -3
- data/spec/{core/conditionals_spec.rb → conditionals_spec.rb} +0 -0
- data/spec/{core/config_spec.rb → logstash/config/config_ast_spec.rb} +0 -0
- data/spec/{core/config_cpu_core_strategy_spec.rb → logstash/config/cpu_core_strategy_spec.rb} +0 -0
- data/spec/{core/config_defaults_spec.rb → logstash/config/defaults_spec.rb} +0 -0
- data/spec/{core/config_mixin_spec.rb → logstash/config/mixin_spec.rb} +0 -0
- data/spec/{core → logstash}/environment_spec.rb +0 -0
- data/spec/{filters → logstash/filters}/base_spec.rb +0 -0
- data/spec/{inputs → logstash/inputs}/base_spec.rb +0 -0
- data/spec/{lib/logstash → logstash}/java_integration_spec.rb +0 -0
- data/spec/{util → logstash}/json_spec.rb +0 -0
- data/spec/logstash/output_delegator_spec.rb +126 -0
- data/spec/logstash/outputs/base_spec.rb +40 -0
- data/spec/logstash/pipeline_reporter_spec.rb +85 -0
- data/spec/{core → logstash}/pipeline_spec.rb +128 -16
- data/spec/{core → logstash}/plugin_spec.rb +47 -1
- data/spec/logstash/runner_spec.rb +68 -0
- data/spec/{core/shutdown_controller_spec.rb → logstash/shutdown_watcher_spec.rb} +17 -11
- data/spec/{util → logstash/util}/buftok_spec.rb +0 -0
- data/spec/{util → logstash/util}/charset_spec.rb +0 -0
- data/spec/{util → logstash/util}/defaults_printer_spec.rb +4 -4
- data/spec/{util → logstash/util}/java_version_spec.rb +0 -0
- data/spec/{util → logstash/util}/plugin_version_spec.rb +0 -0
- data/spec/{util → logstash/util}/unicode_trimmer_spec.rb +0 -0
- data/spec/{util → logstash/util}/worker_threads_default_printer_spec.rb +8 -8
- data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
- data/spec/{util_spec.rb → logstash/util_spec.rb} +0 -0
- metadata +74 -81
- data/lib/logstash/event.rb +0 -275
- data/lib/logstash/patches/bundler.rb +0 -36
- data/lib/logstash/sized_queue.rb +0 -8
- data/lib/logstash/string_interpolation.rb +0 -140
- data/lib/logstash/timestamp.rb +0 -97
- data/lib/logstash/util/accessors.rb +0 -123
- data/spec/core/event_spec.rb +0 -518
- data/spec/core/runner_spec.rb +0 -40
- data/spec/core/timestamp_spec.rb +0 -84
- data/spec/coverage_helper.rb +0 -24
- data/spec/lib/logstash/bundler_spec.rb +0 -121
- data/spec/license_spec.rb +0 -67
- data/spec/outputs/base_spec.rb +0 -26
- data/spec/plugin_manager/install_spec.rb +0 -28
- data/spec/plugin_manager/update_spec.rb +0 -39
- data/spec/plugin_manager/util_spec.rb +0 -71
- data/spec/spec_helper.rb +0 -11
- data/spec/util/accessors_spec.rb +0 -170
- data/spec/util/compress_spec.rb +0 -121
- data/spec/util/gemfile_spec.rb +0 -212
- data/spec/util/retryable_spec.rb +0 -139
@@ -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
|
data/lib/logstash/plugin.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module LogStash
|
4
|
-
class
|
4
|
+
class ShutdownWatcher
|
5
5
|
|
6
6
|
CHECK_EVERY = 1 # second
|
7
7
|
REPORT_EVERY = 5 # checks
|
@@ -34,8 +34,8 @@ module LogStash
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.start(pipeline, cycle_period=CHECK_EVERY, report_every=REPORT_EVERY, abort_threshold=ABORT_AFTER)
|
37
|
-
|
38
|
-
Thread.new(
|
37
|
+
watcher = self.new(pipeline, cycle_period, report_every, abort_threshold)
|
38
|
+
Thread.new(watcher) { |watcher| watcher.start }
|
39
39
|
end
|
40
40
|
|
41
41
|
def logger
|
@@ -47,10 +47,10 @@ module LogStash
|
|
47
47
|
cycle_number = 0
|
48
48
|
stalled_count = 0
|
49
49
|
Stud.interval(@cycle_period) do
|
50
|
-
@reports <<
|
50
|
+
@reports << pipeline_report_snapshot
|
51
51
|
@reports.delete_at(0) if @reports.size > @report_every # expire old report
|
52
52
|
if cycle_number == (@report_every - 1) # it's report time!
|
53
|
-
logger.warn(@reports.last
|
53
|
+
logger.warn(@reports.last)
|
54
54
|
|
55
55
|
if shutdown_stalled?
|
56
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
|
@@ -69,6 +69,10 @@ module LogStash
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
def pipeline_report_snapshot
|
73
|
+
@pipeline.reporter.snapshot
|
74
|
+
end
|
75
|
+
|
72
76
|
# A pipeline shutdown is stalled if
|
73
77
|
# * at least REPORT_EVERY reports have been created
|
74
78
|
# * the inflight event count is in monotonically increasing
|
@@ -78,7 +82,7 @@ module LogStash
|
|
78
82
|
return false unless @reports.size == @report_every #
|
79
83
|
# is stalled if inflight count is either constant or increasing
|
80
84
|
stalled_event_count = @reports.each_cons(2).all? do |prev_report, next_report|
|
81
|
-
prev_report.inflight_count
|
85
|
+
prev_report.inflight_count <= next_report.inflight_count
|
82
86
|
end
|
83
87
|
if stalled_event_count
|
84
88
|
@reports.each_cons(2).all? do |prev_report, next_report|
|
@@ -93,35 +97,4 @@ module LogStash
|
|
93
97
|
exit(-1)
|
94
98
|
end
|
95
99
|
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
100
|
end
|
data/lib/logstash/util.rb
CHANGED
@@ -183,4 +183,21 @@ module LogStash::Util
|
|
183
183
|
o
|
184
184
|
end
|
185
185
|
end
|
186
|
+
|
187
|
+
def self.deep_clone(o)
|
188
|
+
case o
|
189
|
+
when Hash
|
190
|
+
o.inject({}) {|h, (k,v)| h[k] = deep_clone(v); h }
|
191
|
+
when Array
|
192
|
+
o.map {|v| deep_clone(v) }
|
193
|
+
when Fixnum, Symbol, IO, TrueClass, FalseClass, NilClass
|
194
|
+
o
|
195
|
+
when LogStash::Codecs::Base
|
196
|
+
o.clone
|
197
|
+
when String
|
198
|
+
o.clone #need to keep internal state e.g. frozen
|
199
|
+
else
|
200
|
+
Marshal.load(Marshal.dump(o))
|
201
|
+
end
|
202
|
+
end
|
186
203
|
end # module LogStash::Util
|
@@ -19,13 +19,16 @@ module LogStash::Util
|
|
19
19
|
value.each do |v|
|
20
20
|
v = event.sprintf(v)
|
21
21
|
if event.include?(field)
|
22
|
-
|
23
|
-
event[field] << v
|
22
|
+
# note below that the array field needs to be updated then reassigned to the event.
|
23
|
+
# this is important because a construct like event[field] << v will not work
|
24
|
+
# in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
|
25
|
+
a = Array(event[field])
|
26
|
+
a << v
|
27
|
+
event[field] = a
|
24
28
|
else
|
25
29
|
event[field] = v
|
26
30
|
end
|
27
|
-
@logger.debug? and @logger.debug("#{pluginname}: adding value to field",
|
28
|
-
:field => field, :value => value)
|
31
|
+
@logger.debug? and @logger.debug("#{pluginname}: adding value to field", :field => field, :value => value)
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
@@ -34,9 +37,13 @@ module LogStash::Util
|
|
34
37
|
def add_tags(tags, event, pluginname)
|
35
38
|
tags.each do |tag|
|
36
39
|
tag = event.sprintf(tag)
|
37
|
-
@logger.debug? and @logger.debug("#{pluginname}: adding tag",
|
38
|
-
|
39
|
-
|
40
|
+
@logger.debug? and @logger.debug("#{pluginname}: adding tag", :tag => tag)
|
41
|
+
# note below that the tags array field needs to be updated then reassigned to the event.
|
42
|
+
# this is important because a construct like event["tags"] << tag will not work
|
43
|
+
# in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
|
44
|
+
tags = event["tags"] || []
|
45
|
+
tags << tag
|
46
|
+
event["tags"] = tags
|
40
47
|
end
|
41
48
|
end
|
42
49
|
|
@@ -6,8 +6,8 @@ require "logstash/util"
|
|
6
6
|
module LogStash module Util class WorkerThreadsDefaultPrinter
|
7
7
|
|
8
8
|
def initialize(settings)
|
9
|
-
@setting = settings.fetch(
|
10
|
-
@default = settings.fetch(
|
9
|
+
@setting = settings.fetch(:pipeline_workers, 0)
|
10
|
+
@default = settings.fetch(:default_pipeline_workers, 0)
|
11
11
|
end
|
12
12
|
|
13
13
|
def visit(collector)
|
@@ -17,12 +17,12 @@ module LogStash module Util class WorkerThreadsDefaultPrinter
|
|
17
17
|
|
18
18
|
def visit_setting(collector)
|
19
19
|
return if @setting == 0
|
20
|
-
collector.push("User set
|
20
|
+
collector.push("User set pipeline workers: #{@setting}")
|
21
21
|
end
|
22
22
|
|
23
23
|
def visit_default(collector)
|
24
24
|
return if @default == 0
|
25
|
-
collector.push "Default
|
25
|
+
collector.push "Default pipeline workers: #{@default}"
|
26
26
|
end
|
27
27
|
|
28
28
|
end end end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module LogStash; module Util
|
4
|
+
class WrappedSynchronousQueue
|
5
|
+
java_import java.util.concurrent.SynchronousQueue
|
6
|
+
java_import java.util.concurrent.TimeUnit
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
@queue = java.util.concurrent.SynchronousQueue.new()
|
10
|
+
end
|
11
|
+
|
12
|
+
# Push an object to the queue if the queue is full
|
13
|
+
# it will block until the object can be added to the queue.
|
14
|
+
#
|
15
|
+
# @param [Object] Object to add to the queue
|
16
|
+
def push(obj)
|
17
|
+
@queue.put(obj)
|
18
|
+
end
|
19
|
+
alias_method(:<<, :push)
|
20
|
+
|
21
|
+
# Offer an object to the queue, wait for the specified amout of time.
|
22
|
+
# If adding to the queue was successfull 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 successfull 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
|
+
# Block for X millis
|
37
|
+
def poll(millis)
|
38
|
+
@queue.poll(millis, TimeUnit::MILLISECONDS)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end end
|
data/lib/logstash/version.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
# The version of logstash.
|
3
|
-
LOGSTASH_VERSION = "2.1.3"
|
4
2
|
|
3
|
+
# The version of the logstash package (not the logstash-core gem version).
|
4
|
+
#
|
5
5
|
# Note to authors: this should not include dashes because 'gem' barfs if
|
6
6
|
# you include a dash in the version string.
|
7
|
+
|
8
|
+
# TODO: (colin) the logstash-core gem uses it's own version number in logstash-core/lib/logstash-core/version.rb
|
9
|
+
# there are some dependencies in logstash-core on the LOGSTASH_VERSION constant this is why
|
10
|
+
# the logstash version is currently defined here in logstash-core/lib/logstash/version.rb but
|
11
|
+
# eventually this file should be in the root logstash lib fir and dependencies in logstash-core should be
|
12
|
+
# fixed.
|
13
|
+
|
14
|
+
LOGSTASH_VERSION = "2.2.0"
|
data/locales/en.yml
CHANGED
@@ -37,7 +37,7 @@ en:
|
|
37
37
|
output-worker-unsupported-with-message: >-
|
38
38
|
%{plugin} output plugin: setting 'workers => %{worker_count}' is not
|
39
39
|
supported by this plugin. I will continue working as if you had not set
|
40
|
-
this setting.
|
40
|
+
this setting. Reason: %{message}
|
41
41
|
plugin:
|
42
42
|
deprecated_milestone: >-
|
43
43
|
%{plugin} plugin is using the 'milestone' method to declare the version
|
@@ -155,8 +155,13 @@ en:
|
|
155
155
|
the empty string for the '-e' flag.
|
156
156
|
configtest: |+
|
157
157
|
Check configuration for valid syntax and then exit.
|
158
|
-
|
159
|
-
Sets the number of
|
158
|
+
pipeline-workers: |+
|
159
|
+
Sets the number of pipeline workers to run.
|
160
|
+
pipeline-batch-size: |+
|
161
|
+
Size of batches the pipeline is to work in.
|
162
|
+
pipeline-batch-delay: |+
|
163
|
+
When creating pipeline batches, how long to wait while polling
|
164
|
+
for the next event.
|
160
165
|
log: |+
|
161
166
|
Write logstash internal logs to the given
|
162
167
|
file. Without this flag, logstash will emit
|
data/logstash-core.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'logstash/version'
|
4
|
+
require 'logstash-core/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.authors = ["Jordan Sissel", "Pete Fritchman", "Elasticsearch"]
|
@@ -11,11 +11,13 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
|
12
12
|
gem.license = "Apache License (2.0)"
|
13
13
|
|
14
|
-
gem.files = Dir.glob(["logstash-core.gemspec", "lib
|
14
|
+
gem.files = Dir.glob(["logstash-core.gemspec", "lib/**/*.rb", "spec/**/*.rb", "locales/*"])
|
15
15
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
16
|
gem.name = "logstash-core"
|
17
17
|
gem.require_paths = ["lib"]
|
18
|
-
gem.version =
|
18
|
+
gem.version = LOGSTASH_CORE_VERSION
|
19
|
+
|
20
|
+
gem.add_runtime_dependency "logstash-core-event", "~> 2.2.0"
|
19
21
|
|
20
22
|
gem.add_runtime_dependency "cabin", "~> 0.7.0" #(Apache 2.0 license)
|
21
23
|
gem.add_runtime_dependency "pry", "~> 0.10.1" #(Ruby license)
|
File without changes
|
File without changes
|
data/spec/{core/config_cpu_core_strategy_spec.rb → logstash/config/cpu_core_strategy_spec.rb}
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe LogStash::OutputDelegator do
|
5
|
+
let(:logger) { double("logger") }
|
6
|
+
let(:events) { 7.times.map { LogStash::Event.new }}
|
7
|
+
let(:default_worker_count) { 1 }
|
8
|
+
|
9
|
+
subject { described_class.new(logger, out_klass, default_worker_count) }
|
10
|
+
|
11
|
+
context "with a plain output plugin" do
|
12
|
+
let(:out_klass) { double("output klass") }
|
13
|
+
let(:out_inst) { double("output instance") }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(out_klass).to receive(:new).with(any_args).and_return(out_inst)
|
17
|
+
allow(out_klass).to receive(:threadsafe?).and_return(false)
|
18
|
+
allow(out_klass).to receive(:workers_not_supported?).and_return(false)
|
19
|
+
allow(out_inst).to receive(:register)
|
20
|
+
allow(out_inst).to receive(:multi_receive)
|
21
|
+
allow(logger).to receive(:debug).with(any_args)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should initialize cleanly" do
|
25
|
+
expect { subject }.not_to raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
context "after having received a batch of events" do
|
29
|
+
before do
|
30
|
+
subject.multi_receive(events)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should pass the events through" do
|
34
|
+
expect(out_inst).to have_received(:multi_receive).with(events)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should increment the number of events received" do
|
38
|
+
expect(subject.events_received).to eql(events.length)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should register all workers on register" do
|
43
|
+
expect(out_inst).to receive(:register)
|
44
|
+
subject.register
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should close all workers when closing" do
|
48
|
+
expect(out_inst).to receive(:do_close)
|
49
|
+
subject.do_close
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "concurrency and worker support" do
|
53
|
+
describe "non-threadsafe outputs that allow workers" do
|
54
|
+
let(:default_worker_count) { 3 }
|
55
|
+
|
56
|
+
before do
|
57
|
+
allow(out_klass).to receive(:threadsafe?).and_return(false)
|
58
|
+
allow(out_klass).to receive(:workers_not_supported?).and_return(false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should instantiate multiple workers" do
|
62
|
+
expect(subject.workers.length).to eql(default_worker_count)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should send received events to the worker" do
|
66
|
+
expect(out_inst).to receive(:multi_receive).with(events)
|
67
|
+
subject.multi_receive(events)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "threadsafe outputs" do
|
72
|
+
before do
|
73
|
+
allow(out_klass).to receive(:threadsafe?).and_return(true)
|
74
|
+
allow(out_klass).to receive(:workers_not_supported?).and_return(false)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return true when threadsafe? is invoked" do
|
78
|
+
expect(subject.threadsafe?).to eql(true)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should define a threadsafe_worker" do
|
82
|
+
expect(subject.send(:threadsafe_worker)).to eql(out_inst)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should utilize threadsafe_multi_receive" do
|
86
|
+
expect(subject.send(:threadsafe_worker)).to receive(:multi_receive).with(events)
|
87
|
+
subject.multi_receive(events)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not utilize the worker queue" do
|
91
|
+
expect(subject.send(:worker_queue)).not_to receive(:pop)
|
92
|
+
subject.multi_receive(events)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should send received events to the worker" do
|
96
|
+
expect(out_inst).to receive(:multi_receive).with(events)
|
97
|
+
subject.multi_receive(events)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# This may seem suspiciously similar to the class in outputs/base_spec
|
104
|
+
# but, in fact, we need a whole new class because using this even once
|
105
|
+
# will immutably modify the base class
|
106
|
+
class LogStash::Outputs::NOOPDelLegacyNoWorkers < ::LogStash::Outputs::Base
|
107
|
+
LEGACY_WORKERS_NOT_SUPPORTED_REASON = "legacy reason"
|
108
|
+
|
109
|
+
def register
|
110
|
+
workers_not_supported(LEGACY_WORKERS_NOT_SUPPORTED_REASON)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "legacy output workers_not_supported" do
|
115
|
+
let(:default_worker_count) { 2 }
|
116
|
+
let(:out_klass) { LogStash::Outputs::NOOPDelLegacyNoWorkers }
|
117
|
+
|
118
|
+
before do
|
119
|
+
allow(logger).to receive(:debug).with(any_args)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should only setup one worker" do
|
123
|
+
expect(subject.worker_count).to eql(1)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|