logstash-core 5.0.0.alpha5.snapshot1-java → 5.0.0.alpha6.snapshot1-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.

Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core/version.rb +1 -1
  3. data/lib/logstash/agent.rb +1 -1
  4. data/lib/logstash/api/commands/default_metadata.rb +1 -1
  5. data/lib/logstash/api/commands/hot_threads_reporter.rb +4 -7
  6. data/lib/logstash/api/commands/node.rb +5 -4
  7. data/lib/logstash/api/commands/stats.rb +8 -3
  8. data/lib/logstash/api/modules/base.rb +5 -0
  9. data/lib/logstash/api/modules/node.rb +1 -2
  10. data/lib/logstash/api/modules/node_stats.rb +1 -2
  11. data/lib/logstash/codecs/base.rb +29 -1
  12. data/lib/logstash/config/mixin.rb +1 -1
  13. data/lib/logstash/environment.rb +5 -5
  14. data/lib/logstash/filter_delegator.rb +4 -5
  15. data/lib/logstash/instrument/periodic_poller/jvm.rb +43 -10
  16. data/lib/logstash/output_delegator.rb +33 -168
  17. data/lib/logstash/output_delegator_strategies/legacy.rb +29 -0
  18. data/lib/logstash/output_delegator_strategies/shared.rb +20 -0
  19. data/lib/logstash/output_delegator_strategies/single.rb +23 -0
  20. data/lib/logstash/output_delegator_strategy_registry.rb +36 -0
  21. data/lib/logstash/outputs/base.rb +39 -26
  22. data/lib/logstash/patches/clamp.rb +6 -0
  23. data/lib/logstash/pipeline.rb +42 -14
  24. data/lib/logstash/pipeline_reporter.rb +2 -8
  25. data/lib/logstash/plugin.rb +6 -10
  26. data/lib/logstash/runner.rb +12 -9
  27. data/lib/logstash/settings.rb +124 -21
  28. data/lib/logstash/util/wrapped_synchronous_queue.rb +17 -1
  29. data/lib/logstash/version.rb +1 -1
  30. data/lib/logstash/webserver.rb +44 -33
  31. data/locales/en.yml +5 -1
  32. data/logstash-core.gemspec +2 -2
  33. data/spec/api/lib/api/node_spec.rb +62 -10
  34. data/spec/api/lib/api/node_stats_spec.rb +16 -3
  35. data/spec/api/lib/api/support/resource_dsl_methods.rb +11 -1
  36. data/spec/api/spec_helper.rb +1 -1
  37. data/spec/conditionals_spec.rb +12 -1
  38. data/spec/logstash/agent_spec.rb +3 -0
  39. data/spec/logstash/codecs/base_spec.rb +74 -0
  40. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +37 -10
  41. data/spec/logstash/output_delegator_spec.rb +64 -89
  42. data/spec/logstash/outputs/base_spec.rb +91 -15
  43. data/spec/logstash/pipeline_reporter_spec.rb +1 -6
  44. data/spec/logstash/pipeline_spec.rb +20 -22
  45. data/spec/logstash/plugin_spec.rb +3 -3
  46. data/spec/logstash/runner_spec.rb +86 -3
  47. data/spec/logstash/settings/integer_spec.rb +20 -0
  48. data/spec/logstash/settings/numeric_spec.rb +28 -0
  49. data/spec/logstash/settings/port_range_spec.rb +93 -0
  50. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +6 -0
  51. data/spec/logstash/webserver_spec.rb +95 -0
  52. metadata +20 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31b35e84fcbac8fa8ccb7ac01aac834645c04084
4
- data.tar.gz: 3c5d884562c45235f897279458b3e0ee8a840d4b
3
+ metadata.gz: e89e8c25486877ae001285428c6e6d9fbe3dfc6b
4
+ data.tar.gz: 5e6318f6ae9f263864588fa2361f5e9ebdc94fb4
5
5
  SHA512:
6
- metadata.gz: 2355f8393a9f37222e45f7698fdb2b3cf10be0a52cfb132a3bbaf546dadf11e05f4c2b8f60a216409b5bed7b49eba79803270dbac561217a0e36ac107e2348b2
7
- data.tar.gz: 5642f18d54cfb80d5b159575f1ba59b652ec2d57606a5609bda4644740367d7f82187718728c9ccc6854d944291855ec48f54d66b957e3e6e736c52d9c2b9339
6
+ metadata.gz: af57be94f22a74d3ffbbde98eca0eb92fa503c15254b666c5fdfe518c401af10260203b520b9ce26f2b9043c93fdd2289f2af5ecb1387deaf7f65bdfa6ad1a19
7
+ data.tar.gz: 9d6a1a9a69f77fb49cb0ec3f5d2be1f8a0f2f3a460590a4722ae071cd711fb5a792baa663c233a0f06b94dbea6e7a09a3fd9c0f60ee0ac7d488097b5a96f2a52
@@ -5,4 +5,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
7
 
8
- LOGSTASH_CORE_VERSION = "5.0.0.alpha5.snapshot1"
8
+ LOGSTASH_CORE_VERSION = "5.0.0.alpha6.snapshot1"
@@ -135,7 +135,7 @@ class LogStash::Agent
135
135
 
136
136
  private
137
137
  def start_webserver
138
- options = {:http_host => @http_host, :http_port => @http_port, :http_environment => @http_environment }
138
+ options = {:http_host => @http_host, :http_ports => @http_port, :http_environment => @http_environment }
139
139
  @webserver = LogStash::WebServer.new(@logger, self, options)
140
140
  Thread.new(@webserver) do |webserver|
141
141
  LogStash::Util.set_thread_name("Api Webserver")
@@ -9,7 +9,7 @@ module LogStash
9
9
  def all
10
10
  {:host => host, :version => version, :http_address => http_address}
11
11
  end
12
-
12
+
13
13
  def host
14
14
  Socket.gethostname
15
15
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class HotThreadsReport
4
+ STRING_SEPARATOR_LENGTH = 80.freeze
4
5
  HOT_THREADS_STACK_TRACES_SIZE_DEFAULT = 10.freeze
5
6
 
6
7
  def initialize(cmd, options)
@@ -13,19 +14,16 @@ class HotThreadsReport
13
14
  def to_s
14
15
  hash = to_hash[:hot_threads]
15
16
  report = "#{I18n.t("logstash.web_api.hot_threads.title", :hostname => hash[:hostname], :time => hash[:time], :top_count => @thread_dump.top_count )} \n"
16
- report << '=' * 80
17
+ report << '=' * STRING_SEPARATOR_LENGTH
17
18
  report << "\n"
18
19
  hash[:threads].each do |thread|
19
- thread_report = ""
20
- thread_report = "#{I18n.t("logstash.web_api.
21
- hot_threads.thread_title", :percent_of_cpu_time => thread[:percent_of_cpu_time], :thread_state => thread[:state], :thread_name => thread[:name])} \n"
22
- thread_report = "#{thread[:percent_of_cpu_time]} % of of cpu usage by #{thread[:state]} thread named '#{thread[:name]}'\n"
20
+ thread_report = "#{I18n.t("logstash.web_api.hot_threads.thread_title", :percent_of_cpu_time => thread[:percent_of_cpu_time], :thread_state => thread[:state], :thread_name => thread[:name])} \n"
23
21
  thread_report << "#{thread[:path]}\n" if thread[:path]
24
22
  thread[:traces].each do |trace|
25
23
  thread_report << "\t#{trace}\n"
26
24
  end
27
25
  report << thread_report
28
- report << '-' * 80
26
+ report << '-' * STRING_SEPARATOR_LENGTH
29
27
  report << "\n"
30
28
  end
31
29
  report
@@ -57,5 +55,4 @@ class HotThreadsReport
57
55
  def cpu_time(hash)
58
56
  hash["cpu.time"] / 1000000.0
59
57
  end
60
-
61
58
  end
@@ -20,7 +20,7 @@ module LogStash
20
20
  def pipeline
21
21
  extract_metrics(
22
22
  [:stats, :pipelines, :main, :config],
23
- :workers, :batch_size, :batch_delay
23
+ :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval
24
24
  )
25
25
  end
26
26
 
@@ -35,27 +35,28 @@ module LogStash
35
35
 
36
36
  def jvm
37
37
  memory_bean = ManagementFactory.getMemoryMXBean()
38
+
38
39
  {
39
40
  :pid => ManagementFactory.getRuntimeMXBean().getName().split("@").first.to_i,
40
41
  :version => java.lang.System.getProperty("java.version"),
41
42
  :vm_name => java.lang.System.getProperty("java.vm.name"),
42
43
  :vm_version => java.lang.System.getProperty("java.version"),
43
44
  :vm_vendor => java.lang.System.getProperty("java.vendor"),
44
- :vm_name => java.lang.System.getProperty("java.vm.name"),
45
+ :vm_name => java.lang.System.getProperty("java.vm.name"),
45
46
  :start_time_in_millis => started_at,
46
47
  :mem => {
47
48
  :heap_init_in_bytes => (memory_bean.getHeapMemoryUsage().getInit() < 0 ? 0 : memory_bean.getHeapMemoryUsage().getInit()),
48
49
  :heap_max_in_bytes => (memory_bean.getHeapMemoryUsage().getMax() < 0 ? 0 : memory_bean.getHeapMemoryUsage().getMax()),
49
50
  :non_heap_init_in_bytes => (memory_bean.getNonHeapMemoryUsage().getInit() < 0 ? 0 : memory_bean.getNonHeapMemoryUsage().getInit()),
50
51
  :non_heap_max_in_bytes => (memory_bean.getNonHeapMemoryUsage().getMax() < 0 ? 0 : memory_bean.getNonHeapMemoryUsage().getMax())
51
- }
52
+ },
53
+ :gc_collectors => ManagementFactory.getGarbageCollectorMXBeans().collect(&:getName)
52
54
  }
53
55
  end
54
56
 
55
57
  def hot_threads(options={})
56
58
  HotThreadsReport.new(self, options)
57
59
  end
58
-
59
60
  end
60
61
  end
61
62
  end
@@ -14,7 +14,8 @@ module LogStash
14
14
  :count,
15
15
  :peak_count
16
16
  ),
17
- :mem => memory
17
+ :mem => memory,
18
+ :gc => gc
18
19
  }
19
20
  end
20
21
 
@@ -32,7 +33,7 @@ module LogStash
32
33
  def events
33
34
  extract_metrics(
34
35
  [:stats, :events],
35
- :in, :filtered, :out
36
+ :in, :filtered, :out, :duration_in_millis
36
37
  )
37
38
  end
38
39
 
@@ -59,6 +60,10 @@ module LogStash
59
60
  }
60
61
  end
61
62
 
63
+ def gc
64
+ service.get_shallow(:jvm, :gc)
65
+ end
66
+
62
67
  def hot_threads(options={})
63
68
  HotThreadsReport.new(self, options)
64
69
  end
@@ -70,7 +75,7 @@ module LogStash
70
75
  # Turn the `plugins` stats hash into an array of [ {}, {}, ... ]
71
76
  # This is to produce an array of data points, one point for each
72
77
  # plugin instance.
73
- return [] unless stats[:plugins].include?(plugin_type)
78
+ return [] unless stats[:plugins] && stats[:plugins].include?(plugin_type)
74
79
  stats[:plugins][plugin_type].collect do |id, data|
75
80
  { :id => id }.merge(data)
76
81
  end
@@ -34,6 +34,11 @@ module LogStash
34
34
  text = as == :string ? "" : {}
35
35
  respond_with(text, :as => as)
36
36
  end
37
+
38
+ protected
39
+ def human?
40
+ params.has_key?("human") && (params["human"].nil? || as_boolean(params["human"]) == true)
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -14,7 +14,7 @@ module LogStash
14
14
 
15
15
  options = {
16
16
  :ignore_idle_threads => as_boolean(ignore_idle_threads),
17
- :human => params.has_key?("human")
17
+ :human => human?
18
18
  }
19
19
  options[:threads] = params["threads"].to_i if params.has_key?("threads")
20
20
 
@@ -26,7 +26,6 @@ module LogStash
26
26
  selected_fields = extract_fields(params["filter"].to_s.strip)
27
27
  respond_with node.all(selected_fields)
28
28
  end
29
-
30
29
  end
31
30
  end
32
31
  end
@@ -12,8 +12,7 @@ module LogStash
12
12
  payload = {
13
13
  :jvm => jvm_payload,
14
14
  :process => process_payload,
15
- :mem => mem_payload,
16
- :pipeline => pipeline_payload
15
+ :pipeline => pipeline_payload,
17
16
  }
18
17
  respond_with(payload, {:filter => params["filter"]})
19
18
  end
@@ -18,6 +18,7 @@ module LogStash::Codecs; class Base < LogStash::Plugin
18
18
  super
19
19
  config_init(@params)
20
20
  register if respond_to?(:register)
21
+ setup_multi_encode!
21
22
  end
22
23
 
23
24
  public
@@ -28,10 +29,37 @@ module LogStash::Codecs; class Base < LogStash::Plugin
28
29
  alias_method :<<, :decode
29
30
 
30
31
  public
32
+ # DEPRECATED: Prefer defining encode_sync or multi_encode
31
33
  def encode(event)
32
- raise "#{self.class}#encode must be overidden"
34
+ encoded = multi_encode([event])
35
+ encoded.each {|event,data| @on_event.call(event,data) }
33
36
  end # def encode
34
37
 
38
+ public
39
+ # Relies on the codec being synchronous (which they all are!)
40
+ # We need a better long term design here, but this is an improvement
41
+ # over the current API for shared plugins
42
+ # It is best if the codec implements this directly
43
+ def multi_encode(events)
44
+ if @has_encode_sync
45
+ events.map {|event| [event, self.encode_sync(event)]}
46
+ else
47
+ batch = Thread.current[:logstash_output_codec_batch] ||= []
48
+ batch.clear
49
+
50
+ events.each {|event| self.encode(event) }
51
+ batch
52
+ end
53
+ end
54
+
55
+ def setup_multi_encode!
56
+ @has_encode_sync = self.methods.include?(:encode_sync)
57
+
58
+ on_event do |event, data|
59
+ Thread.current[:logstash_output_codec_batch] << [event, data]
60
+ end
61
+ end
62
+
35
63
  public
36
64
  def close; end;
37
65
 
@@ -209,7 +209,7 @@ module LogStash::Config::Mixin
209
209
 
210
210
  name = name.to_s if name.is_a?(Symbol)
211
211
  @config[name] = opts # ok if this is empty
212
-
212
+
213
213
  if name.is_a?(String)
214
214
  define_method(name) { instance_variable_get("@#{name}") }
215
215
  define_method("#{name}=") { |v| instance_variable_set("@#{name}", v) }
@@ -21,12 +21,12 @@ module LogStash
21
21
  Setting::String.new("config.string", nil, false),
22
22
  Setting::Boolean.new("config.test_and_exit", false),
23
23
  Setting::Boolean.new("config.reload.automatic", false),
24
- Setting::Numeric.new("config.reload.interval", 3),
24
+ Setting::Numeric.new("config.reload.interval", 3), # in seconds
25
25
  Setting::Boolean.new("metric.collect", true) {|v| v == true }, # metric collection cannot be disabled
26
26
  Setting::String.new("pipeline.id", "main"),
27
- Setting::Numeric.new("pipeline.workers", LogStash::Config::CpuCoreStrategy.maximum),
28
- Setting::Numeric.new("pipeline.output.workers", 1),
29
- Setting::Numeric.new("pipeline.batch.size", 125),
27
+ Setting::PositiveInteger.new("pipeline.workers", LogStash::Config::CpuCoreStrategy.maximum),
28
+ Setting::PositiveInteger.new("pipeline.output.workers", 1),
29
+ Setting::PositiveInteger.new("pipeline.batch.size", 125),
30
30
  Setting::Numeric.new("pipeline.batch.delay", 5), # in milliseconds
31
31
  Setting::Boolean.new("pipeline.unsafe_shutdown", false),
32
32
  Setting.new("path.plugins", Array, []),
@@ -38,7 +38,7 @@ module LogStash
38
38
  Setting::String.new("path.log", nil, false),
39
39
  Setting::String.new("log.format", "plain", true, ["json", "plain"]),
40
40
  Setting::String.new("http.host", "127.0.0.1"),
41
- Setting::Port.new("http.port", 9600),
41
+ Setting::PortRange.new("http.port", 9600..9700),
42
42
  Setting::String.new("http.environment", "production"),
43
43
  ].each {|setting| SETTINGS.register(setting) }
44
44
 
@@ -13,15 +13,14 @@ module LogStash
13
13
  ]
14
14
  def_delegators :@filter, *DELEGATED_METHODS
15
15
 
16
- def initialize(logger, klass, metric, *args)
17
- options = args.reduce({}, :merge)
18
-
16
+ def initialize(logger, klass, metric, plugin_args)
19
17
  @logger = logger
20
18
  @klass = klass
21
- @filter = klass.new(options)
19
+ @id = plugin_args["id"]
20
+ @filter = klass.new(plugin_args)
22
21
 
23
22
  # Scope the metrics to the plugin
24
- namespaced_metric = metric.namespace(@filter.plugin_unique_name.to_sym)
23
+ namespaced_metric = metric.namespace("#{@klass.config_name}_#{@id}".to_sym)
25
24
  @filter.metric = namespaced_metric
26
25
 
27
26
  @metric_events = namespaced_metric.namespace(:events)
@@ -1,18 +1,36 @@
1
1
 
2
2
  # encoding: utf-8
3
3
  require "logstash/instrument/periodic_poller/base"
4
- require 'jrmonitor'
4
+ require "jrmonitor"
5
+ require "set"
5
6
 
6
7
  java_import 'java.lang.management.ManagementFactory'
7
8
  java_import 'java.lang.management.OperatingSystemMXBean'
9
+ java_import 'java.lang.management.GarbageCollectorMXBean'
8
10
  java_import 'com.sun.management.UnixOperatingSystemMXBean'
9
11
  java_import 'javax.management.MBeanServer'
10
12
  java_import 'javax.management.ObjectName'
11
13
  java_import 'javax.management.AttributeList'
12
14
  java_import 'javax.naming.directory.Attribute'
13
15
 
16
+
14
17
  module LogStash module Instrument module PeriodicPoller
15
18
  class JVM < Base
19
+ class GarbageCollectorName
20
+ YOUNG_GC_NAMES = Set.new(["Copy", "PS Scavenge", "ParNew", "G1 Young Generation"])
21
+ OLD_GC_NAMES = Set.new(["MarkSweepCompact", "PS MarkSweep", "ConcurrentMarkSweep", "G1 Old Generation"])
22
+
23
+ YOUNG = :young
24
+ OLD = :old
25
+
26
+ def self.get(gc_name)
27
+ if YOUNG_GC_NAMES.include?(gc_name)
28
+ YOUNG
29
+ elsif(OLD_GC_NAMES.include?(gc_name))
30
+ OLD
31
+ end
32
+ end
33
+ end
16
34
 
17
35
  attr_reader :metric
18
36
 
@@ -22,31 +40,46 @@ module LogStash module Instrument module PeriodicPoller
22
40
  end
23
41
 
24
42
  def collect
25
- raw = JRMonitor.memory.generate
43
+ raw = JRMonitor.memory.generate
26
44
  collect_heap_metrics(raw)
27
45
  collect_non_heap_metrics(raw)
28
46
  collect_pools_metrics(raw)
29
47
  collect_threads_metrics
30
48
  collect_process_metrics
49
+ collect_gc_stats
31
50
  end
32
51
 
33
52
  private
34
53
 
35
- def collect_threads_metrics
54
+ def collect_gc_stats
55
+ garbage_collectors = ManagementFactory.getGarbageCollectorMXBeans()
56
+
57
+ garbage_collectors.each do |collector|
58
+ name = GarbageCollectorName.get(collector.getName())
59
+ if name.nil?
60
+ logger.error("Unknown garbage collector name", :name => name)
61
+ else
62
+ metric.gauge([:jvm, :gc, :collectors, name], :collection_count, collector.getCollectionCount())
63
+ metric.gauge([:jvm, :gc, :collectors, name], :collection_time_in_millis, collector.getCollectionTime())
64
+ end
65
+ end
66
+ end
67
+
68
+ def collect_threads_metrics
36
69
  threads = JRMonitor.threads.generate
37
-
70
+
38
71
  current = threads.count
39
72
  if @peak_threads.nil? || @peak_threads < current
40
73
  @peak_threads = current
41
- end
42
-
43
- metric.gauge([:jvm, :threads], :count, threads.count)
74
+ end
75
+
76
+ metric.gauge([:jvm, :threads], :count, threads.count)
44
77
  metric.gauge([:jvm, :threads], :peak_count, @peak_threads)
45
78
  end
46
79
 
47
80
  def collect_process_metrics
48
81
  process_metrics = JRMonitor.process.generate
49
-
82
+
50
83
  path = [:jvm, :process]
51
84
 
52
85
 
@@ -91,6 +124,7 @@ module LogStash module Instrument module PeriodicPoller
91
124
  end
92
125
  end
93
126
 
127
+
94
128
  def build_pools_metrics(data)
95
129
  heap = data["heap"]
96
130
  old = {}
@@ -129,9 +163,8 @@ module LogStash module Instrument module PeriodicPoller
129
163
  :committed_in_bytes => 0,
130
164
  :max_in_bytes => 0,
131
165
  :peak_used_in_bytes => 0,
132
- :peak_max_in_bytes => 0
166
+ :peak_max_in_bytes => 0
133
167
  }
134
168
  end
135
-
136
169
  end
137
170
  end; end; end
@@ -1,192 +1,57 @@
1
- # encoding: utf-8
2
- require "concurrent/atomic/atomic_fixnum"
3
- java_import "java.util.concurrent.CopyOnWriteArrayList"
1
+ require "logstash/output_delegator_strategy_registry"
2
+
3
+ require "logstash/output_delegator_strategies/shared"
4
+ require "logstash/output_delegator_strategies/single"
5
+ require "logstash/output_delegator_strategies/legacy"
4
6
 
5
- # This class goes hand in hand with the pipeline to provide a pool of
6
- # free workers to be used by pipeline worker threads. The pool is
7
- # internally represented with a SizedQueue set the the size of the number
8
- # of 'workers' the output plugin is configured with.
9
- #
10
- # This plugin also records some basic statistics
11
7
  module LogStash class OutputDelegator
12
- attr_reader :workers, :config, :threadsafe
8
+ attr_reader :metric, :metric_events, :strategy, :namespaced_metric, :metric_events , :plugin_args, :strategy_registry
13
9
 
14
- # The *args this takes are the same format that a Outputs::Base takes. A list of hashes with parameters in them
15
- # Internally these just get merged together into a single hash
16
- def initialize(logger, klass, default_worker_count, metric, *plugin_args)
10
+ def initialize(logger, output_class, metric, strategy_registry, plugin_args)
17
11
  @logger = logger
18
- @threadsafe = klass.threadsafe?
19
- @config = plugin_args.reduce({}, :merge)
20
- @klass = klass
21
- @workers = java.util.concurrent.CopyOnWriteArrayList.new
22
- @default_worker_count = default_worker_count
23
- @registered = false
24
-
25
- # Create an instance of the input so we can fetch the identifier
26
- output = @klass.new(@config)
27
-
28
- # Scope the metrics to the plugin
29
- namespaced_metric = metric.namespace(output.plugin_unique_name.to_sym)
30
- output.metric = namespaced_metric
31
-
32
- @metric_events = namespaced_metric.namespace(:events)
33
- namespaced_metric.gauge(:name, config_name)
12
+ @output_class = output_class
13
+ @metric = metric
14
+ @plugin_args = plugin_args
15
+ @strategy_registry = strategy_registry
16
+ raise ArgumentError, "No strategy registry specified" unless strategy_registry
17
+ raise ArgumentError, "No ID specified! Got args #{plugin_args}" unless id
18
+
19
+ build_strategy!
34
20
 
35
- @events_received = Concurrent::AtomicFixnum.new(0)
21
+ @namespaced_metric = metric.namespace(id.to_sym)
22
+ @metric_events = @namespaced_metric.namespace(:events)
23
+ @namespaced_metric.gauge(:name, id)
36
24
  end
37
25
 
38
- def threadsafe?
39
- !!@threadsafe
26
+ def config_name
27
+ @output_class.config_name
40
28
  end
41
29
 
42
- def warn_on_worker_override!
43
- # The user has configured extra workers, but this plugin doesn't support it :(
44
- if worker_limits_overriden?
45
- message = @klass.workers_not_supported_message
46
- warning_meta = {:plugin => @klass.config_name, :worker_count => @config["workers"]}
47
- if message
48
- warning_meta[:message] = message
49
- @logger.warn(I18n.t("logstash.pipeline.output-worker-unsupported-with-message", warning_meta))
50
- else
51
- @logger.warn(I18n.t("logstash.pipeline.output-worker-unsupported", warning_meta))
52
- end
53
- end
30
+ def concurrency
31
+ @output_class.concurrency
54
32
  end
55
33
 
56
- def worker_limits_overriden?
57
- @config["workers"] && @config["workers"] > 1 && @klass.workers_not_supported?
34
+ def build_strategy!
35
+ @strategy = strategy_registry.
36
+ class_for(self.concurrency).
37
+ new(@logger, @output_class, @metric, @plugin_args)
58
38
  end
59
39
 
60
- def target_worker_count
61
- # Remove in 5.0 after all plugins upgraded to use class level declarations
62
- raise ArgumentError, "Attempted to detect target worker count before instantiating a worker to test for legacy workers_not_supported!" if @workers.size == 0
63
-
64
- if @threadsafe || @klass.workers_not_supported?
65
- 1
66
- else
67
- @config["workers"] || @default_worker_count
68
- end
69
- end
70
-
71
- def config_name
72
- @klass.config_name
40
+ def id
41
+ @plugin_args["id"]
73
42
  end
74
43
 
75
44
  def register
76
- raise ArgumentError, "Attempted to register #{self} twice!" if @registered
77
- @registered = true
78
- # We define this as an array regardless of threadsafety
79
- # to make reporting simpler, even though a threadsafe plugin will just have
80
- # a single instance
81
- #
82
- # Older plugins invoke the instance method Outputs::Base#workers_not_supported
83
- # To detect these we need an instance to be created first :()
84
- # TODO: In the next major version after 2.x remove support for this
85
- @workers << @klass.new(@config)
86
- @workers.first.register # Needed in case register calls `workers_not_supported`
87
-
88
- @logger.debug("Will start workers for output", :worker_count => target_worker_count, :class => @klass.name)
89
-
90
- # Threadsafe versions don't need additional workers
91
- setup_additional_workers!(target_worker_count) unless @threadsafe
92
- # We skip the first worker because that's pre-registered to deal with legacy workers_not_supported
93
- @workers.subList(1,@workers.size).each(&:register)
94
- setup_multi_receive!
95
- end
96
-
97
- def setup_additional_workers!(target_worker_count)
98
- warn_on_worker_override!
99
-
100
- (target_worker_count - 1).times do
101
- inst = @klass.new(@config)
102
- inst.metric = @metric
103
- @workers << inst
104
- end
105
-
106
- # This queue is used to manage sharing across threads
107
- @worker_queue = SizedQueue.new(target_worker_count)
108
- @workers.each {|w| @worker_queue << w }
45
+ @strategy.register
109
46
  end
110
47
 
111
- def setup_multi_receive!
112
- # One might wonder why we don't use something like
113
- # define_singleton_method(:multi_receive, method(:threadsafe_multi_receive)
114
- # and the answer is this is buggy on Jruby 1.7.x . It works 98% of the time!
115
- # The other 2% you get weird errors about rebinding to the same object
116
- # Until we switch to Jruby 9.x keep the define_singleton_method parts
117
- # the way they are, with a block
118
- # See https://github.com/jruby/jruby/issues/3582
119
- if threadsafe?
120
- @threadsafe_worker = @workers.first
121
- define_singleton_method(:multi_receive) do |events|
122
- threadsafe_multi_receive(events)
123
- end
124
- else
125
- define_singleton_method(:multi_receive) do |events|
126
- worker_multi_receive(events)
127
- end
128
- end
129
- end
130
-
131
- def threadsafe_multi_receive(events)
132
- @events_received.increment(events.length)
48
+ def multi_receive(events)
133
49
  @metric_events.increment(:in, events.length)
134
-
135
- clock = @metric_events.time(:duration_in_millis)
136
- @threadsafe_worker.multi_receive(events)
137
- clock.stop
50
+ @strategy.multi_receive(events)
138
51
  @metric_events.increment(:out, events.length)
139
52
  end
140
53
 
141
- def worker_multi_receive(events)
142
- @events_received.increment(events.length)
143
- @metric_events.increment(:in, events.length)
144
-
145
- worker = @worker_queue.pop
146
- begin
147
- clock = @metric_events.time(:duration_in_millis)
148
- worker.multi_receive(events)
149
- clock.stop
150
- @metric_events.increment(:out, events.length)
151
- ensure
152
- @worker_queue.push(worker)
153
- end
154
- end
155
-
156
54
  def do_close
157
- @logger.debug("closing output delegator", :klass => @klass.name)
158
-
159
- if @threadsafe
160
- @workers.each(&:do_close)
161
- else
162
- worker_count.times do
163
- worker = @worker_queue.pop
164
- worker.do_close
165
- end
166
- end
55
+ @strategy.do_close
167
56
  end
168
-
169
- def events_received
170
- @events_received.value
171
- end
172
-
173
- # There's no concept of 'busy' workers for a threadsafe plugin!
174
- def busy_workers
175
- if @threadsafe
176
- 0
177
- else
178
- # The pipeline reporter can run before the outputs are registered trying to pull a value here
179
- # In that case @worker_queue is empty, we just return 0
180
- return 0 unless @worker_queue
181
- @workers.size - @worker_queue.size
182
- end
183
- end
184
-
185
- def worker_count
186
- @workers.size
187
- end
188
-
189
- private
190
- # Needed for testing, so private
191
- attr_reader :threadsafe_worker, :worker_queue
192
- end end
57
+ end; end